]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Issue #17347: B-Splines in Sketcher
authorazv <azv@opencascade.com>
Fri, 17 Jan 2020 08:31:19 +0000 (11:31 +0300)
committerazv <azv@opencascade.com>
Fri, 17 Jan 2020 13:20:29 +0000 (16:20 +0300)
Python API for B-spline curves

19 files changed:
src/ModelHighAPI/ModelHighAPI.i
src/ModelHighAPI/ModelHighAPI_Double.cpp
src/ModelHighAPI/ModelHighAPI_Double.h
src/ModelHighAPI/ModelHighAPI_Dumper.cpp
src/ModelHighAPI/ModelHighAPI_Dumper.h
src/ModelHighAPI/ModelHighAPI_Tools.cpp
src/ModelHighAPI/ModelHighAPI_Tools.h
src/SketchAPI/CMakeLists.txt
src/SketchAPI/SketchAPI.i
src/SketchAPI/SketchAPI_BSpline.cpp [new file with mode: 0644]
src/SketchAPI/SketchAPI_BSpline.h [new file with mode: 0644]
src/SketchAPI/SketchAPI_Projection.cpp
src/SketchAPI/SketchAPI_Sketch.cpp
src/SketchAPI/SketchAPI_Sketch.h
src/SketchAPI/SketchAPI_SketchEntity.cpp
src/SketchAPI/SketchAPI_swig.h
src/SketchPlugin/SketchPlugin_MacroBSpline.cpp
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_FeatureBuilder.cpp
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp

index 72971cc015fdb391b1226a44f2c303097ff74f1d..442e1cd2a0ed2bbcc5ca16e215aa55665085aa6c 100644 (file)
   }
 }
 
+
+%typemap(in) const std::list<int> & (std::list<int> temp) {
+  int newmem = 0;
+  if (PySequence_Check($input)) {
+    for (Py_ssize_t i = 0; i < PySequence_Size($input); ++i) {
+      PyObject * item = PySequence_GetItem($input, i);
+      if (PyLong_Check(item)) {
+        temp.push_back((int)PyLong_AsLong(item));
+      } else {
+        PyErr_SetString(PyExc_TypeError, "argument must integet value.");
+        return NULL;
+      }
+      Py_DECREF(item);
+    }
+    $1 = &temp;
+  } else {
+    PyErr_SetString(PyExc_ValueError, "argument must be a tuple of integer values.");
+    return NULL;
+  }
+}
+
+%typecheck(SWIG_TYPECHECK_POINTER) std::list<int>, const std::list<int>& {
+  int newmem = 0;
+  if (PySequence_Check($input)) {
+    for (Py_ssize_t i = 0; i < PySequence_Size($input); ++i) {
+      PyObject * item = PySequence_GetItem($input, i);
+      if (PyLong_Check(item)) {
+        $1 = 1;
+      } else {
+        $1 = 0;
+        break;
+      }
+      Py_DECREF(item);
+    }
+  } else {
+    $1 = 0;
+  }
+}
+
+
 %typemap(in) const std::list<double> & (std::list<double> temp) {
-  double * temp_attribute;
   int newmem = 0;
   if (PyTuple_Check($input)) {
     for (Py_ssize_t i = 0; i < PyTuple_Size($input); ++i) {
 }
 
 %typecheck(SWIG_TYPECHECK_POINTER) std::list<double>, const std::list<double>& {
-  double * temp_object;
-  std::shared_ptr<ModelHighAPI_Interface> * temp_interface;
   int newmem = 0;
   if (PyTuple_Check($input)) {
     for (Py_ssize_t i = 0; i < PyTuple_Size($input); ++i) {
   }
 }
 
+
+%typemap(in) const std::list<ModelHighAPI_Double> & (std::list<ModelHighAPI_Double> temp) {
+  ModelHighAPI_Double * temp_double;
+  if (PySequence_Check($input)) {
+    for (Py_ssize_t i = 0; i < PySequence_Size($input); ++i) {
+      PyObject * item = PySequence_GetItem($input, i);
+      if (PyFloat_Check(item) || PyLong_Check(item)) {
+        temp.push_back(ModelHighAPI_Double(PyFloat_AsDouble(item)));
+      } else if (PyUnicode_Check(item)) {
+        temp.push_back(ModelHighAPI_Double(PyUnicode_AsUTF8(item)));
+      } else if ((SWIG_ConvertPtr(item, (void **)&temp_double, $1_descriptor, SWIG_POINTER_EXCEPTION)) == 0) {
+        temp.push_back(*temp_double);
+      } else {
+        PyErr_SetString(PyExc_ValueError, "argument must be a list of ModelHighAPI_Double, float, int or string.");
+        return NULL;
+      }
+      Py_DECREF(item);
+    }
+    $1 = &temp;
+  } else {
+    PyErr_SetString(PyExc_ValueError, "argument must be a list of ModelHighAPI_Double, float, int or string.");
+    return NULL;
+  }
+}
+
+%typecheck(SWIG_TYPECHECK_POINTER) std::list<ModelHighAPI_Double>, const std::list<ModelHighAPI_Double> & {
+  if (PySequence_Check($input)) {
+    for (Py_ssize_t i = 0; i < PySequence_Size($input) && $1; ++i) {
+      PyObject * item = PySequence_GetItem($input, i);
+      $1 = ((PyFloat_Check(item) || PyLong_Check(item) || PyUnicode_Check(item)) && !PyBool_Check(item)) ? 1 : 0;
+      Py_DECREF(item);
+    }
+  } else {
+    $1 = 0;
+  }
+}
+
+
 // all supported interfaces
 %include "ModelHighAPI_Double.h"
 %include "ModelHighAPI_Dumper.h"
index 35370c8190295fb7bcbdc02229ce90c1c06dafd6..33c52647d98ef1009250ab14075a844c7f387869 100644 (file)
@@ -46,6 +46,12 @@ ModelHighAPI_Double::~ModelHighAPI_Double()
 {
 }
 
+double ModelHighAPI_Double::value() const
+{
+  // needed for array of double, which supports no text
+  return myDouble;
+}
+
 //--------------------------------------------------------------------------------------
 void ModelHighAPI_Double::fillAttribute(
     const std::shared_ptr<ModelAPI_AttributeDouble> & theAttribute) const
index 6861a7c0a3f55b9a5898acbc3ea61556841f541b..9fe5df5369c272b49df1379bd0ba261fd5739f10 100644 (file)
@@ -60,6 +60,9 @@ public:
     const ModelHighAPI_Double & theY,
     const ModelHighAPI_Double & theZ) const;
 
+  /// Value of the attribute
+  MODELHIGHAPI_EXPORT double value() const;
+
 private:
   enum VariantType { VT_DOUBLE, VT_STRING } myVariantType;
   double myDouble;
index 9df987e6101f4b342e2a8d7c96f457d38f27448c..677e31be7b524cbf64ad988ca713e921cd158d88 100644 (file)
@@ -22,6 +22,7 @@
 #include <Config_PropManager.h>
 
 #include <GeomAPI_Pnt.h>
+#include <GeomAPI_Pnt2d.h>
 #include <GeomAPI_Dir.h>
 #include <GeomAPI_ShapeExplorer.h>
 #include <GeomAPI_ShapeIterator.h>
 #include <GeomDataAPI_Dir.h>
 #include <GeomDataAPI_Point.h>
 #include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
 
 #include <ModelAPI_AttributeBoolean.h>
 #include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeDoubleArray.h>
 #include <ModelAPI_AttributeIntArray.h>
 #include <ModelAPI_AttributeInteger.h>
 #include <ModelAPI_AttributeRefAttr.h>
@@ -1082,6 +1085,43 @@ ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
   return *this;
 }
 
+ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
+  const std::shared_ptr<GeomDataAPI_Point2DArray>& thePointArray)
+{
+  static const int aThreshold = 4;
+  static bool aDumpAsIs = false;
+  static std::string aSeparator = "";
+  // if number of elements in the list if greater than a threshold,
+  // dump it in a separate line with specific name
+  int aSize = thePointArray->size();
+  if (aDumpAsIs || aSize <= aThreshold) {
+    *myDumpStorage << "[";
+    GeomPnt2dPtr aPoint = thePointArray->pnt(0);
+    *myDumpStorage << "(" << aPoint->x() << ", " << aPoint->y() << ")";
+    for (int anIndex = 1; anIndex < aSize; ++anIndex) {
+      aPoint = thePointArray->pnt(anIndex);
+      *myDumpStorage << "," << aSeparator << " (" << aPoint->x() << ", " << aPoint->y() << ")";
+    }
+    *myDumpStorage << aSeparator << "]";
+  }
+  else {
+    // name of list
+    FeaturePtr anOwner = ModelAPI_Feature::feature(thePointArray->owner());
+    std::string aListName = name(anOwner) + "_" + thePointArray->id();
+    // reserve dumped buffer and store list "as is"
+    myDumpStorage->reserveBuffer();
+    aDumpAsIs = true;
+    aSeparator = std::string("\n") + std::string(aListName.size() + 3, ' ');
+    *this << aListName << " = " << thePointArray << "\n";
+    aDumpAsIs = false;
+    aSeparator = "";
+    // append reserved data to the end of the current buffer
+    myDumpStorage->restoreReservedBuffer();
+    *myDumpStorage << aListName;
+  }
+  return *this;
+}
+
 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
     const std::shared_ptr<ModelAPI_AttributeBoolean>& theAttrBool)
 {
@@ -1111,6 +1151,20 @@ ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
   return *this;
 }
 
+ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
+  const std::shared_ptr<ModelAPI_AttributeDoubleArray>& theArray)
+{
+  *myDumpStorage << "[";
+  int aSize = theArray->size();
+  if (aSize > 0) {
+    *myDumpStorage << theArray->value(0);
+    for (int anIndex = 1; anIndex < aSize; ++anIndex)
+      *myDumpStorage << ", " << theArray->value(anIndex);
+  }
+  *myDumpStorage << "]";
+  return *this;
+}
+
 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
     const std::shared_ptr<ModelAPI_AttributeString>& theAttrStr)
 {
index 2bbc294357441c7a74ef484ec8124b9ce3b68811..f9114176d8377d25d4e06357b3dff4f936e8fc07 100644 (file)
@@ -36,10 +36,12 @@ class GeomAPI_Dir;
 class GeomDataAPI_Dir;
 class GeomDataAPI_Point;
 class GeomDataAPI_Point2D;
+class GeomDataAPI_Point2DArray;
 
 class ModelAPI_Attribute;
 class ModelAPI_AttributeBoolean;
 class ModelAPI_AttributeDouble;
+class ModelAPI_AttributeDoubleArray;
 class ModelAPI_AttributeInteger;
 class ModelAPI_AttributeRefAttr;
 class ModelAPI_AttributeRefAttrList;
@@ -262,6 +264,9 @@ public:
   /// "X, Y"
   MODELHIGHAPI_EXPORT
   ModelHighAPI_Dumper& operator<<(const std::shared_ptr<GeomDataAPI_Point2D>& thePoint);
+  /// Dump GeomDataAPI_Point2DArray as a list of 2D points
+  MODELHIGHAPI_EXPORT
+  ModelHighAPI_Dumper& operator<<(const std::shared_ptr<GeomDataAPI_Point2DArray>& thePointArray);
 
   /// Dump AttributeBoolean
   MODELHIGHAPI_EXPORT
@@ -272,6 +277,9 @@ public:
   /// Dump AttributeDouble
   MODELHIGHAPI_EXPORT
   ModelHighAPI_Dumper& operator<<(const std::shared_ptr<ModelAPI_AttributeDouble>& theAttrReal);
+  /// Dump AttributeDoubleArray
+  MODELHIGHAPI_EXPORT
+  ModelHighAPI_Dumper& operator<<(const std::shared_ptr<ModelAPI_AttributeDoubleArray>& theArray);
   /// Dump AttributeString
   MODELHIGHAPI_EXPORT
   ModelHighAPI_Dumper& operator<<(const std::shared_ptr<ModelAPI_AttributeString>& theAttrStr);
index 8f1938720491f21997eee2676bc0b331c92a68e9..e2b0e3cbd5d5e86213f1d00eeddc6fdd8ef4e282 100644 (file)
 #include <GeomDataAPI_Dir.h>
 #include <GeomDataAPI_Point.h>
 #include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
 //--------------------------------------------------------------------------------------
 #include <ModelAPI_AttributeBoolean.h>
 #include <ModelAPI_AttributeDocRef.h>
 #include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeDoubleArray.h>
 #include <ModelAPI_AttributeIntArray.h>
 #include <ModelAPI_AttributeInteger.h>
 #include <ModelAPI_AttributeRefAttr.h>
@@ -239,6 +241,29 @@ void fillAttribute(const std::list<ModelHighAPI_Integer> & theValue,
     theAttribute->setValue(anIndex, it->intValue()); // use only values, no text support in array
 }
 
+//--------------------------------------------------------------------------------------
+void fillAttribute(const std::list<ModelHighAPI_Double> & theValue,
+                   const std::shared_ptr<ModelAPI_AttributeDoubleArray> & theAttribute)
+{
+  theAttribute->setSize(int(theValue.size()));
+
+  int anIndex = 0;
+  for (auto it = theValue.begin(); it != theValue.end(); ++it, ++anIndex)
+    theAttribute->setValue(anIndex, it->value()); // use only values, no text support in array
+}
+
+//--------------------------------------------------------------------------------------
+void fillAttribute(const std::list<std::shared_ptr<GeomAPI_Pnt2d> > & theValue,
+                   const std::shared_ptr<GeomDataAPI_Point2DArray> & theAttribute)
+{
+  theAttribute->setSize(int(theValue.size()));
+
+  int anIndex = 0;
+  for (auto it = theValue.begin(); it != theValue.end(); ++it, ++anIndex)
+    theAttribute->setPnt(anIndex, *it);
+}
+
+//--------------------------------------------------------------------------------------
 void fillAttribute(const ModelHighAPI_Double & theX,
                    const ModelHighAPI_Double & theY,
                    const ModelHighAPI_Double & theZ,
@@ -247,7 +272,6 @@ void fillAttribute(const ModelHighAPI_Double & theX,
   theX.fillAttribute(theAttribute, theX, theY, theZ);
 }
 
-
 //==================================================================================================
 GeomAPI_Shape::ShapeType shapeTypeByStr(std::string theShapeTypeStr)
 {
index d0fc586ca29eba28141ea0089ac37e382c44a8dd..e46596c3e1a0ea7191348fe68a073c08803d4bac 100644 (file)
@@ -37,9 +37,11 @@ class GeomAPI_Pnt2d;
 class GeomDataAPI_Dir;
 class GeomDataAPI_Point;
 class GeomDataAPI_Point2D;
+class GeomDataAPI_Point2DArray;
 //--------------------------------------------------------------------------------------
 class ModelAPI_AttributeBoolean;
 class ModelAPI_AttributeDouble;
+class ModelAPI_AttributeDoubleArray;
 class ModelAPI_AttributeIntArray;
 class ModelAPI_AttributeInteger;
 class ModelAPI_AttributeRefAttr;
@@ -146,6 +148,14 @@ MODELHIGHAPI_EXPORT
 void fillAttribute(const std::list<ModelHighAPI_Integer> & theValue,
                    const std::shared_ptr<ModelAPI_AttributeIntArray> & theAttribute);
 
+MODELHIGHAPI_EXPORT
+void fillAttribute(const std::list<ModelHighAPI_Double> & theValue,
+                   const std::shared_ptr<ModelAPI_AttributeDoubleArray> & theAttribute);
+
+MODELHIGHAPI_EXPORT
+void fillAttribute(const std::list<std::shared_ptr<GeomAPI_Pnt2d> > & theValue,
+                   const std::shared_ptr<GeomDataAPI_Point2DArray> & theAttribute);
+
 MODELHIGHAPI_EXPORT
 void fillAttribute(const ModelHighAPI_Double & theX,
                    const ModelHighAPI_Double & theY,
index 9d2b423d8a244dc27cab1286d334d11b2ec35c43..c81d857be876744e1ae073b9f30c09cd77b8b3f7 100644 (file)
@@ -22,6 +22,7 @@ INCLUDE(Common)
 SET(PROJECT_HEADERS
   SketchAPI.h
   SketchAPI_Arc.h
+  SketchAPI_BSpline.h
   SketchAPI_Circle.h
   SketchAPI_Constraint.h
   SketchAPI_ConstraintAngle.h
@@ -45,6 +46,7 @@ SET(PROJECT_HEADERS
 
 SET(PROJECT_SOURCES
   SketchAPI_Arc.cpp
+  SketchAPI_BSpline.cpp
   SketchAPI_Circle.cpp
   SketchAPI_Constraint.cpp
   SketchAPI_ConstraintAngle.cpp
index 07f596c21909c1356ccbdebbcd58ca112d354aa5..e2a43e68de85b6548f81e4730f70982d21f717b2 100644 (file)
@@ -45,6 +45,8 @@
 %include "std_shared_ptr.i"
 
 // function with named parameters
+%feature("kwargs") SketchAPI_BSpline::controlPoles;
+%feature("kwargs") SketchAPI_BSpline::controlPolygon;
 %feature("kwargs") SketchAPI_Ellipse::construction;
 %feature("kwargs") SketchAPI_EllipticArc::construction;
 %feature("kwargs") SketchAPI_Sketch::setAngle;
@@ -58,6 +60,7 @@
 %shared_ptr(SketchAPI_MacroEllipse)
 %shared_ptr(SketchAPI_EllipticArc)
 %shared_ptr(SketchAPI_MacroEllipticArc)
+%shared_ptr(SketchAPI_BSpline)
 %shared_ptr(SketchAPI_Constraint)
 %shared_ptr(SketchAPI_ConstraintAngle)
 %shared_ptr(SketchAPI_IntersectionPoint)
@@ -75,6 +78,7 @@
 %template(InterfaceList) std::list<std::shared_ptr<ModelHighAPI_Interface> >;
 %template(EntityList)    std::list<std::shared_ptr<SketchAPI_SketchEntity> >;
 %template(SketchPointList) std::list<std::shared_ptr<SketchAPI_Point> >;
+%template(GeomPnt2dList) std::list<std::shared_ptr<GeomAPI_Pnt2d> >;
 // std::pair -> []
 %template(PointRefAttrPair) std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>;
 
 // fix compilarion error: 'res*' was not declared in this scope
 %typemap(freearg) const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr> & {}
 
+
+%typemap(in) const std::list<std::shared_ptr<GeomAPI_Pnt2d> > & (std::list<std::shared_ptr<GeomAPI_Pnt2d> > temp) {
+  std::shared_ptr<GeomAPI_Pnt2d> * temp_point = 0;
+  int newmem = 0;
+  if (PySequence_Check($input)) {
+    for (Py_ssize_t i = 0; i < PySequence_Size($input); ++i) {
+      PyObject * item = PySequence_GetItem($input, i);
+      if (PyTuple_Check(item)) {
+        if (PyTuple_Size(item) == 2) {
+          double x = (double)PyFloat_AsDouble(PySequence_GetItem(item, 0));
+          double y = (double)PyFloat_AsDouble(PySequence_GetItem(item, 1));
+          temp.push_back(std::shared_ptr<GeomAPI_Pnt2d>(new GeomAPI_Pnt2d(x, y)));
+        } else {
+          PyErr_SetString(PyExc_TypeError, "argument must a list of 2D points.");
+          return NULL;
+        }
+      } else
+      if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_point, $descriptor(std::shared_ptr<GeomAPI_Pnt2d> *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
+        temp.push_back(*temp_point);
+        if (temp_point && (newmem & SWIG_CAST_NEW_MEMORY)) {
+          delete temp_point;
+        }
+      } else {
+        PyErr_SetString(PyExc_TypeError, "argument must a list of 2D points.");
+        return NULL;
+      }
+      Py_DECREF(item);
+    }
+    $1 = &temp;
+  } else {
+    PyErr_SetString(PyExc_ValueError, "argument must be a tuple of lists.");
+    return NULL;
+  }
+}
+
+%typecheck(SWIG_TYPECHECK_POINTER) std::list<std::shared_ptr<GeomAPI_Pnt2d> >, const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& {
+  std::shared_ptr<GeomAPI_Pnt2d> * temp_point = 0;
+  int newmem = 0;
+  if (PySequence_Check($input)) {
+    for (Py_ssize_t i = 0; i < PySequence_Size($input) && $1; ++i) {
+      PyObject * item = PySequence_GetItem($input, i);
+      if (PyTuple_Check(item)) {
+        if (PyTuple_Size(item) == 2) {
+          if (PyNumber_Check(PySequence_GetItem(item, 0)) && PyNumber_Check(PySequence_GetItem(item, 1))) {
+            $1 = 1;
+          } else {
+            $1 = 0;
+          }
+        } else {
+          $1 = 0;
+        }
+      } else
+      if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_point, $descriptor(std::shared_ptr<GeomAPI_Pnt2d> *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
+        if (temp_point) {
+          $1 = 1;
+        } else {
+          $1 = 0;
+        }
+      }
+      Py_DECREF(item);
+    }
+  } else {
+    $1 = 0;
+  }
+}
+
+// fix compilarion error: 'res*' was not declared in this scope
+%typemap(freearg) const std::list<std::shared_ptr<GeomAPI_Pnt2d> > & {}
+
+
 // all supported interfaces (the order is very important according dependencies: base class first)
 %include "SketchAPI_SketchEntity.h"
 %include "SketchAPI_Point.h"
 %include "SketchAPI_MacroEllipse.h"
 %include "SketchAPI_EllipticArc.h"
 %include "SketchAPI_MacroEllipticArc.h"
+%include "SketchAPI_BSpline.h"
 %include "SketchAPI_Projection.h"
 %include "SketchAPI_Mirror.h"
 %include "SketchAPI_Translation.h"
diff --git a/src/SketchAPI/SketchAPI_BSpline.cpp b/src/SketchAPI/SketchAPI_BSpline.cpp
new file mode 100644 (file)
index 0000000..9023d70
--- /dev/null
@@ -0,0 +1,509 @@
+// 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 "SketchAPI_BSpline.h"
+
+#include <GeomAPI_BSpline2d.h>
+#include <GeomAPI_Pnt2d.h>
+
+#include <GeomAlgoAPI_EdgeBuilder.h>
+
+#include <ModelHighAPI_Double.h>
+#include <ModelHighAPI_Dumper.h>
+#include <ModelHighAPI_Integer.h>
+#include <ModelHighAPI_Selection.h>
+#include <ModelHighAPI_Tools.h>
+
+#include <SketchPlugin_ConstraintCoincidenceInternal.h>
+#include <SketchPlugin_Line.h>
+#include <SketchPlugin_Point.h>
+
+#include <cmath>
+
+
+SketchAPI_BSpline::SketchAPI_BSpline(const std::shared_ptr<ModelAPI_Feature> & theFeature)
+  : SketchAPI_SketchEntity(theFeature)
+{
+  initialize();
+}
+
+SketchAPI_BSpline::SketchAPI_BSpline(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                     const std::list<GeomPnt2dPtr>& thePoles,
+                                     const std::list<ModelHighAPI_Double>& theWeights)
+  : SketchAPI_SketchEntity(theFeature)
+{
+  if (initialize()) {
+    setByDegreePolesAndWeights(ModelHighAPI_Integer(-1), thePoles, theWeights);
+  }
+}
+
+SketchAPI_BSpline::SketchAPI_BSpline(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                     const int theDegree,
+                                     const std::list<GeomPnt2dPtr>& thePoles,
+                                     const std::list<ModelHighAPI_Double>& theWeights,
+                                     const std::list<ModelHighAPI_Double>& theKnots,
+                                     const std::list<ModelHighAPI_Integer>& theMults)
+  : SketchAPI_SketchEntity(theFeature)
+{
+  if (initialize()) {
+    if (theKnots.empty() || theMults.empty())
+      setByDegreePolesAndWeights(theDegree, thePoles, theWeights);
+    else
+      setByParameters(theDegree, thePoles, theWeights, theKnots, theMults);
+  }
+}
+
+SketchAPI_BSpline::SketchAPI_BSpline(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                     const ModelHighAPI_Selection& theExternal)
+  : SketchAPI_SketchEntity(theFeature)
+{
+  if (initialize()) {
+    setByExternal(theExternal);
+  }
+}
+
+SketchAPI_BSpline::SketchAPI_BSpline(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                     const std::string& theExternalName)
+  : SketchAPI_SketchEntity(theFeature)
+{
+  if (initialize()) {
+    setByExternalName(theExternalName);
+  }
+}
+
+SketchAPI_BSpline::~SketchAPI_BSpline()
+{
+}
+
+void SketchAPI_BSpline::setByDegreePolesAndWeights(const ModelHighAPI_Integer& theDegree,
+                                                   const std::list<GeomPnt2dPtr>& thePoles,
+                                                   const std::list<ModelHighAPI_Double>& theWeights)
+{
+  std::list<ModelHighAPI_Double> aWeights;
+  if (theWeights.size() <= 1) {
+    // prepare array of equal weights
+    aWeights.assign(thePoles.size(),
+        theWeights.empty() ? ModelHighAPI_Double(1.0) : theWeights.front());
+  }
+  else
+    aWeights = theWeights;
+
+  ModelHighAPI_Integer aDegree = theDegree;
+  std::list<ModelHighAPI_Double> aKnots;
+  std::list<ModelHighAPI_Integer> aMults;
+  getDefaultParameters(thePoles, aWeights, aDegree, aKnots, aMults);
+
+  setByParameters(aDegree, thePoles, aWeights, aKnots, aMults);
+}
+
+void SketchAPI_BSpline::setByParameters(const ModelHighAPI_Integer& theDegree,
+                                        const std::list<GeomPnt2dPtr>& thePoles,
+                                        const std::list<ModelHighAPI_Double>& theWeights,
+                                        const std::list<ModelHighAPI_Double>& theKnots,
+                                        const std::list<ModelHighAPI_Integer>& theMults)
+{
+  fillAttribute(theDegree, degree());
+
+  fillAttribute(thePoles, poles());
+  if (theWeights.size() <= 1) {
+    // prepare array of equal weights
+    std::list<ModelHighAPI_Double> aWeights(thePoles.size(),
+        theWeights.empty() ? ModelHighAPI_Double(1.0) : theWeights.front());
+    fillAttribute(aWeights, weights());
+  }
+  else
+    fillAttribute(theWeights, weights());
+
+  fillAttribute(theKnots, knots());
+  fillAttribute(theMults, multiplicities());
+
+  setStartAndEndPoints();
+  execute();
+}
+
+void SketchAPI_BSpline::setStartAndEndPoints()
+{
+  fillAttribute(poles()->pnt(0), startPoint());
+  fillAttribute(poles()->pnt(poles()->size() - 1), endPoint());
+}
+
+void SketchAPI_BSpline::setByExternal(const ModelHighAPI_Selection & theExternal)
+{
+  fillAttribute(theExternal, external());
+  execute();
+}
+
+void SketchAPI_BSpline::setByExternalName(const std::string & theExternalName)
+{
+  fillAttribute(ModelHighAPI_Selection("EDGE", theExternalName), external());
+  execute();
+}
+
+static CompositeFeaturePtr sketchForFeature(FeaturePtr theFeature)
+{
+  const std::set<AttributePtr>& aRefs = theFeature->data()->refsToMe();
+  for (std::set<AttributePtr>::const_iterator anIt = aRefs.begin(); anIt != aRefs.end(); ++anIt)
+    if ((*anIt)->id() == SketchPlugin_Sketch::FEATURES_ID())
+      return std::dynamic_pointer_cast<ModelAPI_CompositeFeature>((*anIt)->owner());
+  return CompositeFeaturePtr();
+}
+
+static void createInternalConstraint(const CompositeFeaturePtr& theSketch,
+                                     const AttributePoint2DPtr& thePoint,
+                                     const AttributePoint2DArrayPtr& thePoles,
+                                     const int thePoleIndex)
+{
+  FeaturePtr aConstraint = theSketch->addFeature(SketchPlugin_ConstraintCoincidenceInternal::ID());
+  aConstraint->refattr(SketchPlugin_Constraint::ENTITY_A())->setAttr(thePoint);
+  aConstraint->refattr(SketchPlugin_Constraint::ENTITY_B())->setAttr(thePoles);
+  aConstraint->integer(SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_B())
+      ->setValue(thePoleIndex);
+  aConstraint->execute();
+}
+
+static void createPole(const CompositeFeaturePtr& theSketch,
+                       const FeaturePtr& theBSpline,
+                       const AttributePoint2DArrayPtr& thePoles,
+                       const int thePoleIndex,
+                       const bool theAuxiliary,
+                       std::list<FeaturePtr>& theEntities)
+{
+  GeomPnt2dPtr aPole = thePoles->pnt(thePoleIndex);
+
+  FeaturePtr aPointFeature = theSketch->addFeature(SketchPlugin_Point::ID());
+  AttributePoint2DPtr aCoord = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      aPointFeature->attribute(SketchPlugin_Point::COORD_ID()));
+  aCoord->setValue(aPole);
+  aPointFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(theBSpline);
+  aPointFeature->execute();
+
+  std::ostringstream aName;
+  aName << theBSpline->name() << "_" << thePoles->id() << "_" << thePoleIndex;
+  aPointFeature->data()->setName(aName.str());
+  aPointFeature->lastResult()->data()->setName(aName.str());
+
+  aPointFeature->boolean(SketchPlugin_Point::AUXILIARY_ID())->setValue(theAuxiliary);
+
+  createInternalConstraint(theSketch, aCoord, thePoles, thePoleIndex);
+
+  theEntities.push_back(aPointFeature);
+}
+
+static void createSegment(const CompositeFeaturePtr& theSketch,
+                          const FeaturePtr& theBSpline,
+                          const AttributePoint2DArrayPtr& thePoles,
+                          const int theStartPoleIndex,
+                          const bool theAuxiliary,
+                          std::list<FeaturePtr>& theEntities)
+{
+  GeomPnt2dPtr aStartPoint = thePoles->pnt(theStartPoleIndex);
+  GeomPnt2dPtr aEndPoint = thePoles->pnt(theStartPoleIndex + 1);
+
+  FeaturePtr aLineFeature = theSketch->addFeature(SketchPlugin_Line::ID());
+  AttributePoint2DPtr aLineStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      aLineFeature->attribute(SketchPlugin_Line::START_ID()));
+  aLineStart->setValue(aStartPoint);
+  AttributePoint2DPtr aLineEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      aLineFeature->attribute(SketchPlugin_Line::END_ID()));
+  aLineEnd->setValue(aEndPoint);
+  aLineFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(theBSpline);
+  aLineFeature->execute();
+
+  std::ostringstream aName;
+  aName << theBSpline->name() << "_segment_" << theStartPoleIndex << "_" << theStartPoleIndex + 1;
+  aLineFeature->data()->setName(aName.str());
+  aLineFeature->lastResult()->data()->setName(aName.str());
+
+  aLineFeature->boolean(SketchPlugin_Line::AUXILIARY_ID())->setValue(theAuxiliary);
+
+  createInternalConstraint(theSketch, aLineStart, thePoles, theStartPoleIndex);
+  createInternalConstraint(theSketch, aLineEnd, thePoles, theStartPoleIndex + 1);
+
+  theEntities.push_back(aLineFeature);
+}
+
+static void toMapOfAuxIndices(const std::list<int>& theRegular,
+                              const std::list<int>& theAuxiliary,
+                              std::map<int, bool>& theIndices)
+{
+  for (auto it = theRegular.begin(); it != theRegular.end(); ++it)
+    theIndices[*it] = false;
+  for (auto it = theAuxiliary.begin(); it != theAuxiliary.end(); ++it)
+    theIndices[*it] = true;
+}
+
+std::list<std::shared_ptr<SketchAPI_SketchEntity> > SketchAPI_BSpline::controlPoles(
+    const std::list<int>& regular,
+    const std::list<int>& auxiliary) const
+{
+  std::map<int, bool> anAux;
+  toMapOfAuxIndices(regular, auxiliary, anAux);
+
+  std::list<FeaturePtr> anEntities;
+
+  FeaturePtr aBSpline = feature();
+  CompositeFeaturePtr aSketch = sketchForFeature(aBSpline);
+  AttributePoint2DArrayPtr aPoles = poles();
+
+  for (auto it = anAux.begin(); it != anAux.end(); ++it)
+    createPole(aSketch, aBSpline, aPoles, it->first, it->second, anEntities);
+
+  return SketchAPI_SketchEntity::wrap(anEntities);
+}
+
+std::list<std::shared_ptr<SketchAPI_SketchEntity> > SketchAPI_BSpline::controlPolygon(
+    const std::list<int>& regular,
+    const std::list<int>& auxiliary) const
+{
+  std::map<int, bool> anAux;
+  toMapOfAuxIndices(regular, auxiliary, anAux);
+
+  std::list<FeaturePtr> anEntities;
+
+  FeaturePtr aBSpline = feature();
+  CompositeFeaturePtr aSketch = sketchForFeature(aBSpline);
+  AttributePoint2DArrayPtr aPoles = poles();
+
+  for (auto it = anAux.begin(); it != anAux.end(); ++it)
+    createSegment(aSketch, aBSpline, aPoles, it->first, it->second, anEntities);
+
+  return SketchAPI_SketchEntity::wrap(anEntities);
+}
+
+
+void SketchAPI_BSpline::getDefaultParameters(
+    const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+    const std::list<ModelHighAPI_Double>& theWeights,
+    ModelHighAPI_Integer& theDegree,
+    std::list<ModelHighAPI_Double>& theKnots,
+    std::list<ModelHighAPI_Integer>& theMults) const
+{
+  std::shared_ptr<GeomAPI_BSpline2d> aBSplineCurve;
+  try {
+    std::list<double> aWeights;
+    for (std::list<ModelHighAPI_Double>::const_iterator it = theWeights.begin();
+         it != theWeights.end(); ++it)
+      aWeights.push_back(it->value());
+
+    if (theDegree.intValue() < 0)
+      aBSplineCurve.reset(new GeomAPI_BSpline2d(thePoles, aWeights));
+    else
+      aBSplineCurve.reset(new GeomAPI_BSpline2d(theDegree.intValue(), thePoles, aWeights));
+  }
+  catch (...) {
+    // cannot build a B-spline curve
+    return;
+  }
+
+  theDegree = aBSplineCurve->degree();
+  std::list<double> aKnots = aBSplineCurve->knots();
+  std::list<int> aMults = aBSplineCurve->mults();
+  theKnots.assign(aKnots.begin(), aKnots.end());
+  theMults.assign(aMults.begin(), aMults.end());
+}
+
+void SketchAPI_BSpline::checkDefaultParameters(bool& isDefaultDegree,
+                                               bool& isDefaultWeights,
+                                               bool& isDefaultKnotsMults) const
+{
+  static const double TOLERANCE = 1.e-7;
+
+  AttributePoint2DArrayPtr aPolesAttr = poles();
+  AttributeDoubleArrayPtr aWeightsAttr = weights();
+  AttributeDoubleArrayPtr aKnotsAttr = knots();
+  AttributeIntArrayPtr aMultsAttr = multiplicities();
+
+  std::list<GeomPnt2dPtr> aPoles;
+  std::list<ModelHighAPI_Double> aWeights;
+  isDefaultWeights = true;
+  for (int anIndex = 0; anIndex < aPolesAttr->size(); ++anIndex) {
+    aPoles.push_back(aPolesAttr->pnt(anIndex));
+    double aCurWeight = aWeightsAttr->value(anIndex);
+    isDefaultWeights = isDefaultWeights && fabs(aCurWeight - 1.0) < TOLERANCE;
+    aWeights.push_back(aCurWeight);
+  }
+
+  ModelHighAPI_Integer aDegree(-1);
+  std::list<ModelHighAPI_Double> aKnots;
+  std::list<ModelHighAPI_Integer> aMults;
+  getDefaultParameters(aPoles, aWeights, aDegree, aKnots, aMults);
+  isDefaultDegree = aDegree.intValue() == degree()->value();
+  if (!isDefaultDegree) {
+    // recalculate knots and multiplicities with the actual degree
+    aDegree = degree()->value();
+    getDefaultParameters(aPoles, aWeights, aDegree, aKnots, aMults);
+  }
+
+  isDefaultKnotsMults = aKnotsAttr->size() == (int)aKnots.size()
+                     && aMultsAttr->size() == (int)aMults.size();
+  if (isDefaultKnotsMults) {
+    std::list<ModelHighAPI_Double>::iterator anIt = aKnots.begin();
+    for (int anIndex = 0; isDefaultKnotsMults && anIt != aKnots.end(); ++anIt, ++anIndex)
+      isDefaultKnotsMults = fabs(anIt->value() - aKnotsAttr->value(anIndex)) < TOLERANCE;
+  }
+  if (isDefaultKnotsMults) {
+    std::list<ModelHighAPI_Integer>::iterator anIt = aMults.begin();
+    for (int anIndex = 0; isDefaultKnotsMults && anIt != aMults.end(); ++anIt, ++anIndex)
+      isDefaultKnotsMults = anIt->intValue() == aMultsAttr->value(anIndex);
+  }
+
+  isDefaultDegree = isDefaultDegree && isDefaultKnotsMults;
+  isDefaultWeights = isDefaultWeights && isDefaultKnotsMults;
+}
+
+
+static void bsplineAuxiliaryFeature(const AttributeRefAttrPtr& theReference,
+                                    FeaturePtr& thePoint,
+                                    FeaturePtr& theSegment)
+{
+  ObjectPtr anAuxObject;
+  if (theReference->isObject())
+    anAuxObject = theReference->object();
+  else
+    anAuxObject = theReference->attr()->owner();
+
+  FeaturePtr anAuxFeature = ModelAPI_Feature::feature(anAuxObject);
+  if (anAuxFeature->getKind() == SketchPlugin_Point::ID())
+    thePoint = anAuxFeature;
+  else if (anAuxFeature->getKind() == SketchPlugin_Line::ID() &&
+           theReference->attr()->id() == SketchPlugin_Line::START_ID()) {
+    // process only coincidence with start point
+    theSegment = anAuxFeature;
+  }
+}
+
+static void collectAuxiliaryFeatures(FeaturePtr theBSpline,
+                                     std::map<int, FeaturePtr>& thePoints,
+                                     std::map<int, FeaturePtr>& theSegments)
+{
+  const std::set<AttributePtr>& aRefs = theBSpline->data()->refsToMe();
+  for (std::set<AttributePtr>::const_iterator aRefIt = aRefs.begin();
+       aRefIt != aRefs.end(); ++aRefIt) {
+    FeaturePtr anOwner = ModelAPI_Feature::feature((*aRefIt)->owner());
+    if (anOwner->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID()) {
+      // process internal constraints only
+      AttributeRefAttrPtr aRefAttrA = anOwner->refattr(SketchPlugin_Constraint::ENTITY_A());
+      AttributeRefAttrPtr aRefAttrB = anOwner->refattr(SketchPlugin_Constraint::ENTITY_B());
+      AttributePtr anAttrA = aRefAttrA->attr();
+      AttributePtr anAttrB = aRefAttrB->attr();
+
+      AttributeIntegerPtr aPoleIndex;
+      FeaturePtr aPoint, aLine;
+      if (anAttrA && anAttrA->attributeType() == GeomDataAPI_Point2DArray::typeId()) {
+        aPoleIndex = anOwner->integer(SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_A());
+        bsplineAuxiliaryFeature(aRefAttrB, aPoint, aLine);
+      }
+      else if (anAttrB && anAttrB->attributeType() == GeomDataAPI_Point2DArray::typeId()) {
+        aPoleIndex = anOwner->integer(SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_B());
+        bsplineAuxiliaryFeature(aRefAttrA, aPoint, aLine);
+      }
+
+      if (aPoint)
+        thePoints[aPoleIndex->value()] = aPoint;
+      else if (aLine)
+        theSegments[aPoleIndex->value()] = aLine;
+    }
+  }
+}
+
+void SketchAPI_BSpline::dump(ModelHighAPI_Dumper& theDumper) const
+{
+  if (isCopy())
+    return; // no need to dump copied feature
+
+  FeaturePtr aBase = feature();
+  const std::string& aSketchName = theDumper.parentName(aBase);
+
+  AttributeSelectionPtr anExternal = aBase->selection(SketchPlugin_SketchEntity::EXTERNAL_ID());
+  if (anExternal->context()) {
+    // B-spline is external
+    theDumper << aBase << " = " << aSketchName << ".addSpline(" << anExternal << ")" << std::endl;
+  } else {
+    // check if some B-spline parameters are default and should not be dumped
+    bool isDefaultDegree, isDefaultWeights, isDefaultKnotsMults;
+    checkDefaultParameters(isDefaultDegree, isDefaultWeights, isDefaultKnotsMults);
+
+    theDumper << aBase << " = " << aSketchName << ".addSpline(";
+    if (!isDefaultDegree)
+      theDumper << degree() << ", ";
+    theDumper << poles();
+    if (!isDefaultWeights)
+      theDumper << ", " << weights();
+    if (!isDefaultKnotsMults)
+      theDumper << ", " << knots() << ", " << multiplicities();
+    theDumper << ")" << std::endl;
+  }
+  // dump "auxiliary" flag if necessary
+  SketchAPI_SketchEntity::dump(theDumper);
+
+  // dump control polygon
+  std::map<int, FeaturePtr> anAuxPoles, anAuxSegments;
+  collectAuxiliaryFeatures(aBase, anAuxPoles, anAuxSegments);
+
+  if (!anAuxPoles.empty())
+    dumpControlPolygon(theDumper, aBase, "controlPoles", anAuxPoles);
+  if (!anAuxSegments.empty())
+    dumpControlPolygon(theDumper, aBase, "controlPolygon", anAuxSegments);
+}
+
+static void dumpList(ModelHighAPI_Dumper& theDumper,
+                     const std::string& theAttrName,
+                     const std::set<int>& theIndices)
+{
+  theDumper << theAttrName << " = [";
+  std::set<int>::const_iterator it = theIndices.begin();
+  theDumper << *it;
+  for (++it; it != theIndices.end(); ++it)
+    theDumper << ", " << *it;
+  theDumper << "]";
+}
+
+void SketchAPI_BSpline::dumpControlPolygon(
+    ModelHighAPI_Dumper& theDumper,
+    const FeaturePtr& theBSpline,
+    const std::string& theMethod,
+    const std::map<int, FeaturePtr>& theAuxFeatures) const
+{
+  theDumper << "[";
+  bool isFirst = true;
+  // dump features and split them to auxiliary and regular
+  std::set<int> aRegular, anAuxiliary;
+  for (std::map<int, FeaturePtr>::const_iterator it = theAuxFeatures.begin();
+       it != theAuxFeatures.end(); ++it) {
+    if (!isFirst)
+      theDumper << ", ";
+    theDumper << theDumper.name(it->second, false);
+    theDumper.doNotDumpFeature(it->second);
+    isFirst = false;
+
+    if (it->second->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value())
+      anAuxiliary.insert(it->first);
+    else
+      aRegular.insert(it->first);
+  }
+  theDumper << "] = " << theDumper.name(theBSpline) << "." << theMethod << "(";
+  if (!aRegular.empty()) {
+    dumpList(theDumper, "regular", aRegular);
+    if (!anAuxiliary.empty())
+      theDumper << ", ";
+  }
+  if (!anAuxiliary.empty())
+    dumpList(theDumper, "auxiliary", anAuxiliary);
+  theDumper << ")" << std::endl;
+}
diff --git a/src/SketchAPI/SketchAPI_BSpline.h b/src/SketchAPI/SketchAPI_BSpline.h
new file mode 100644 (file)
index 0000000..70370ad
--- /dev/null
@@ -0,0 +1,158 @@
+// 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 SketchAPI_BSpline_H_
+#define SketchAPI_BSpline_H_
+
+#include "SketchAPI.h"
+#include "SketchAPI_SketchEntity.h"
+
+#include <GeomDataAPI_Point2DArray.h>
+
+#include <ModelAPI_AttributeDoubleArray.h>
+
+#include <SketchPlugin_BSpline.h>
+
+class ModelHighAPI_Double;
+class ModelHighAPI_Integer;
+class ModelHighAPI_Selection;
+
+/// \class SketchAPI_BSpline
+/// \ingroup CPPHighAPI
+/// \brief Interface for BSpline feature.
+class SketchAPI_BSpline : public SketchAPI_SketchEntity
+{
+public:
+  /// Constructor without values.
+  SKETCHAPI_EXPORT
+  explicit SketchAPI_BSpline(const std::shared_ptr<ModelAPI_Feature>& theFeature);
+
+  /// Constructor with values.
+  SKETCHAPI_EXPORT SketchAPI_BSpline(
+      const std::shared_ptr<ModelAPI_Feature>& theFeature,
+      const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+      const std::list<ModelHighAPI_Double>& theWeights = std::list<ModelHighAPI_Double>());
+
+  /// Constructor with values.
+  SKETCHAPI_EXPORT SketchAPI_BSpline(
+      const std::shared_ptr<ModelAPI_Feature>& theFeature,
+      const int theDegree,
+      const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+      const std::list<ModelHighAPI_Double>& theWeights = std::list<ModelHighAPI_Double>(),
+      const std::list<ModelHighAPI_Double>& theKnots = std::list<ModelHighAPI_Double>(),
+      const std::list<ModelHighAPI_Integer>& theMults = std::list<ModelHighAPI_Integer>());
+
+  /// Constructor with external.
+  SKETCHAPI_EXPORT
+  SketchAPI_BSpline(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                    const ModelHighAPI_Selection& theExternal);
+
+  /// Constructor with external.
+  SKETCHAPI_EXPORT
+  SketchAPI_BSpline(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                    const std::string& theExternalName);
+
+  /// Destructor.
+  SKETCHAPI_EXPORT
+  virtual ~SketchAPI_BSpline();
+
+  INTERFACE_8(SketchPlugin_BSpline::ID(),
+              poles, SketchPlugin_BSpline::POLES_ID(),
+              GeomDataAPI_Point2DArray, /** B-spline poles */,
+              weights, SketchPlugin_BSpline::WEIGHTS_ID(),
+              ModelAPI_AttributeDoubleArray, /** B-spline weights */,
+              knots, SketchPlugin_BSpline::KNOTS_ID(),
+              ModelAPI_AttributeDoubleArray, /** B-spline knots */,
+              multiplicities, SketchPlugin_BSpline::MULTS_ID(),
+              ModelAPI_AttributeIntArray, /** Knots multiplicities */,
+              degree, SketchPlugin_BSpline::DEGREE_ID(),
+              ModelAPI_AttributeInteger, /** B-spline degree */,
+              startPoint, SketchPlugin_BSpline::START_ID(),
+              GeomDataAPI_Point2D, /** First pole of B-spline */,
+              endPoint, SketchPlugin_BSpline::END_ID(),
+              GeomDataAPI_Point2D, /** Last pole of B-spline */,
+              external, SketchPlugin_BSpline::EXTERNAL_ID(),
+              ModelAPI_AttributeSelection, /** External */)
+
+  /// Set by poles and weights.
+  SKETCHAPI_EXPORT
+  void setByDegreePolesAndWeights(const ModelHighAPI_Integer& theDegree,
+                                  const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+                                  const std::list<ModelHighAPI_Double>& theWeights);
+
+  /// Initialize by full set of B-spline parameters.
+  SKETCHAPI_EXPORT
+  void setByParameters(const ModelHighAPI_Integer& theDegree,
+                       const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+                       const std::list<ModelHighAPI_Double>& theWeights,
+                       const std::list<ModelHighAPI_Double>& theKnots,
+                       const std::list<ModelHighAPI_Integer>& theMults);
+
+  /// Set by external.
+  SKETCHAPI_EXPORT
+  void setByExternal(const ModelHighAPI_Selection& theExternal);
+
+  /// Set by external name.
+  SKETCHAPI_EXPORT
+  void setByExternalName(const std::string& theExternalName);
+
+  /// Generate list of construction points coincident with B-spline poles
+  SKETCHAPI_EXPORT
+  std::list<std::shared_ptr<SketchAPI_SketchEntity> > controlPoles(
+      const std::list<int>& regular   = std::list<int>(),
+      const std::list<int>& auxiliary = std::list<int>()) const;
+
+  /// Generate control polygon for B-spline curve
+  SKETCHAPI_EXPORT
+  std::list<std::shared_ptr<SketchAPI_SketchEntity> > controlPolygon(
+      const std::list<int>& regular   = std::list<int>(),
+      const std::list<int>& auxiliary = std::list<int>()) const;
+
+  /// Dump wrapped feature
+  SKETCHAPI_EXPORT
+  virtual void dump(ModelHighAPI_Dumper& theDumper) const;
+
+private:
+  /// Initialize start and end points of B-spline and apply internal coincidence
+  /// constraint to keep them on the corresponding pole.
+  void setStartAndEndPoints();
+
+  /// Compute default B-spline parameters (degree, knots and multiplicities)
+  /// basing on hte given poles and weights
+  void getDefaultParameters(const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+                            const std::list<ModelHighAPI_Double>& theWeights,
+                            ModelHighAPI_Integer& theDegree,
+                            std::list<ModelHighAPI_Double>& theKnots,
+                            std::list<ModelHighAPI_Integer>& theMults) const;
+
+  /// Check what parameters of B-spline are default
+  void checkDefaultParameters(bool& isDefaultDegree,
+                              bool& isDefaultWeights,
+                              bool& isDefaultKnotsMults) const;
+
+  void dumpControlPolygon(ModelHighAPI_Dumper& theDumper,
+                          const FeaturePtr& theBSpline,
+                          const std::string& theMethod,
+                          const std::map<int, FeaturePtr>& theAuxFeatures) const;
+};
+
+/// Pointer on B-spline object.
+typedef std::shared_ptr<SketchAPI_BSpline> BSplinePtr;
+
+#endif // SketchAPI_BSpline_H_
index 4baf94150d033d352ab0027122a39bbae3822ffd..3e1a3f7898bab4a69781cc66aeba04c2f848a255 100644 (file)
 #include "SketchAPI_Projection.h"
 
 #include <SketchPlugin_Line.h>
+#include <SketchPlugin_BSpline.h>
 #include <SketchPlugin_Circle.h>
 #include <SketchPlugin_Ellipse.h>
 #include <SketchPlugin_EllipticArc.h>
 #include <SketchPlugin_Point.h>
 
 #include <SketchAPI_Arc.h>
+#include <SketchAPI_BSpline.h>
 #include <SketchAPI_Circle.h>
 #include <SketchAPI_Ellipse.h>
 #include <SketchAPI_EllipticArc.h>
@@ -108,6 +110,8 @@ std::shared_ptr<SketchAPI_SketchEntity> SketchAPI_Projection::createdFeature() c
     anEntity.reset(new SketchAPI_Ellipse(aProjectedFeature));
   else if (aProjectedFeature->getKind() == SketchPlugin_EllipticArc::ID())
     anEntity.reset(new SketchAPI_EllipticArc(aProjectedFeature));
+  else if (aProjectedFeature->getKind() == SketchPlugin_BSpline::ID())
+    anEntity.reset(new SketchAPI_BSpline(aProjectedFeature));
   else if (aProjectedFeature->getKind() == SketchPlugin_Point::ID())
     anEntity.reset(new SketchAPI_Point(aProjectedFeature));
 
index 25cac9e71a89939ce77cfa5e9be64e6421379419..d1d2967b1a5bfe0a48c76092e565601ecccf7a0e 100644 (file)
@@ -53,6 +53,7 @@
 #include <ModelHighAPI_Tools.h>
 //--------------------------------------------------------------------------------------
 #include "SketchAPI_Arc.h"
+#include "SketchAPI_BSpline.h"
 #include "SketchAPI_Circle.h"
 #include "SketchAPI_Ellipse.h"
 #include "SketchAPI_EllipticArc.h"
@@ -697,6 +698,40 @@ std::shared_ptr<SketchAPI_EllipticArc> SketchAPI_Sketch::addEllipticArc(
   return EllipticArcPtr(new SketchAPI_EllipticArc(aFeature, theExternalName));
 }
 
+//--------------------------------------------------------------------------------------
+std::shared_ptr<SketchAPI_BSpline> SketchAPI_Sketch::addSpline(
+    const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+    const std::list<ModelHighAPI_Double>& theWeights)
+{
+  FeaturePtr aFeature = compositeFeature()->addFeature(SketchPlugin_BSpline::ID());
+  return BSplinePtr(new SketchAPI_BSpline(aFeature, thePoles, theWeights));
+}
+
+std::shared_ptr<SketchAPI_BSpline> SketchAPI_Sketch::addSpline(
+    const int theDegree,
+    const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+    const std::list<ModelHighAPI_Double>& theWeights,
+    const std::list<ModelHighAPI_Double>& theKnots,
+    const std::list<ModelHighAPI_Integer>& theMults)
+{
+  FeaturePtr aFeature = compositeFeature()->addFeature(SketchPlugin_BSpline::ID());
+  return BSplinePtr(new SketchAPI_BSpline(aFeature,
+      theDegree, thePoles, theWeights, theKnots, theMults));
+}
+
+std::shared_ptr<SketchAPI_BSpline> SketchAPI_Sketch::addSpline(
+    const ModelHighAPI_Selection & theExternal)
+{
+  FeaturePtr aFeature = compositeFeature()->addFeature(SketchPlugin_BSpline::ID());
+  return BSplinePtr(new SketchAPI_BSpline(aFeature, theExternal));
+}
+
+std::shared_ptr<SketchAPI_BSpline> SketchAPI_Sketch::addSpline(const std::string & theExternalName)
+{
+  FeaturePtr aFeature = compositeFeature()->addFeature(SketchPlugin_BSpline::ID());
+  return BSplinePtr(new SketchAPI_BSpline(aFeature, theExternalName));
+}
+
 //--------------------------------------------------------------------------------------
 std::shared_ptr<SketchAPI_Projection> SketchAPI_Sketch::addProjection(
     const ModelHighAPI_Selection & theExternalFeature,
index f1787c9360267c1f533f37f541c0ff84a067b53b..4ea404be6dc10a01ddc3b8fc55c09470132da644 100644 (file)
@@ -46,6 +46,7 @@ class SketchAPI_Ellipse;
 class SketchAPI_MacroEllipse;
 class SketchAPI_EllipticArc;
 class SketchAPI_MacroEllipticArc;
+class SketchAPI_BSpline;
 class SketchAPI_IntersectionPoint;
 class SketchAPI_Line;
 class SketchAPI_Mirror;
@@ -324,6 +325,26 @@ public:
   SKETCHAPI_EXPORT
   std::shared_ptr<SketchAPI_EllipticArc> addEllipticArc(const std::string & theExternalName);
 
+  /// Add B-spline
+  SKETCHAPI_EXPORT
+  std::shared_ptr<SketchAPI_BSpline> addSpline(
+      const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+      const std::list<ModelHighAPI_Double>& theWeights = std::list<ModelHighAPI_Double>());
+  /// Add B-spline
+  SKETCHAPI_EXPORT
+  std::shared_ptr<SketchAPI_BSpline> addSpline(
+      const int theDegree,
+      const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+      const std::list<ModelHighAPI_Double>& theWeights = std::list<ModelHighAPI_Double>(),
+      const std::list<ModelHighAPI_Double>& theKnots = std::list<ModelHighAPI_Double>(),
+      const std::list<ModelHighAPI_Integer>& theMults = std::list<ModelHighAPI_Integer>());
+  /// Add B-spline
+  SKETCHAPI_EXPORT
+  std::shared_ptr<SketchAPI_BSpline> addSpline(const ModelHighAPI_Selection & theExternal);
+  /// Add B-spline
+  SKETCHAPI_EXPORT
+  std::shared_ptr<SketchAPI_BSpline> addSpline(const std::string & theExternalName);
+
   /// Add projection
   SKETCHAPI_EXPORT
   std::shared_ptr<SketchAPI_Projection> addProjection(
index 467e04349007f9719eb375542bf144417d93f5ea..d169c52de4216d1433d8e58dafd556484b7c9f1a 100644 (file)
@@ -19,6 +19,7 @@
 
 #include "SketchAPI_SketchEntity.h"
 #include <SketchAPI_Arc.h>
+#include <SketchAPI_BSpline.h>
 #include <SketchAPI_Circle.h>
 #include <SketchAPI_Ellipse.h>
 #include <SketchAPI_EllipticArc.h>
@@ -30,6 +31,7 @@
 #include <ModelHighAPI_Tools.h>
 
 #include <SketchPlugin_Arc.h>
+#include <SketchPlugin_BSpline.h>
 #include <SketchPlugin_Circle.h>
 #include <SketchPlugin_Ellipse.h>
 #include <SketchPlugin_IntersectionPoint.h>
@@ -103,6 +105,8 @@ SketchAPI_SketchEntity::wrap(const std::list<std::shared_ptr<ModelAPI_Feature> >
       aResult.push_back(std::shared_ptr<SketchAPI_SketchEntity>(new SketchAPI_Ellipse(*anIt)));
     else if ((*anIt)->getKind() == SketchPlugin_EllipticArc::ID())
       aResult.push_back(std::shared_ptr<SketchAPI_SketchEntity>(new SketchAPI_EllipticArc(*anIt)));
+    else if ((*anIt)->getKind() == SketchPlugin_BSpline::ID())
+      aResult.push_back(std::shared_ptr<SketchAPI_SketchEntity>(new SketchAPI_BSpline(*anIt)));
     else if ((*anIt)->getKind() == SketchPlugin_Point::ID())
       aResult.push_back(std::shared_ptr<SketchAPI_SketchEntity>(new SketchAPI_Point(*anIt)));
     else if ((*anIt)->getKind() == SketchPlugin_IntersectionPoint::ID())
index 93788350bae92690c04502d068eb60227b3b250c..28370b70ce25ebc7c50275432d0d4c4d194e2abb 100644 (file)
@@ -31,6 +31,7 @@
   #include "SketchAPI_MacroEllipse.h"
   #include "SketchAPI_EllipticArc.h"
   #include "SketchAPI_MacroEllipticArc.h"
+  #include "SketchAPI_BSpline.h"
   #include "SketchAPI_Constraint.h"
   #include "SketchAPI_ConstraintAngle.h"
   #include "SketchAPI_IntersectionPoint.h"
index 63826c7da4d92ab455a5ce310b738a696b62c6d7..28200494663ca0d248c31f3a55e9e85c156f042f 100644 (file)
@@ -183,14 +183,10 @@ FeaturePtr SketchPlugin_MacroBSpline::createBSplineFeature()
   AttributePoint2DPtr aStartPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
       aBSpline->attribute(SketchPlugin_BSpline::START_ID()));
   aStartPoint->setValue(aPoles->pnt(0));
-  // internal constraint to keep position of the point
-  createInternalConstraint(aSketch, aStartPoint, aPoles, 0);
 
   AttributePoint2DPtr aEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
       aBSpline->attribute(SketchPlugin_BSpline::END_ID()));
   aEndPoint->setValue(aPoles->pnt(aPoles->size() - 1));
-  // internal constraint to keep position of the point
-  createInternalConstraint(aSketch, aEndPoint, aPoles, aPoles->size() - 1);
 
   aBSpline->boolean(SketchPlugin_BSpline::AUXILIARY_ID())->setValue(
       boolean(AUXILIARY_ID())->value());
index 499dfe1af8467f27ac7da03c7ea4b27fc73872a9..8db97df1a3ea32ba9bd78dc4c4fdb71c68bd7743 100644 (file)
@@ -301,6 +301,8 @@ EntityWrapperPtr createBSpline(const AttributeEntityMap& theAttributes)
   aNewSpline->degree = 3;
   aNewSpline->periodic = false;
 
+  std::map<std::string, EntityWrapperPtr> anAdditionalAttributes;
+
   AttributeEntityMap::const_iterator anIt = theAttributes.begin();
   for (; anIt != theAttributes.end(); ++anIt) {
     const std::string& anAttrID = anIt->first->id();
@@ -321,6 +323,10 @@ EntityWrapperPtr createBSpline(const AttributeEntityMap& theAttributes)
           std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(anIt->second);
       aNewSpline->degree = (int)aScalar->value();
     }
+    else if (anAttrID == SketchPlugin_BSpline::START_ID() ||
+             anAttrID == SketchPlugin_BSpline::END_ID()) {
+      anAdditionalAttributes[anAttrID] = anIt->second;
+    }
     else {
       ScalarArrayWrapperPtr anArray =
           std::dynamic_pointer_cast<PlaneGCSSolver_ScalarArrayWrapper>(anIt->second);
@@ -337,5 +343,7 @@ EntityWrapperPtr createBSpline(const AttributeEntityMap& theAttributes)
     }
   }
 
-  return EdgeWrapperPtr(new PlaneGCSSolver_EdgeWrapper(aNewSpline));
+  EdgeWrapperPtr aWrapper(new PlaneGCSSolver_EdgeWrapper(aNewSpline));
+  aWrapper->setAdditionalAttributes(anAdditionalAttributes);
+  return aWrapper;
 }
index 3c1e8fa4313d3212d029567458b5ac52b72defae..c190ae1b9cbcbff66bbfda51d2a39ddc020936af 100644 (file)
@@ -38,6 +38,7 @@
 #include <GeomDataAPI_Point2DArray.h>
 #include <ModelAPI_AttributeDoubleArray.h>
 #include <ModelAPI_AttributeRefAttr.h>
+#include <SketchPlugin_BSpline.h>
 #include <SketchPlugin_Ellipse.h>
 #include <SketchPlugin_Projection.h>
 
@@ -367,6 +368,45 @@ static void createEllipticArcConstraints(
   constraintsToSolver(aConstraint, theSolver);
 }
 
+static void createBSplineConstraints(
+    const EntityWrapperPtr& theCurve,
+    const SolverPtr& theSolver,
+    const ConstraintID theConstraintID,
+    std::map<EntityWrapperPtr, ConstraintWrapperPtr>& theConstraints)
+{
+  // set start and end point of B-spline equal to first and last pole correspondingly
+  EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theCurve);
+  std::shared_ptr<GCS::BSpline> aBSpline =
+      std::dynamic_pointer_cast<GCS::BSpline>(anEdge->entity());
+
+  std::list<GCSConstraintPtr> aBSplineConstraints;
+
+  const std::map<std::string, EntityWrapperPtr>& anAdditional = anEdge->additionalAttributes();
+  PointWrapperPtr aStartPoint = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(
+      anAdditional.at(SketchPlugin_BSpline::START_ID()));
+
+  const GCS::Point& sp = *aStartPoint->point();
+  const GCS::Point& p0 = aBSpline->poles.front();
+  aBSplineConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintEqual(p0.x, sp.x)));
+  aBSplineConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintEqual(p0.y, sp.y)));
+
+  PointWrapperPtr aEndPoint = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(
+      anAdditional.at(SketchPlugin_BSpline::END_ID()));
+
+  const GCS::Point& ep = *aEndPoint->point();
+  const GCS::Point& pN = aBSpline->poles.back();
+  aBSplineConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintEqual(pN.x, ep.x)));
+  aBSplineConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintEqual(pN.y, ep.y)));
+
+  ConstraintWrapperPtr aWrapper(
+      new PlaneGCSSolver_ConstraintWrapper(aBSplineConstraints, CONSTRAINT_UNKNOWN));
+  aWrapper->setId(theConstraintID);
+  if (theSolver)
+    constraintsToSolver(aWrapper, theSolver);
+
+  theConstraints[theCurve] = aWrapper;
+}
+
 void PlaneGCSSolver_Storage::createAuxiliaryConstraints(const EntityWrapperPtr& theEntity)
 {
   if (!theEntity || theEntity->isExternal())
@@ -380,6 +420,8 @@ void PlaneGCSSolver_Storage::createAuxiliaryConstraints(const EntityWrapperPtr&
     createEllipticArcConstraints(theEntity, mySketchSolver,
                                  ++myConstraintLastID, myAuxConstraintMap);
   }
+  else if (theEntity->type() == ENTITY_BSPLINE)
+    createBSplineConstraints(theEntity, mySketchSolver, ++myConstraintLastID, myAuxConstraintMap);
 }
 
 void PlaneGCSSolver_Storage::removeAuxiliaryConstraints(const EntityWrapperPtr& theEntity)