From 0fc5f96ba5c785c7cd55bf2c9b196727afa6640d Mon Sep 17 00:00:00 2001 From: azv Date: Fri, 31 Jan 2020 15:39:10 +0300 Subject: [PATCH] Improve code coverage for AttributeRefAttrList. --- src/ModelHighAPI/ModelHighAPI_RefAttr.cpp | 2 +- src/SketchAPI/SketchAPI.i | 200 +++++++++++++++--- src/SketchAPI/SketchAPI_Constraint.cpp | 13 -- src/SketchAPI/SketchAPI_Sketch.cpp | 89 ++++++-- src/SketchAPI/SketchAPI_Sketch.h | 19 +- src/SketchPlugin/CMakeLists.txt | 1 + .../SketchPlugin_MacroBSpline.cpp | 3 + .../Test/TestCreateMacroBSpline.py | 163 ++++++++++++++ 8 files changed, 422 insertions(+), 68 deletions(-) create mode 100644 src/SketchPlugin/Test/TestCreateMacroBSpline.py diff --git a/src/ModelHighAPI/ModelHighAPI_RefAttr.cpp b/src/ModelHighAPI/ModelHighAPI_RefAttr.cpp index 03548d252..7d2edf482 100644 --- a/src/ModelHighAPI/ModelHighAPI_RefAttr.cpp +++ b/src/ModelHighAPI/ModelHighAPI_RefAttr.cpp @@ -27,7 +27,7 @@ #include "ModelHighAPI_Interface.h" //-------------------------------------------------------------------------------------- ModelHighAPI_RefAttr::ModelHighAPI_RefAttr() -: myVariantType(VT_ATTRIBUTE) +: myVariantType(VT_OBJECT) { } diff --git a/src/SketchAPI/SketchAPI.i b/src/SketchAPI/SketchAPI.i index ee47707e0..6d113b794 100644 --- a/src/SketchAPI/SketchAPI.i +++ b/src/SketchAPI/SketchAPI.i @@ -344,29 +344,114 @@ %typemap(freearg) const std::pair, ModelHighAPI_RefAttr> & {} -%typemap(in) const std::list > & (std::list > temp) { - std::shared_ptr * temp_point = 0; - int newmem = 0; +%typemap(in) const std::list, ModelHighAPI_RefAttr> > & (std::list, 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(new GeomAPI_Pnt2d(x, y))); + + std::list 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 * temp_attribute = 0; + std::shared_ptr * temp_object = 0; + std::shared_ptr * temp_interface = 0; + ModelHighAPI_Selection* temp_selection = 0; + std::pair, ModelHighAPI_RefAttr>* temp_pair = 0; + std::shared_ptr * temp_point = 0; + ModelHighAPI_RefAttr temp_refattr; + int newmem = 0; + int clearmem = 0; + + for (std::list::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(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 *), 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 *), 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 *), 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, 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(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 *), 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(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, 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, ModelHighAPI_RefAttr>(std::shared_ptr(), temp_refattr)); } - } else - if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_point, $descriptor(std::shared_ptr *), 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); @@ -378,25 +463,88 @@ } } -%typecheck(SWIG_TYPECHECK_POINTER) std::list >, const std::list >& { - std::shared_ptr * temp_point = 0; +%typecheck(SWIG_TYPECHECK_POINTER) std::list, ModelHighAPI_RefAttr> >, const std::list, 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 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 * temp_attribute = 0; + std::shared_ptr * temp_object = 0; + std::shared_ptr * temp_interface = 0; + ModelHighAPI_Selection* temp_selection = 0; + std::pair, ModelHighAPI_RefAttr>* temp_pair = 0; + std::shared_ptr * temp_point = 0; + ModelHighAPI_RefAttr temp_refattr; + + $1 = 1; + for (std::list::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 *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) { - if (temp_point) { + } else + if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_attribute, $descriptor(std::shared_ptr *), 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 *), 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 *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) { + if (temp_interface) { + $1 = 1; + } else { + $1 = 0; + } + } else + if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_pair, $descriptor(std::pair, 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 *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) { + if (temp_point) { + $1 = 1; + } else { + $1 = 0; + } + } else + if (PyNumber_Check(item)) { $1 = 1; } else { $1 = 0; diff --git a/src/SketchAPI/SketchAPI_Constraint.cpp b/src/SketchAPI/SketchAPI_Constraint.cpp index b1fefb5e2..7ff2457a9 100644 --- a/src/SketchAPI/SketchAPI_Constraint.cpp +++ b/src/SketchAPI/SketchAPI_Constraint.cpp @@ -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; diff --git a/src/SketchAPI/SketchAPI_Sketch.cpp b/src/SketchAPI/SketchAPI_Sketch.cpp index 5a8d9ce21..7b472113e 100644 --- a/src/SketchAPI/SketchAPI_Sketch.cpp +++ b/src/SketchAPI/SketchAPI_Sketch.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include //-------------------------------------------------------------------------------------- #include @@ -607,9 +608,9 @@ std::shared_ptr SketchAPI_Sketch::addEllipse( } std::shared_ptr SketchAPI_Sketch::addEllipse( - const std::pair, ModelHighAPI_RefAttr>& thePoint1, - const std::pair, ModelHighAPI_RefAttr>& thePoint2, - const std::pair, ModelHighAPI_RefAttr>& thePassedPoint, + const PointOrReference& thePoint1, + const PointOrReference& thePoint2, + const PointOrReference& thePassedPoint, bool isPoint1Center) { std::shared_ptr aFeature = @@ -666,10 +667,10 @@ std::shared_ptr SketchAPI_Sketch::addEllipticArc( } std::shared_ptr SketchAPI_Sketch::addEllipticArc( - const std::pair, ModelHighAPI_RefAttr>& theCenter, - const std::pair, ModelHighAPI_RefAttr>& theMajorAxisPoint, - const std::pair, ModelHighAPI_RefAttr>& theStartPoint, - const std::pair, ModelHighAPI_RefAttr>& theEndPoint, + const PointOrReference& theCenter, + const PointOrReference& theMajorAxisPoint, + const PointOrReference& theStartPoint, + const PointOrReference& theEndPoint, bool theInversed) { std::shared_ptr aFeature = @@ -703,24 +704,74 @@ std::shared_ptr SketchAPI_Sketch::addEllipticArc( std::shared_ptr SketchAPI_Sketch::addSpline( const ModelHighAPI_Selection & external, const int degree, - const std::list >& poles, + const std::list& poles, const std::list& weights, const std::list& knots, const std::list& 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 aPoints; + std::list aReferences; + for (std::list::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( + 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(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; } diff --git a/src/SketchAPI/SketchAPI_Sketch.h b/src/SketchAPI/SketchAPI_Sketch.h index ddbb18291..e8a2b089f 100644 --- a/src/SketchAPI/SketchAPI_Sketch.h +++ b/src/SketchAPI/SketchAPI_Sketch.h @@ -56,6 +56,8 @@ class SketchAPI_Rectangle; class SketchAPI_Rotation; class SketchAPI_Translation; //-------------------------------------------------------------------------------------- +typedef std::pair, 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 addEllipse( - const std::pair, ModelHighAPI_RefAttr>& thePoint1, - const std::pair, ModelHighAPI_RefAttr>& thePoint2, - const std::pair, 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 addEllipticArc( - const std::pair, ModelHighAPI_RefAttr>& theCenter, - const std::pair, ModelHighAPI_RefAttr>& theMajorAxisPoint, - const std::pair, ModelHighAPI_RefAttr>& theStartPoint, - const std::pair, 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 addSpline( const ModelHighAPI_Selection & external = ModelHighAPI_Selection(), const int degree = -1, - const std::list >& poles = - std::list >(), + const std::list& poles = std::list(), const std::list& weights = std::list(), const std::list& knots = std::list(), const std::list& multiplicities = std::list(), diff --git a/src/SketchPlugin/CMakeLists.txt b/src/SketchPlugin/CMakeLists.txt index 27965e742..fbd8bb857 100644 --- a/src/SketchPlugin/CMakeLists.txt +++ b/src/SketchPlugin/CMakeLists.txt @@ -285,6 +285,7 @@ ADD_UNIT_TESTS( TestCreateEllipseByExternal.py TestCreateEllipticArc.py TestCreateEllipticArcByExternal.py + TestCreateMacroBSpline.py TestDegeneratedGeometry.py TestDistanceDump.py TestDistanceSignedVsUnsigned01.py diff --git a/src/SketchPlugin/SketchPlugin_MacroBSpline.cpp b/src/SketchPlugin/SketchPlugin_MacroBSpline.cpp index 4f491fe2d..0ed1258b5 100644 --- a/src/SketchPlugin/SketchPlugin_MacroBSpline.cpp +++ b/src/SketchPlugin/SketchPlugin_MacroBSpline.cpp @@ -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 index 000000000..478ef970f --- /dev/null +++ b/src/SketchPlugin/Test/TestCreateMacroBSpline.py @@ -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() -- 2.39.2