Salome HOME
Improve code coverage for AttributeRefAttrList.
authorazv <azv@opencascade.com>
Fri, 31 Jan 2020 12:39:10 +0000 (15:39 +0300)
committerazv <azv@opencascade.com>
Fri, 31 Jan 2020 12:39:35 +0000 (15:39 +0300)
src/ModelHighAPI/ModelHighAPI_RefAttr.cpp
src/SketchAPI/SketchAPI.i
src/SketchAPI/SketchAPI_Constraint.cpp
src/SketchAPI/SketchAPI_Sketch.cpp
src/SketchAPI/SketchAPI_Sketch.h
src/SketchPlugin/CMakeLists.txt
src/SketchPlugin/SketchPlugin_MacroBSpline.cpp
src/SketchPlugin/Test/TestCreateMacroBSpline.py [new file with mode: 0644]

index 03548d25270fe4ec2d63747e93fd1e8b68803bab..7d2edf482d8166faa14eb85bc84dc2599e4759ac 100644 (file)
@@ -27,7 +27,7 @@
 #include "ModelHighAPI_Interface.h"
 //--------------------------------------------------------------------------------------
 ModelHighAPI_RefAttr::ModelHighAPI_RefAttr()
-: myVariantType(VT_ATTRIBUTE)
+: myVariantType(VT_OBJECT)
 {
 }
 
index ee47707e0042c6bf37a723c4d708c9a45e0764d9..6d113b794dc297e1eb211a20b5d2f023127bbe7e 100644 (file)
 %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;
+%typemap(in) const std::list<std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr> > & (std::list<std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr> > temp) {
   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)));
+
+      std::list<PyObject*> temp_inputlist;
+      if (PySequence_Check(item)) {
+        for (Py_ssize_t i = 0; i < PySequence_Size(item); ++i) {
+          PyObject * tmpItem = PySequence_GetItem(item, i);
+          temp_inputlist.push_back(tmpItem);
+        }
+      } else {
+        temp_inputlist.push_back(item);
+      }
+
+      std::shared_ptr<ModelAPI_Attribute> * temp_attribute = 0;
+      std::shared_ptr<ModelAPI_Object> * temp_object = 0;
+      std::shared_ptr<ModelHighAPI_Interface> * temp_interface = 0;
+      ModelHighAPI_Selection* temp_selection = 0;
+      std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>* temp_pair = 0;
+      std::shared_ptr<GeomAPI_Pnt2d> * temp_point = 0;
+      ModelHighAPI_RefAttr temp_refattr;
+      int newmem = 0;
+      int clearmem = 0;
+
+      for (std::list<PyObject*>::iterator it = temp_inputlist.begin(); it != temp_inputlist.end(); ++it) {
+        PyObject* item = *it;
+
+        if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_selection, $descriptor(ModelHighAPI_Selection*), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
+          if (temp_selection) {
+            temp_refattr = ModelHighAPI_RefAttr(std::shared_ptr<ModelAPI_Object>(temp_selection->resultSubShapePair().first));
+            if (newmem & SWIG_CAST_NEW_MEMORY) {
+              delete temp_selection;
+            }
+          }
+        } else
+        if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_attribute, $descriptor(std::shared_ptr<ModelAPI_Attribute> *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
+          if (temp_attribute) {
+            temp_refattr = ModelHighAPI_RefAttr(*temp_attribute);
+            if (newmem & SWIG_CAST_NEW_MEMORY) {
+              delete temp_attribute;
+            }
+          }
+        } else
+        if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_object, $descriptor(std::shared_ptr<ModelAPI_Object> *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
+          if (temp_object) {
+            temp_refattr = ModelHighAPI_RefAttr(*temp_object);
+            if (newmem & SWIG_CAST_NEW_MEMORY) {
+              delete temp_object;
+            }
+          }
+        } else
+        if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_interface, $descriptor(std::shared_ptr<ModelHighAPI_Interface> *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
+          if (temp_interface) {
+            temp_refattr = ModelHighAPI_RefAttr(*temp_interface);
+            if (newmem & SWIG_CAST_NEW_MEMORY) {
+              delete temp_interface;
+            }
+          }
+        } else
+        if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_pair, $descriptor(std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr> *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
+          if (temp_pair) {
+            temp_point = &temp_pair->first;
+            temp_refattr = temp_pair->second;
+            if (newmem & SWIG_CAST_NEW_MEMORY) {
+              delete temp_pair;
+            }
+          }
+        } else
+        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_point = new std::shared_ptr<GeomAPI_Pnt2d>(new GeomAPI_Pnt2d(x, y));
+            clearmem = 1;
+          } 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) {
+          // fall through
+        } else
+        if (PyNumber_Check(item)) {
+          PyObject* item1 = *(++it);
+          if (PyNumber_Check(item1)) {
+            double x = (double)PyFloat_AsDouble(item);
+            double y = (double)PyFloat_AsDouble(item1);
+            temp_point = new std::shared_ptr<GeomAPI_Pnt2d>(new GeomAPI_Pnt2d(x, y));
+            clearmem = 1;
+          } else {
+            PyErr_SetString(PyExc_TypeError, "argument must a list of 2D points.");
+            return NULL;
+          }
+        }
+      }
+
+      if (temp_point || !temp_refattr.isEmpty()) {
+        if (temp_point) {
+          temp.push_back(std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>(*temp_point, temp_refattr));
         } else {
-          PyErr_SetString(PyExc_TypeError, "argument must a list of 2D points.");
-          return NULL;
+          temp.push_back(std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>(std::shared_ptr<GeomAPI_Pnt2d>(), temp_refattr));
         }
-      } 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)) {
+        if (temp_point && ((newmem & SWIG_CAST_NEW_MEMORY) || clearmem)) {
           delete temp_point;
         }
       } else {
-        PyErr_SetString(PyExc_TypeError, "argument must a list of 2D points.");
+        PyErr_SetString(PyExc_TypeError, "argument must be ModelHighAPI_RefAttr, ModelHighAPI_Selection, ModelHighAPI_Interface, ModelAPI_Attribute or ModelAPI_Object.");
         return NULL;
       }
       Py_DECREF(item);
   }
 }
 
-%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;
+%typecheck(SWIG_TYPECHECK_POINTER) std::list<std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr> >, const std::list<std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr> >& {
   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))) {
+
+      std::list<PyObject*> temp_inputlist;
+      if (PySequence_Check(item)) {
+        for (Py_ssize_t i = 0; i < PySequence_Size(item); ++i) {
+          PyObject * tmpItem = PySequence_GetItem(item, i);
+          temp_inputlist.push_back(tmpItem);
+        }
+      } else {
+        temp_inputlist.push_back(item);
+      }
+
+      std::shared_ptr<ModelAPI_Attribute> * temp_attribute = 0;
+      std::shared_ptr<ModelAPI_Object> * temp_object = 0;
+      std::shared_ptr<ModelHighAPI_Interface> * temp_interface = 0;
+      ModelHighAPI_Selection* temp_selection = 0;
+      std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>* temp_pair = 0;
+      std::shared_ptr<GeomAPI_Pnt2d> * temp_point = 0;
+      ModelHighAPI_RefAttr temp_refattr;
+
+      $1 = 1;
+      for (std::list<PyObject*>::iterator it = temp_inputlist.begin(); it != temp_inputlist.end() && $1; ++it) {
+        PyObject* item = *it;
+
+        if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_selection, $descriptor(ModelHighAPI_Selection*), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
+          if (temp_selection) {
             $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) {
+        } else
+        if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_attribute, $descriptor(std::shared_ptr<ModelAPI_Attribute> *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
+          if (temp_attribute) {
+            $1 = 1;
+          } else {
+            $1 = 0;
+          }
+        } else
+        if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_object, $descriptor(std::shared_ptr<ModelAPI_Object> *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
+          if (temp_object) {
+            $1 = 1;
+          } else {
+            $1 = 0;
+          }
+        } else
+        if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_interface, $descriptor(std::shared_ptr<ModelHighAPI_Interface> *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
+          if (temp_interface) {
+            $1 = 1;
+          } else {
+            $1 = 0;
+          }
+        } else
+        if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_pair, $descriptor(std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr> *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
+          if (temp_pair) {
+            $1 = 1;
+          } else {
+            $1 = 0;
+          }
+        } else
+        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;
+          }
+        } else
+        if (PyNumber_Check(item)) {
           $1 = 1;
         } else {
           $1 = 0;
index b1fefb5e25c945e95743b65687b36b8237be8834..7ff2457a9b5f6b86e1e3fc1bc2458b65ee674927 100644 (file)
@@ -156,19 +156,6 @@ static const std::string& constraintTypeToSetter(const std::string& theType)
   return DUMMY;
 }
 
-static std::string angleTypeToString(int theAngleType)
-{
-  switch (theAngleType) {
-  case SketcherPrs_Tools::ANGLE_COMPLEMENTARY:
-    return std::string("Complementary");
-  case SketcherPrs_Tools::ANGLE_BACKWARD:
-    return std::string("Backward");
-  default:
-    break;
-  }
-  return std::string();
-}
-
 bool SketchAPI_Constraint::areAllAttributesDumped(ModelHighAPI_Dumper& theDumper) const
 {
   bool areAttributesDumped = true;
index 5a8d9ce21a3158b9ca52667fb5f933721915feba..7b472113e72a508ca7e994bf0a65629c18d8d4e1 100644 (file)
@@ -40,6 +40,7 @@
 #include <SketchPlugin_Split.h>
 #include <SketchPlugin_ConstraintTangent.h>
 #include <SketchPlugin_ConstraintVertical.h>
+#include <SketchPlugin_MacroBSpline.h>
 #include <SketcherPrs_Tools.h>
 //--------------------------------------------------------------------------------------
 #include <ModelAPI_Events.h>
@@ -607,9 +608,9 @@ std::shared_ptr<SketchAPI_MacroEllipse> SketchAPI_Sketch::addEllipse(
 }
 
 std::shared_ptr<SketchAPI_MacroEllipse> SketchAPI_Sketch::addEllipse(
-    const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& thePoint1,
-    const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& thePoint2,
-    const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& thePassedPoint,
+    const PointOrReference& thePoint1,
+    const PointOrReference& thePoint2,
+    const PointOrReference& thePassedPoint,
     bool isPoint1Center)
 {
   std::shared_ptr<ModelAPI_Feature> aFeature =
@@ -666,10 +667,10 @@ std::shared_ptr<SketchAPI_EllipticArc> SketchAPI_Sketch::addEllipticArc(
 }
 
 std::shared_ptr<SketchAPI_MacroEllipticArc> SketchAPI_Sketch::addEllipticArc(
-    const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& theCenter,
-    const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& theMajorAxisPoint,
-    const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& theStartPoint,
-    const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& theEndPoint,
+    const PointOrReference& theCenter,
+    const PointOrReference& theMajorAxisPoint,
+    const PointOrReference& theStartPoint,
+    const PointOrReference& theEndPoint,
     bool theInversed)
 {
   std::shared_ptr<ModelAPI_Feature> aFeature =
@@ -703,24 +704,74 @@ std::shared_ptr<SketchAPI_EllipticArc> SketchAPI_Sketch::addEllipticArc(
 std::shared_ptr<SketchAPI_BSpline> SketchAPI_Sketch::addSpline(
     const ModelHighAPI_Selection & external,
     const int degree,
-    const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& poles,
+    const std::list<PointOrReference>& poles,
     const std::list<ModelHighAPI_Double>& weights,
     const std::list<ModelHighAPI_Double>& knots,
     const std::list<ModelHighAPI_Integer>& multiplicities,
     const bool periodic)
 {
-  FeaturePtr aFeature = compositeFeature()->addFeature(
-    periodic ? SketchPlugin_BSplinePeriodic::ID() : SketchPlugin_BSpline::ID());
-
-  BSplinePtr aBSpline(periodic ? new SketchAPI_BSplinePeriodic(aFeature)
-                               : new SketchAPI_BSpline(aFeature));
-  if (external.variantType() != ModelHighAPI_Selection::VT_Empty)
-    aBSpline->setByExternal(external);
-  else if (knots.empty() || multiplicities.empty())
-    aBSpline->setByDegreePolesAndWeights(degree, poles, weights);
-  else
-    aBSpline->setByParameters(degree, poles, weights, knots, multiplicities);
+  // split poles and references to other shapes
+  bool hasReference = false;
+  std::list<GeomPnt2dPtr> aPoints;
+  std::list<ModelHighAPI_RefAttr> aReferences;
+  for (std::list<PointOrReference>::const_iterator it = poles.begin(); it != poles.end(); ++it) {
+    aPoints.push_back(it->first);
+    aReferences.push_back(it->second);
+    if (!it->second.isEmpty())
+      hasReference = true;
+  }
 
+  BSplinePtr aBSpline;
+  CompositeFeaturePtr aSketch = compositeFeature();
+  if (hasReference) {
+    // use macro-feature to create coincidences to referred features
+    FeaturePtr aMacroFeature = aSketch->addFeature(
+        periodic ? SketchPlugin_MacroBSplinePeriodic::ID() : SketchPlugin_MacroBSpline::ID());
+    AttributePoint2DArrayPtr aPolesAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
+        aMacroFeature->attribute(SketchPlugin_MacroBSpline::POLES_ID()));
+    AttributeDoubleArrayPtr aWeightsAttr =
+        aMacroFeature->data()->realArray(SketchPlugin_MacroBSpline::WEIGHTS_ID());
+    AttributeRefAttrListPtr aPolesRefAttr =
+        aMacroFeature->data()->refattrlist(SketchPlugin_MacroBSpline::REF_POLES_ID());
+    // always generate a control polygon to apply coincidences correctly
+    aMacroFeature->boolean(SketchPlugin_MacroBSpline::CONTROL_POLYGON_ID())->setValue(true);
+    // initialize B-spline attributes
+    fillAttribute(aPoints, aPolesAttr);
+    if (weights.empty())
+      fillAttribute(std::list<ModelHighAPI_Double>(poles.size(), 1.0), aWeightsAttr);
+    else
+      fillAttribute(weights, aWeightsAttr);
+    fillAttribute(aReferences, aPolesRefAttr);
+    apply(); // to kill macro-feature
+
+    // find created B-spline feature
+    const std::string& aKindToFind =
+        periodic ? SketchPlugin_BSplinePeriodic::ID() : SketchPlugin_BSpline::ID();
+    int aNbSubs = aSketch->numberOfSubs();
+    for (int anIndex = aNbSubs - 1; anIndex >= 0; --anIndex) {
+      FeaturePtr aFeature = aSketch->subFeature(anIndex);
+      if (aFeature->getKind() == aKindToFind) {
+        aBSpline.reset(periodic ? new SketchAPI_BSplinePeriodic(aFeature)
+                                : new SketchAPI_BSpline(aFeature));
+        aBSpline->execute();
+        break;
+      }
+    }
+  }
+  else {
+    // compute B-spline by parameters
+    FeaturePtr aFeature = aSketch->addFeature(
+        periodic ? SketchPlugin_BSplinePeriodic::ID() : SketchPlugin_BSpline::ID());
+
+    aBSpline.reset(periodic ? new SketchAPI_BSplinePeriodic(aFeature)
+                            : new SketchAPI_BSpline(aFeature));
+    if (external.variantType() != ModelHighAPI_Selection::VT_Empty)
+      aBSpline->setByExternal(external);
+    else if (knots.empty() || multiplicities.empty())
+      aBSpline->setByDegreePolesAndWeights(degree, aPoints, weights);
+    else
+      aBSpline->setByParameters(degree, aPoints, weights, knots, multiplicities);
+  }
   return aBSpline;
 }
 
index ddbb1829186f83da593adb0520b1716aeed821cd..e8a2b089f1136b92fbe99f3633a4cdc4a19bc3fe 100644 (file)
@@ -56,6 +56,8 @@ class SketchAPI_Rectangle;
 class SketchAPI_Rotation;
 class SketchAPI_Translation;
 //--------------------------------------------------------------------------------------
+typedef std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr> PointOrReference;
+//--------------------------------------------------------------------------------------
 /**\class SketchAPI_Sketch
  * \ingroup CPPHighAPI
  * \brief Interface for Sketch feature
@@ -291,9 +293,9 @@ public:
   /// Add ellipse
   SKETCHAPI_EXPORT
   std::shared_ptr<SketchAPI_MacroEllipse> addEllipse(
-      const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& thePoint1,
-      const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& thePoint2,
-      const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& thePassedPoint,
+      const PointOrReference& thePoint1,
+      const PointOrReference& thePoint2,
+      const PointOrReference& thePassedPoint,
       bool isPoint1Center = true);
   /// Add ellipse
   SKETCHAPI_EXPORT
@@ -313,10 +315,10 @@ public:
   /// Add elliptic arc
   SKETCHAPI_EXPORT
   std::shared_ptr<SketchAPI_MacroEllipticArc> addEllipticArc(
-      const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& theCenter,
-      const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& theMajorAxisPoint,
-      const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& theStartPoint,
-      const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>& theEndPoint,
+      const PointOrReference& theCenter,
+      const PointOrReference& theMajorAxisPoint,
+      const PointOrReference& theStartPoint,
+      const PointOrReference& theEndPoint,
       bool theInversed = false);
   /// Add elliptic arc
   SKETCHAPI_EXPORT
@@ -330,8 +332,7 @@ public:
   std::shared_ptr<SketchAPI_BSpline> addSpline(
       const ModelHighAPI_Selection & external = ModelHighAPI_Selection(),
       const int degree = -1,
-      const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& poles =
-                                          std::list<std::shared_ptr<GeomAPI_Pnt2d> >(),
+      const std::list<PointOrReference>& poles = std::list<PointOrReference>(),
       const std::list<ModelHighAPI_Double>& weights = std::list<ModelHighAPI_Double>(),
       const std::list<ModelHighAPI_Double>& knots = std::list<ModelHighAPI_Double>(),
       const std::list<ModelHighAPI_Integer>& multiplicities = std::list<ModelHighAPI_Integer>(),
index 27965e742648c96ed226431afd726e030ca30892..fbd8bb857f34acf23577065d6b33780080d4d047 100644 (file)
@@ -285,6 +285,7 @@ ADD_UNIT_TESTS(
   TestCreateEllipseByExternal.py
   TestCreateEllipticArc.py
   TestCreateEllipticArcByExternal.py
+  TestCreateMacroBSpline.py
   TestDegeneratedGeometry.py
   TestDistanceDump.py
   TestDistanceSignedVsUnsigned01.py
index 4f491fe2d9cd7470ef2651cf1445116c24035bc7..0ed1258b51d1526b36c5c0bbf73eedf5a1f8d4de 100644 (file)
@@ -142,6 +142,9 @@ std::string SketchPlugin_MacroBSpline::processEvent(
 
 FeaturePtr SketchPlugin_MacroBSpline::createBSplineFeature()
 {
+  if (myKnots.empty() || myMultiplicities.empty())
+    getAISObject(AISObjectPtr()); // fill B-spline parameters
+
   FeaturePtr aBSpline = sketch()->addFeature(
       myIsPeriodic ? SketchPlugin_BSplinePeriodic::ID() : SketchPlugin_BSpline::ID());
 
diff --git a/src/SketchPlugin/Test/TestCreateMacroBSpline.py b/src/SketchPlugin/Test/TestCreateMacroBSpline.py
new file mode 100644 (file)
index 0000000..478ef97
--- /dev/null
@@ -0,0 +1,163 @@
+# Copyright (C) 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
+#
+
+"""
+    Test creation of B-spline curve by references to another features
+"""
+
+import unittest
+from salome.shaper import model
+
+from GeomAPI import *
+from GeomDataAPI import *
+from ModelAPI import *
+from SketchAPI import *
+
+__updated__ = "2020-01-31"
+
+class TestMacroBSpline(unittest.TestCase):
+  def setUp(self):
+    model.begin()
+    self.myDocument = model.moduleDocument()
+    self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+    self.myPoint = self.mySketch.addPoint(50., 50.)
+    self.myLine = self.mySketch.addLine(30., -1., 70., 19.)
+
+    self.myPoles = [[GeomAPI_Pnt2d(50., 50.), self.myPoint.coordinates()],
+                    GeomAPI_Pnt2d(70., 70.),
+                    (80., 30.),
+                    [GeomAPI_Pnt2d(50., 10.), self.myLine.result()],
+                    GeomAPI_Pnt2d(20., 10.)
+                   ]
+
+    self.myDegree = 3;
+    self.myDOF = 6
+    self.myNbPoints = 1
+    self.myNbLines = 1
+    self.myNbSplines = 0
+    self.myNbSplinesP = 0
+    self.myNbCoincidences = 0
+    self.myNbInternal = 0
+
+  def tearDown(self):
+    self.checkDOF()
+    model.end()
+    model.testNbSubFeatures(self.mySketch, "SketchPoint", self.myNbPoints)
+    model.testNbSubFeatures(self.mySketch, "SketchLine", self.myNbLines)
+    model.testNbSubFeatures(self.mySketch, "SketchBSpline", self.myNbSplines)
+    model.testNbSubFeatures(self.mySketch, "SketchBSplinePeriodic", self.myNbSplinesP)
+    model.testNbSubFeatures(self.mySketch, "SketchMacroBSpline", 0)
+    model.testNbSubFeatures(self.mySketch, "SketchMacroBSplinePeriodic", 0)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", self.myNbCoincidences)
+    model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidenceInternal", self.myNbInternal)
+
+
+  def checkDOF(self):
+    self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+
+  def test_bspline_non_periodic(self):
+    """ Test 1. Create B-spline curve by poles and references to other shapes
+    """
+    self.mySpline = self.mySketch.addSpline(poles = self.myPoles)
+    self.myDOF += len(self.myPoles) * 2 - 3
+    self.myNbSplines += 1
+    self.myNbPoints += len(self.myPoles)
+    self.myNbLines += len(self.myPoles) - 1
+    self.myNbCoincidences += 2
+    self.myNbInternal += len(self.myPoles) * 3 - 2
+    model.do()
+
+    assert(self.mySpline.feature())
+    assert(self.mySpline.feature().error() == "")
+    assert(self.mySpline.degree().value() == self.myDegree)
+
+  def test_bspline_periodic(self):
+    """ Test 2. Create periodic B-spline curve by poles and references to other shapes
+    """
+    self.mySpline = self.mySketch.addSpline(poles = self.myPoles, periodic = True)
+    self.myDOF += len(self.myPoles) * 2 - 3
+    self.myNbSplinesP += 1
+    self.myNbPoints += len(self.myPoles)
+    self.myNbLines += len(self.myPoles)
+    self.myNbCoincidences += 2
+    self.myNbInternal += len(self.myPoles) * 3
+    model.do()
+
+    assert(self.mySpline.feature())
+    assert(self.mySpline.feature().error() == "")
+    assert(self.mySpline.degree().value() == self.myDegree)
+
+  def test_bspline_lowlevel(self):
+    """ Test 3. Create macro B-spline on low-level to test attributeRefAttrList
+    """
+    model.end()
+    session = ModelAPI_Session.get()
+    sketch = featureToCompositeFeature(self.mySketch.feature())
+    session.startOperation()
+    bspline = sketch.addFeature("SketchMacroBSpline")
+    poles = geomDataAPI_Point2DArray(bspline.attribute("poles"))
+    weights = bspline.data().realArray("weights")
+    polesRef = bspline.data().refattrlist("poles_ref")
+    bspline.boolean("need_control_poly").setValue(False)
+
+    poles.setSize(3); weights.setSize(3)
+    poles.setPnt(0, GeomAPI_Pnt2d(50., 50.)); weights.setValue(0, 1.0); polesRef.append(self.myPoint.coordinates())
+    poles.setPnt(1, GeomAPI_Pnt2d(50., 10.)); weights.setValue(1, 1.0); polesRef.append(self.myLine.defaultResult())
+    poles.setPnt(2, GeomAPI_Pnt2d(20., 10.)); weights.setValue(2, 1.0); polesRef.append(None)
+
+    assert(polesRef.isInList(self.myPoint.coordinates()))
+    assert(not polesRef.isInList(self.myLine.startPoint()))
+    assert(polesRef.isInList(self.myLine.defaultResult()))
+    assert(not polesRef.isInList(self.myPoint.defaultResult()))
+
+    assert(polesRef.isAttribute(0))
+    assert(not polesRef.isAttribute(1))
+    assert(not polesRef.isAttribute(2))
+    assert(not polesRef.isAttribute(3))
+
+    assert(polesRef.attribute(0) is not None)
+    assert(polesRef.attribute(1) is None)
+    assert(polesRef.attribute(2) is None)
+    assert(polesRef.attribute(3) is None)
+    assert(polesRef.object(0) is not None)
+    assert(polesRef.object(1) is not None)
+    assert(polesRef.object(2) is None)
+    assert(polesRef.object(3) is None)
+
+    polesRef.remove(self.myPoint.coordinates())
+    polesRef.remove(self.myLine.defaultResult())
+    assert(polesRef.size() == 1)
+    polesRef.removeLast()
+
+    polesRef.append(self.myPoint.coordinates())
+    polesRef.append(None)
+    polesRef.append(self.myLine.defaultResult())
+    polesRef.removeLast()
+    polesRef.append(self.myLine.defaultResult())
+
+    session.finishOperation()
+    model.begin()
+    self.myDOF += 6
+    self.myNbSplines += 1
+
+if __name__ == "__main__":
+    test_program = unittest.main(exit=False)
+    assert test_program.result.wasSuccessful(), "Test failed"
+    assert model.checkPythonDump()