From 15e07776045d232135802444b5eb3375e31c9a0e Mon Sep 17 00:00:00 2001 From: azv Date: Mon, 20 Jan 2020 16:31:16 +0300 Subject: [PATCH] Unit tests for B-splines in the sketcher. --- src/GeomAPI/GeomAPI.i | 4 + src/GeomAPI/GeomAPI_BSpline2d.cpp | 12 +- src/GeomAPI/GeomAPI_Edge.cpp | 13 + src/GeomAPI/GeomAPI_Edge.h | 4 + src/GeomAPI/GeomAPI_swig.h | 2 + src/GeomDataAPI/GeomDataAPI.i | 3 + src/GeomDataAPI/GeomDataAPI_swig.h | 1 + src/ModelHighAPI/ModelHighAPI.i | 39 ++ src/ModelHighAPI/ModelHighAPI_Dumper.cpp | 14 + src/ModelHighAPI/ModelHighAPI_Dumper.h | 4 + src/SketchAPI/SketchAPI_Sketch.cpp | 18 +- src/SketchPlugin/CMakeLists.txt | 4 + src/SketchPlugin/SketchPlugin_BSpline.cpp | 11 +- src/SketchPlugin/Test/TestCreateBSpline.py | 195 ++++++++ src/SketchPlugin/Test/TestMoveBSpline.py | 418 ++++++++++++++++++ src/SketchPlugin/Test/TestPresentation.py | 19 + .../Test/TestProjectionBSpline.py | 78 ++++ src/SketchPlugin/Test/TestRemoveBSpline.py | 108 +++++ 18 files changed, 941 insertions(+), 6 deletions(-) create mode 100644 src/SketchPlugin/Test/TestCreateBSpline.py create mode 100644 src/SketchPlugin/Test/TestMoveBSpline.py create mode 100644 src/SketchPlugin/Test/TestProjectionBSpline.py create mode 100644 src/SketchPlugin/Test/TestRemoveBSpline.py diff --git a/src/GeomAPI/GeomAPI.i b/src/GeomAPI/GeomAPI.i index 4c4110155..29d051d85 100644 --- a/src/GeomAPI/GeomAPI.i +++ b/src/GeomAPI/GeomAPI.i @@ -42,6 +42,8 @@ %shared_ptr(GeomAPI_Ax2) %shared_ptr(GeomAPI_Ax3) %shared_ptr(GeomAPI_Box) +%shared_ptr(GeomAPI_BSpline) +%shared_ptr(GeomAPI_BSpline2d) %shared_ptr(GeomAPI_Circ) %shared_ptr(GeomAPI_Circ2d) %shared_ptr(GeomAPI_Cone) @@ -125,6 +127,8 @@ %include "GeomAPI_Ax2.h" %include "GeomAPI_Ax3.h" %include "GeomAPI_Box.h" +%include "GeomAPI_BSpline.h" +%include "GeomAPI_BSpline2d.h" %include "GeomAPI_Circ.h" %include "GeomAPI_Circ2d.h" %include "GeomAPI_Cone.h" diff --git a/src/GeomAPI/GeomAPI_BSpline2d.cpp b/src/GeomAPI/GeomAPI_BSpline2d.cpp index de07f9299..d23633dfa 100644 --- a/src/GeomAPI/GeomAPI_BSpline2d.cpp +++ b/src/GeomAPI/GeomAPI_BSpline2d.cpp @@ -26,6 +26,13 @@ #define MY_BSPLINE (*(implPtr())) +static Handle_Geom2d_BSplineCurve* newBSpline2d( + const std::list >& thePoles, + const std::list& theWeights, + const int theDegree, + const bool thePeriodic); + + static Handle_Geom2d_BSplineCurve* newBSpline2d( const std::list >& thePoles, const std::list& theWeights, @@ -34,6 +41,9 @@ static Handle_Geom2d_BSplineCurve* newBSpline2d( const int theDegree, const bool thePeriodic) { + if (theKnots.empty() || theMults.empty()) + return newBSpline2d(thePoles, theWeights, theDegree, thePeriodic); + // collect arrays of poles, weights, knots and multiplicities TColgp_Array1OfPnt2d aPoles(1, (int)thePoles.size()); TColStd_Array1OfReal aWeights(1, (int)theWeights.size()); @@ -62,7 +72,7 @@ static Handle_Geom2d_BSplineCurve* newBSpline2d( return new Handle_Geom2d_BSplineCurve(aCurve); } -static Handle_Geom2d_BSplineCurve* newBSpline2d( +Handle_Geom2d_BSplineCurve* newBSpline2d( const std::list >& thePoles, const std::list& theWeights, const int theDegree, diff --git a/src/GeomAPI/GeomAPI_Edge.cpp b/src/GeomAPI/GeomAPI_Edge.cpp index c4504272b..fdd99efb8 100644 --- a/src/GeomAPI/GeomAPI_Edge.cpp +++ b/src/GeomAPI/GeomAPI_Edge.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -179,6 +180,18 @@ bool GeomAPI_Edge::isEllipse() const return false; } +bool GeomAPI_Edge::isBSpline() const +{ + const TopoDS_Shape& aShape = const_cast(this)->impl(); + double aFirst, aLast; + Handle(Geom_Curve) aCurve = BRep_Tool::Curve((const TopoDS_Edge&)aShape, aFirst, aLast); + if (aCurve.IsNull()) // degenerative edge + return false; + while (aCurve->IsKind(STANDARD_TYPE(Geom_TrimmedCurve))) + aCurve = Handle(Geom_TrimmedCurve)::DownCast(aCurve)->BasisCurve(); + return aCurve->IsKind(STANDARD_TYPE(Geom_BSplineCurve)); +} + std::shared_ptr GeomAPI_Edge::firstPoint() { const TopoDS_Shape& aShape = const_cast(this)->impl(); diff --git a/src/GeomAPI/GeomAPI_Edge.h b/src/GeomAPI/GeomAPI_Edge.h index fdf82ed6f..b319cc26d 100644 --- a/src/GeomAPI/GeomAPI_Edge.h +++ b/src/GeomAPI/GeomAPI_Edge.h @@ -70,6 +70,10 @@ public: GEOMAPI_EXPORT bool isEllipse() const; + /// Verifies that the edge is based on a B-spline curve + GEOMAPI_EXPORT + bool isBSpline() const; + /// Returns the first vertex coordinates of the edge GEOMAPI_EXPORT std::shared_ptr firstPoint(); diff --git a/src/GeomAPI/GeomAPI_swig.h b/src/GeomAPI/GeomAPI_swig.h index 8c5472e93..065840804 100644 --- a/src/GeomAPI/GeomAPI_swig.h +++ b/src/GeomAPI/GeomAPI_swig.h @@ -28,6 +28,8 @@ #include "GeomAPI_Ax2.h" #include "GeomAPI_Ax3.h" #include "GeomAPI_Box.h" + #include "GeomAPI_BSpline.h" + #include "GeomAPI_BSpline2d.h" #include "GeomAPI_Circ.h" #include "GeomAPI_Circ2d.h" #include "GeomAPI_Cone.h" diff --git a/src/GeomDataAPI/GeomDataAPI.i b/src/GeomDataAPI/GeomDataAPI.i index 3fd23f6c8..1a6fd286b 100644 --- a/src/GeomDataAPI/GeomDataAPI.i +++ b/src/GeomDataAPI/GeomDataAPI.i @@ -40,13 +40,16 @@ %shared_ptr(GeomDataAPI_Point) %shared_ptr(GeomDataAPI_Dir) %shared_ptr(GeomDataAPI_Point2D) +%shared_ptr(GeomDataAPI_Point2DArray) // all supported interfaces %include "GeomDataAPI_Point.h" %include "GeomDataAPI_Dir.h" %include "GeomDataAPI_Point2D.h" +%include "GeomDataAPI_Point2DArray.h" template std::shared_ptr castTo(std::shared_ptr theObject); %template(geomDataAPI_Point) castTo; %template(geomDataAPI_Dir) castTo; %template(geomDataAPI_Point2D) castTo; +%template(geomDataAPI_Point2DArray) castTo; diff --git a/src/GeomDataAPI/GeomDataAPI_swig.h b/src/GeomDataAPI/GeomDataAPI_swig.h index b23de6016..9cd94e9f3 100644 --- a/src/GeomDataAPI/GeomDataAPI_swig.h +++ b/src/GeomDataAPI/GeomDataAPI_swig.h @@ -28,6 +28,7 @@ #include "GeomDataAPI_Point.h" #include "GeomDataAPI_Dir.h" #include "GeomDataAPI_Point2D.h" + #include "GeomDataAPI_Point2DArray.h" #include #include diff --git a/src/ModelHighAPI/ModelHighAPI.i b/src/ModelHighAPI/ModelHighAPI.i index 442e1cd2a..30fb144b3 100644 --- a/src/ModelHighAPI/ModelHighAPI.i +++ b/src/ModelHighAPI/ModelHighAPI.i @@ -467,6 +467,7 @@ %typecheck(SWIG_TYPECHECK_POINTER) std::list, const std::list & { if (PySequence_Check($input)) { + $1 = 1; 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; @@ -478,6 +479,44 @@ } +%typemap(in) const std::list & (std::list temp) { + ModelHighAPI_Integer * temp_int; + 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(ModelHighAPI_Integer(PyLong_AsLong(item))); + } else if (PyUnicode_Check(item)) { + temp.push_back(ModelHighAPI_Integer(PyUnicode_AsUTF8(item))); + } else if ((SWIG_ConvertPtr(item, (void **)&temp_int, $1_descriptor, SWIG_POINTER_EXCEPTION)) == 0) { + temp.push_back(*temp_int); + } else { + PyErr_SetString(PyExc_ValueError, "argument must be a list of ModelHighAPI_Integer, int or string."); + return NULL; + } + Py_DECREF(item); + } + $1 = &temp; + } else { + PyErr_SetString(PyExc_ValueError, "argument must be a list of ModelHighAPI_Integer, int or string."); + return NULL; + } +} + +%typecheck(SWIG_TYPECHECK_POINTER) std::list, const std::list & { + if (PySequence_Check($input)) { + $1 = 1; + for (Py_ssize_t i = 0; i < PySequence_Size($input) && $1; ++i) { + PyObject * item = PySequence_GetItem($input, i); + $1 = ((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" diff --git a/src/ModelHighAPI/ModelHighAPI_Dumper.cpp b/src/ModelHighAPI/ModelHighAPI_Dumper.cpp index 677e31be7..1d655bbdf 100644 --- a/src/ModelHighAPI/ModelHighAPI_Dumper.cpp +++ b/src/ModelHighAPI/ModelHighAPI_Dumper.cpp @@ -1140,6 +1140,20 @@ ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<( return *this; } +ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<( + const std::shared_ptr& 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& theAttrReal) { diff --git a/src/ModelHighAPI/ModelHighAPI_Dumper.h b/src/ModelHighAPI/ModelHighAPI_Dumper.h index f9114176d..90242c3aa 100644 --- a/src/ModelHighAPI/ModelHighAPI_Dumper.h +++ b/src/ModelHighAPI/ModelHighAPI_Dumper.h @@ -42,6 +42,7 @@ class ModelAPI_Attribute; class ModelAPI_AttributeBoolean; class ModelAPI_AttributeDouble; class ModelAPI_AttributeDoubleArray; +class ModelAPI_AttributeIntArray; class ModelAPI_AttributeInteger; class ModelAPI_AttributeRefAttr; class ModelAPI_AttributeRefAttrList; @@ -274,6 +275,9 @@ public: /// Dump AttributeInteger MODELHIGHAPI_EXPORT ModelHighAPI_Dumper& operator<<(const std::shared_ptr& theAttrInt); + /// Dump AttributeIntArray + MODELHIGHAPI_EXPORT + ModelHighAPI_Dumper& operator<<(const std::shared_ptr& theArray); /// Dump AttributeDouble MODELHIGHAPI_EXPORT ModelHighAPI_Dumper& operator<<(const std::shared_ptr& theAttrReal); diff --git a/src/SketchAPI/SketchAPI_Sketch.cpp b/src/SketchAPI/SketchAPI_Sketch.cpp index d1d2967b1..f64f93fc6 100644 --- a/src/SketchAPI/SketchAPI_Sketch.cpp +++ b/src/SketchAPI/SketchAPI_Sketch.cpp @@ -1219,7 +1219,19 @@ static std::shared_ptr pointOnEllipse(const FeaturePtr& theFeatur return aMajorAxisEnd ? aMajorAxisEnd->pnt() : std::shared_ptr(); } -static std::shared_ptr middlePoint(const ObjectPtr& theObject) +static std::shared_ptr middlePointOnBSpline(const FeaturePtr& theFeature, + const CompositeFeaturePtr& theSketch) +{ + GeomAPI_Edge anEdge(theFeature->lastResult()->shape()); + GeomPointPtr aMiddle = anEdge.middlePoint(); + + std::shared_ptr aSketch = + std::dynamic_pointer_cast(theSketch); + return aSketch->to2D(aMiddle); +} + +static std::shared_ptr middlePoint(const ObjectPtr& theObject, + const CompositeFeaturePtr& theSketch) { std::shared_ptr aMiddlePoint; FeaturePtr aFeature = ModelAPI_Feature::feature(theObject); @@ -1238,6 +1250,8 @@ static std::shared_ptr middlePoint(const ObjectPtr& theObject) aMiddlePoint = pointOnEllipse(aFeature); else if (aFeatureKind == SketchPlugin_EllipticArc::ID()) aMiddlePoint = pointOnEllipse(aFeature, false); + else if (aFeatureKind == SketchPlugin_BSpline::ID()) + aMiddlePoint = middlePointOnBSpline(aFeature, theSketch); } return aMiddlePoint; } @@ -1252,7 +1266,7 @@ void SketchAPI_Sketch::move(const ModelHighAPI_RefAttr& theMovedEntity, if (aMessage->movedAttribute()) anOriginalPosition = pointCoordinates(aMessage->movedAttribute()); else - anOriginalPosition = middlePoint(aMessage->movedObject()); + anOriginalPosition = middlePoint(aMessage->movedObject(), compositeFeature()); if (!anOriginalPosition) return; // something has gone wrong, do not process movement diff --git a/src/SketchPlugin/CMakeLists.txt b/src/SketchPlugin/CMakeLists.txt index cf6523d41..e2ad2a043 100644 --- a/src/SketchPlugin/CMakeLists.txt +++ b/src/SketchPlugin/CMakeLists.txt @@ -277,6 +277,7 @@ ADD_UNIT_TESTS( TestCreateArcByThreePoints.py TestCreateArcByTransversalLine.py TestCreateArcChangeType.py + TestCreateBSpline.py TestCreateCircleByCenterAndPassed.py TestCreateCircleByThreePoints.py TestCreateCircleChangeType.py @@ -312,12 +313,14 @@ ADD_UNIT_TESTS( TestMultiTranslation.py TestPresentation.py TestProjection.py + TestProjectionBSpline.py TestProjectionEllipse.py TestProjectionEllipticArc.py TestProjectionIntoResult.py TestProjectionUpdate.py TestRectangle.py TestRemainingDoF.py + TestRemoveBSpline.py TestRemoveEllipse.py TestRemoveEllipticArc.py TestRemoveSketch.py @@ -355,6 +358,7 @@ ADD_UNIT_TESTS( if(${SKETCHER_CHANGE_RADIUS_WHEN_MOVE}) ADD_UNIT_TESTS( TestMoveArc.py + TestMoveBSpline.py TestMoveCircle.py TestMoveEllipse.py TestMoveEllipticArc.py diff --git a/src/SketchPlugin/SketchPlugin_BSpline.cpp b/src/SketchPlugin/SketchPlugin_BSpline.cpp index e8e84177d..f4aee05a9 100644 --- a/src/SketchPlugin/SketchPlugin_BSpline.cpp +++ b/src/SketchPlugin/SketchPlugin_BSpline.cpp @@ -152,9 +152,14 @@ void SketchPlugin_BSpline::attributeChanged(const std::string& theID) { //// fillCharacteristicPoints(); //// } } -//// else if (theID == CENTER_ID() || theID == FIRST_FOCUS_ID() || -//// theID == START_POINT_ID() || theID == END_POINT_ID()) -//// fillCharacteristicPoints(); + else if (theID == POLES_ID()) { + AttributePoint2DArrayPtr aPolesArray = + std::dynamic_pointer_cast(attribute(POLES_ID())); + std::dynamic_pointer_cast( + attribute(START_ID()))->setValue(aPolesArray->pnt(0)); + std::dynamic_pointer_cast( + attribute(END_ID()))->setValue(aPolesArray->pnt(aPolesArray->size() - 1)); + } //// else if (theID == REVERSED_ID() && myParamDelta == 0.0) //// myParamDelta = 2.0 * PI; } diff --git a/src/SketchPlugin/Test/TestCreateBSpline.py b/src/SketchPlugin/Test/TestCreateBSpline.py new file mode 100644 index 000000000..413c84b44 --- /dev/null +++ b/src/SketchPlugin/Test/TestCreateBSpline.py @@ -0,0 +1,195 @@ +# 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 +""" + +import unittest +from salome.shaper import model + +from GeomAPI import * +from SketchAPI import * + +__updated__ = "2020-01-17" + +class TestBSpline(unittest.TestCase): + def setUp(self): + model.begin() + self.myDocument = model.moduleDocument() + self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY")) + self.myPoles = [GeomAPI_Pnt2d(50., 50.), GeomAPI_Pnt2d(70., 70.), GeomAPI_Pnt2d(80., 30.), GeomAPI_Pnt2d(50., 10.), GeomAPI_Pnt2d(10., -30.)] + self.myPolesCoordinates = [(50., 50.), (70., 70.), (80., 30.), (50., 10.), (10., -30.)] + self.myDegree = 3; + self.myDOF = 0 + self.myNbPoints = 0 + self.myNbLines = 0 + self.myNbSplines = 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) + + + def checkDOF(self): + self.assertEqual(model.dof(self.mySketch), self.myDOF) + + + def test_bspline_by_coordinates(self): + """ Test 1. Create B-spline curve by coordinates of its poles + """ + self.mySpline = self.mySketch.addSpline(self.myPolesCoordinates) + self.myDOF += len(self.myPolesCoordinates) * 2 + self.myNbSplines += 1 + model.do() + + assert(self.mySpline.feature()) + assert(self.mySpline.feature().error() == "") + assert(self.mySpline.degree().value() == self.myDegree) + + def test_bspline_by_poles(self): + """ Test 2. Create B-spline curve by poles + """ + self.mySpline = self.mySketch.addSpline(self.myPoles) + self.myDOF += len(self.myPoles) * 2 + self.myNbSplines += 1 + model.do() + + assert(self.mySpline.feature()) + assert(self.mySpline.feature().error() == "") + assert(self.mySpline.degree().value() == self.myDegree) + + def test_bspline_by_degree_and_poles(self): + """ Test 3. Create B-spline curve by poles and degree + """ + self.myDegree = 4 + self.mySpline = self.mySketch.addSpline(self.myDegree, self.myPoles) + self.myDOF += len(self.myPoles) * 2 + self.myNbSplines += 1 + model.do() + + assert(self.mySpline.feature()) + assert(self.mySpline.feature().error() == "") + assert(self.mySpline.degree().value() == self.myDegree) + + def test_bspline_by_poles_and_weights(self): + """ Test 4. Create B-spline curve by poles and weights + """ + self.mySpline = self.mySketch.addSpline(self.myPoles, [1, 2, 3, 2, 1]) + self.myDOF += len(self.myPoles) * 2 + self.myNbSplines += 1 + model.do() + + assert(self.mySpline.feature()) + assert(self.mySpline.feature().error() == "") + assert(self.mySpline.degree().value() == self.myDegree) + + def test_bspline_by_parametric(self): + """ Test 5. Create B-spline curve by whole set of parameters + """ + self.myDegree = 5 + self.myPolesCoordinates = [(-79.8578274581199, 75.5284518447357), + (-64.6205376770376, 62.7428476092882), + (-49.3832478959552, 49.9572433738407), + (-34.1459581148729, 37.1716391383932), + (-18.9086683337906, 24.3860349029457), + (-3.55842111132817, 11.5056481200973), + (-3.37993197286247, 11.42995541724), + (-3.1778022626919, 11.4565662984205), + (-3.02498570721059, 11.575876223351), + (8.46852511720001, 27.9903107977019), + (19.8774589601206, 44.2839569245217), + (31.2863928030413, 60.5776030513415), + (42.6953266459619, 76.8712491781612), + (54.1042604888826, 93.164895304981) + ] + self.mySpline = self.mySketch.addSpline(self.myDegree, + self.myPolesCoordinates, + [1, 1, 1, 1, 1, 1, 0.957903314642061, 0.95790331464206, 1, 1, 1, 1, 1, 1], + [-494.543457494654, 500, 507.372773368102, 1501.91623086297], + [6, 4, 4, 6]) + self.myDOF += len(self.myPolesCoordinates) * 2 + self.myNbSplines += 1 + model.do() + + assert(self.mySpline.feature()) + assert(self.mySpline.feature().error() == "") + assert(self.mySpline.degree().value() == self.myDegree) + + def test_bspline_linear(self): + """ Test 6. Create B-spline curve by 2 poles + """ + self.myDegree = 1 + self.mySpline = self.mySketch.addSpline(self.myPoles[:2]) + self.myDOF += 4 + self.myNbSplines += 1 + model.do() + + assert(self.mySpline.feature()) + assert(self.mySpline.feature().error() == "") + assert(self.mySpline.degree().value() == self.myDegree) + + def test_bspline_parabola(self): + """ Test 7. Create B-spline curve by 3 poles + """ + self.myDegree = 2 + self.mySpline = self.mySketch.addSpline(self.myPoles[:3]) + self.myDOF += 6 + self.myNbSplines += 1 + model.do() + + assert(self.mySpline.feature()) + assert(self.mySpline.feature().error() == "") + assert(self.mySpline.degree().value() == self.myDegree) + + def test_bspline_with_poles(self): + """ Test 8. Create B-spline curve and points coincident with its poles + """ + self.mySpline = self.mySketch.addSpline(self.myPoles) + self.mySpline.controlPoles(regular = [0, 2], auxiliary = [1, 3]) + self.myDOF += len(self.myPoles) * 2 + self.myNbSplines += 1 + self.myNbPoints += 4 + model.do() + + assert(self.mySpline.feature()) + assert(self.mySpline.feature().error() == "") + assert(self.mySpline.degree().value() == self.myDegree) + + def test_bspline_with_polygon(self): + """ Test 9. Create B-spline curve and its control polygon + """ + self.mySpline = self.mySketch.addSpline(self.myPoles) + self.mySpline.controlPolygon(regular = [0, 2], auxiliary = [1, 3]) + self.myDOF += len(self.myPoles) * 2 + self.myNbSplines += 1 + self.myNbLines += 4 + model.do() + + assert(self.mySpline.feature()) + assert(self.mySpline.feature().error() == "") + assert(self.mySpline.degree().value() == self.myDegree) + +if __name__ == "__main__": + test_program = unittest.main(exit=False) + assert test_program.result.wasSuccessful(), "Test failed" + assert model.checkPythonDump() diff --git a/src/SketchPlugin/Test/TestMoveBSpline.py b/src/SketchPlugin/Test/TestMoveBSpline.py new file mode 100644 index 000000000..eb71bffc8 --- /dev/null +++ b/src/SketchPlugin/Test/TestMoveBSpline.py @@ -0,0 +1,418 @@ +# 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 +# + +""" + Test movement of the B-spline curve +""" + +import unittest +import math +from GeomAPI import * +from GeomDataAPI import geomDataAPI_Point2DArray +from SketchAPI import * +from salome.shaper import model + +__updated__ = "2020-01-20" + +class TestMoveBSpline(unittest.TestCase): + def setUp(self): + model.begin() + self.myDocument = model.moduleDocument() + self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY")) + self.myPoles = [GeomAPI_Pnt2d(20., 50.), + GeomAPI_Pnt2d(70., 70.), + GeomAPI_Pnt2d(80., 30.), + GeomAPI_Pnt2d(50., 10.), + GeomAPI_Pnt2d(90., -30.)] + self.mySpline = self.mySketch.addSpline(self.myPoles) + self.myDOF = len(self.myPoles) * 2 + model.do() + self.checkDOF() + + def tearDown(self): + self.checkDOF() + model.end() + + def checkDOF(self): + self.assertEqual(model.dof(self.mySketch), self.myDOF) + + def checkPointCoordinates(self, thePoint, theCoordinates): + aCoord = [] + if issubclass(type(theCoordinates), GeomAPI_Pnt2d): + aCoord = [theCoordinates.x(), theCoordinates.y()] + else: + aCoord = theCoordinates + DIGITS = 7 - math.floor(math.log10(math.hypot(aCoord[0], aCoord[1]))) + self.assertAlmostEqual(thePoint.x(), aCoord[0], DIGITS) + self.assertAlmostEqual(thePoint.y(), aCoord[1], DIGITS) + + def checkPoles(self, theBSpline, theCoordinates): + poles = theBSpline.poles() + for index, point in zip(range(0, len(theCoordinates)), theCoordinates): + self.checkPointCoordinates(poles.pnt(index), point) + + def fixPoint(self, thePoint): + self.mySketch.setFixed(thePoint) + self.myDOF -= 2 + model.do() + self.checkDOF() + + + def test_move_free_bspline(self): + """ Test 1. Movement of a free B-spline dragging the edge + """ + oldPosition = GeomAPI_Edge(self.mySpline.defaultResult().shape()).middlePoint() + newPosition = GeomAPI_Pnt2d(120., 90.) + self.mySketch.move(self.mySpline.defaultResult(), newPosition) + model.do() + + # plane is XOY, no need to project oldPosition point + dx = newPosition.x() - oldPosition.x() + dy = newPosition.y() - oldPosition.y() + + newPoles = [] + for pole in self.myPoles: + newPoles.append(GeomAPI_Pnt2d(pole.x() + dx, pole.y() + dy)) + self.checkPoles(self.mySpline, newPoles) + + def test_move_start_point(self): + """ Test 2. Movement of start point of a free B-spline curve + """ + newPoles = self.myPoles + + newPoles[0].setX(newPoles[0].x() - 20.) + newPoles[0].setY(newPoles[0].y() + 10.) + self.mySketch.move(self.mySpline.startPoint(), newPoles[0]) + model.do() + + self.checkPoles(self.mySpline, newPoles) + + def test_move_end_point(self): + """ Test 3. Movement of end point of a free B-spline curve + """ + newPoles = self.myPoles + + newPoles[-1].setX(newPoles[-1].x() + 20.) + newPoles[-1].setY(newPoles[-1].y() + 10.) + self.mySketch.move(self.mySpline.endPoint(), newPoles[-1]) + model.do() + + self.checkPoles(self.mySpline, newPoles) + + + def test_move_bspline_with_start_point_fixed(self): + """ Test 4. Movement of a B-spline dragging the edge when start point is fixed + """ + self.fixPoint(self.mySpline.startPoint()) + model.do() + + oldPosition = GeomAPI_Edge(self.mySpline.defaultResult().shape()).middlePoint() + newPosition = GeomAPI_Pnt2d(120., 90.) + self.mySketch.move(self.mySpline.defaultResult(), newPosition) + model.do() + + # plane is XOY, no need to project oldPosition point + dx = newPosition.x() - oldPosition.x() + dy = newPosition.y() - oldPosition.y() + + newPoles = [self.myPoles[0]] + for pole in self.myPoles[1:]: + newPoles.append(GeomAPI_Pnt2d(pole.x() + dx, pole.y() + dy)) + self.checkPoles(self.mySpline, newPoles) + + def test_move_start_point_with_start_point_fixed(self): + """ Test 5. Movement of start point of a free B-spline curve has no result if the first pole is fixed + """ + self.fixPoint(self.mySpline.startPoint()) + model.do() + + self.mySketch.move(self.mySpline.startPoint(), self.myPoles[0].x() - 10., self.myPoles[0].y() + 10.) + model.do() + + self.checkPoles(self.mySpline, self.myPoles) + + def test_move_end_point_with_start_point_fixed(self): + """ Test 6. Movement of end point of a free B-spline curve when start point is fixed + """ + self.fixPoint(self.mySpline.startPoint()) + model.do() + + newPoles = self.myPoles + + newPoles[-1].setX(newPoles[-1].x() + 20.) + newPoles[-1].setY(newPoles[-1].y() + 10.) + self.mySketch.move(self.mySpline.endPoint(), newPoles[-1]) + model.do() + + self.checkPoles(self.mySpline, newPoles) + + + def test_move_bspline_with_end_point_fixed(self): + """ Test 7. Movement of a B-spline dragging the edge when end point is fixed + """ + self.fixPoint(self.mySpline.endPoint()) + model.do() + + oldPosition = GeomAPI_Edge(self.mySpline.defaultResult().shape()).middlePoint() + newPosition = GeomAPI_Pnt2d(120., 90.) + self.mySketch.move(self.mySpline.defaultResult(), newPosition) + model.do() + + # plane is XOY, no need to project oldPosition point + dx = newPosition.x() - oldPosition.x() + dy = newPosition.y() - oldPosition.y() + + newPoles = [] + for pole in self.myPoles[:-1]: + newPoles.append(GeomAPI_Pnt2d(pole.x() + dx, pole.y() + dy)) + newPoles.append(self.myPoles[-1]) + self.checkPoles(self.mySpline, newPoles) + + def test_move_start_point_with_end_point_fixed(self): + """ Test 8. Movement of start point of a free B-spline curve when end point is fixed + """ + self.fixPoint(self.mySpline.endPoint()) + model.do() + + newPoles = self.myPoles + + newPoles[0].setX(newPoles[0].x() + 20.) + newPoles[0].setY(newPoles[0].y() + 10.) + self.mySketch.move(self.mySpline.startPoint(), self.myPoles[0]) + model.do() + + self.checkPoles(self.mySpline, self.myPoles) + + def test_move_end_point_with_end_point_fixed(self): + """ Test 9. Movement of end point of a free B-spline curve has no result if the last pole is fixed + """ + self.fixPoint(self.mySpline.endPoint()) + model.do() + + self.mySketch.move(self.mySpline.endPoint(), self.myPoles[-1].x() + 10., self.myPoles[-1].y() + 10.) + model.do() + + self.checkPoles(self.mySpline, self.myPoles) + + + def test_move_fixed_bspline(self): + """ Test 10. Movement of a fully fixed B-spline + """ + self.mySketch.setFixed(self.mySpline.defaultResult()) + self.myDOF = 0 + model.do() + + newPosition = GeomAPI_Pnt2d(120., 90.) + self.mySketch.move(self.mySpline.defaultResult(), newPosition) + model.do() + + self.checkPoles(self.mySpline, self.myPoles) + + def test_move_start_point_of_fixed_bspline(self): + """ Test 11. Movement of start point of a fully fixed B-spline curve + """ + self.mySketch.setFixed(self.mySpline.defaultResult()) + self.myDOF = 0 + model.do() + + self.mySketch.move(self.mySpline.startPoint(), self.myPoles[0].x() + 10., self.myPoles[0].y() + 10.) + model.do() + + self.checkPoles(self.mySpline, self.myPoles) + + def test_move_end_point_of_fixed_bspline(self): + """ Test 12. Movement of end point of a fully fixed B-spline curve + """ + self.mySketch.setFixed(self.mySpline.defaultResult()) + self.myDOF = 0 + model.do() + + self.mySketch.move(self.mySpline.endPoint(), self.myPoles[-1].x() + 10., self.myPoles[-1].y() + 10.) + model.do() + + self.checkPoles(self.mySpline, self.myPoles) + + + def test_move_bspline_with_fixed_pole(self): + """ Test 13. Movement of a B-spline curve with fixed pole + """ + [Point_1, Point_2, Point_3, Point_4, Point_5] = self.mySpline.controlPoles(auxiliary = [0, 1, 2, 3, 4]) + model.do() + + self.fixPoint(Point_2.defaultResult()) + model.do() + + oldPosition = GeomAPI_Edge(self.mySpline.defaultResult().shape()).middlePoint() + newPosition = GeomAPI_Pnt2d(120., 90.) + self.mySketch.move(self.mySpline.defaultResult(), newPosition) + model.do() + + # plane is XOY, no need to project oldPosition point + dx = newPosition.x() - oldPosition.x() + dy = newPosition.y() - oldPosition.y() + + newPoles = [] + for pole in self.myPoles: + newPoles.append(GeomAPI_Pnt2d(pole.x() + dx, pole.y() + dy)) + newPoles[1].setX(newPoles[1].x() - dx) + newPoles[1].setY(newPoles[1].y() - dy) + self.checkPoles(self.mySpline, newPoles) + + def test_move_start_point_with_fixed_pole(self): + """ Test 14. Movement of start point of a B-spline curve with fixed pole + """ + [Point_1, Point_2, Point_3, Point_4, Point_5] = self.mySpline.controlPoles(auxiliary = [0, 1, 2, 3, 4]) + model.do() + + self.fixPoint(Point_2.defaultResult()) + model.do() + + newPoles = self.myPoles + + newPoles[0].setX(newPoles[0].x() + 20.) + newPoles[0].setY(newPoles[0].y() + 10.) + self.mySketch.move(self.mySpline.startPoint(), newPoles[0]) + model.do() + + self.checkPoles(self.mySpline, newPoles) + + def test_move_end_point_with_fixed_pole(self): + """ Test 15. Movement of end point of a B-spline curve with fixed pole + """ + [Point_1, Point_2, Point_3, Point_4, Point_5] = self.mySpline.controlPoles(auxiliary = [0, 1, 2, 3, 4]) + model.do() + + self.fixPoint(Point_2.defaultResult()) + model.do() + + newPoles = self.myPoles + + newPoles[-1].setX(newPoles[-1].x() + 20.) + newPoles[-1].setY(newPoles[-1].y() + 10.) + self.mySketch.move(self.mySpline.endPoint(), newPoles[-1]) + model.do() + + self.checkPoles(self.mySpline, newPoles) + + + def test_move_bspline_with_fixed_segment(self): + """ Test 16. Movement of a B-spline curve with fixed control segment + """ + [Line_1, Line_2, Line_3, Line_4] = self.mySpline.controlPolygon(auxiliary = [0, 1, 2, 3]) + model.do() + + self.mySketch.setFixed(Line_1.defaultResult()) + self.myDOF -= 4 + model.do() + + oldPosition = GeomAPI_Edge(self.mySpline.defaultResult().shape()).middlePoint() + newPosition = GeomAPI_Pnt2d(120., 90.) + self.mySketch.move(self.mySpline.defaultResult(), newPosition) + model.do() + + # plane is XOY, no need to project oldPosition point + dx = newPosition.x() - oldPosition.x() + dy = newPosition.y() - oldPosition.y() + + newPoles = [self.myPoles[0], self.myPoles[1]] + for pole in self.myPoles[2:]: + newPoles.append(GeomAPI_Pnt2d(pole.x() + dx, pole.y() + dy)) + self.checkPoles(self.mySpline, newPoles) + + def test_move_start_point_with_fixed_segment(self): + """ Test 17. Movement of start point of a B-spline curve with fixed control segment + """ + [Line_1, Line_2, Line_3, Line_4] = self.mySpline.controlPolygon(auxiliary = [0, 1, 2, 3]) + model.do() + + self.mySketch.setFixed(Line_1.defaultResult()) + self.myDOF -= 4 + model.do() + + self.mySketch.move(self.mySpline.startPoint(), self.myPoles[0].x() + 10., self.myPoles[0].y() - 20.) + model.do() + + self.checkPoles(self.mySpline, self.myPoles) + + def test_move_end_point_with_fixed_segment(self): + """ Test 18. Movement of end point of a B-spline curve with fixed control segment + """ + [Line_1, Line_2, Line_3, Line_4] = self.mySpline.controlPolygon(auxiliary = [0, 1, 2, 3]) + model.do() + + self.mySketch.setFixed(Line_1.defaultResult()) + self.myDOF -= 4 + model.do() + + newPoles = self.myPoles + + newPoles[-1].setX(newPoles[-1].x() + 20.) + newPoles[-1].setY(newPoles[-1].y() + 10.) + self.mySketch.move(self.mySpline.endPoint(), newPoles[-1]) + model.do() + + self.checkPoles(self.mySpline, newPoles) + + + def test_move_pole_of_free_bspline(self): + """ Test 19. Movement of a pole of a B-spline curve + """ + [Point_1, Point_2, Point_3, Point_4, Point_5] = self.mySpline.controlPoles(auxiliary = [0, 1, 2, 3, 4]) + [Line_1, Line_2, Line_3, Line_4] = self.mySpline.controlPolygon(auxiliary = [0, 1, 2, 3]) + model.do() + + newPoles = self.myPoles + + newPoles[2].setX(newPoles[2].x() + 20.) + newPoles[2].setY(newPoles[2].y() + 20.) + self.mySketch.move(SketchAPI_Point(Point_3).coordinates(), newPoles[2]) + model.do() + + self.checkPoles(self.mySpline, newPoles) + + def test_move_segment_of_free_bspline(self): + """ Test 20. Movement of a control segment of a B-spline curve + """ + [Point_1, Point_2, Point_3, Point_4, Point_5] = self.mySpline.controlPoles(auxiliary = [0, 1, 2, 3, 4]) + [Line_1, Line_2, Line_3, Line_4] = self.mySpline.controlPolygon(auxiliary = [0, 1, 2, 3]) + model.do() + + oldPosition = GeomAPI_Pnt2d(0.5 * (self.myPoles[2].x() + self.myPoles[3].x()), + 0.5 * (self.myPoles[2].y() + self.myPoles[3].y())) + newPosition = GeomAPI_Pnt2d(120., 90.) + self.mySketch.move(SketchAPI_Line(Line_3).defaultResult(), newPosition) + model.do() + + dx = newPosition.x() - oldPosition.x() + dy = newPosition.y() - oldPosition.y() + + newPoles = self.myPoles + newPoles[2].setX(newPoles[2].x() + dx) + newPoles[2].setY(newPoles[2].y() + dy) + newPoles[3].setX(newPoles[3].x() + dx) + newPoles[3].setY(newPoles[3].y() + dy) + + self.checkPoles(self.mySpline, newPoles) + + + +if __name__ == "__main__": + test_program = unittest.main(exit=False) + assert test_program.result.wasSuccessful(), "Test failed" + assert model.checkPythonDump() diff --git a/src/SketchPlugin/Test/TestPresentation.py b/src/SketchPlugin/Test/TestPresentation.py index b3400e70e..2b675b4ce 100644 --- a/src/SketchPlugin/Test/TestPresentation.py +++ b/src/SketchPlugin/Test/TestPresentation.py @@ -156,3 +156,22 @@ anEllipticArcPnt3.setValue(0, 5) anEllipticArcPnt4.setValue(-10, 0) assert(featureToPresentation(anEllipticArc).getAISObject(None) is not None) aSession.finishOperation() + +# Test presentation for MacroBSpline on low-level +aSession.startOperation() +aBSpline = aSketchFeature.addFeature("SketchMacroBSpline") +aPoles = geomDataAPI_Point2DArray(aBSpline.attribute("poles")) +aPoles.setSize(4) +aPoles.setPnt(0, 0, 0) +aPoles.setPnt(1, 10, 0) +aPoles.setPnt(2, 10, 10) +aPoles.setPnt(3, 0, 10) +aWeights = aBSpline.data().realArray("weights") +aWeights.setSize(4) +aWeights.setValue(0, 1) +aWeights.setValue(1, 2) +aWeights.setValue(2, 2) +aWeights.setValue(3, 1) +aBSpline.boolean("need_control_poly").setValue(True) +assert(featureToPresentation(aBSpline).getAISObject(None) is not None) +aSession.finishOperation() diff --git a/src/SketchPlugin/Test/TestProjectionBSpline.py b/src/SketchPlugin/Test/TestProjectionBSpline.py new file mode 100644 index 000000000..d053681db --- /dev/null +++ b/src/SketchPlugin/Test/TestProjectionBSpline.py @@ -0,0 +1,78 @@ +# 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 +# + +from salome.shaper import model + +model.begin() +partSet = model.moduleDocument() +Part_1 = model.addPart(partSet) +Part_1_doc = Part_1.document() +Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10, 180) +Sketch_1 = model.addSketch(Part_1_doc, model.selection("FACE", "Cylinder_1_1/Face_5")) +SketchCircle_1 = Sketch_1.addCircle(-0.87355746875896, 7.873567272779828, 3.095312696967586) +model.do() +ExtrusionCut_1 = model.addExtrusionCut(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2r")], model.selection(), [model.selection("SOLID", "Cylinder_1_1")]) +Rotation_1 = model.addRotation(Part_1_doc, [model.selection("SOLID", "ExtrusionCut_1_1")], model.selection("EDGE", "PartSet/OX"), 45) +Edge_1 = model.addEdge(Part_1_doc, [model.selection("EDGE", "[Rotation_1_1/MF:Rotated&Cylinder_1_1/Face_1][(Rotation_1_1/MF:Rotated&Cylinder_1_1/Face_1)(Rotation_1_1/MF:Rotated&Cylinder_1_1/Face_5)(Rotation_1_1/MF:Rotated&Cylinder_1_1/Face_4)(Rotation_1_1/MF:Rotated&Cylinder_1_1/Face_3)2]")], False) + +Sketch_2 = model.addSketch(Part_1_doc, model.standardPlane("XOY")) +SketchProjection_1 = Sketch_2.addProjection(model.selection("EDGE", "Edge_1_1"), True) +SketchBSpline_1 = SketchProjection_1.createdFeature() +model.do() + +Sketch_3 = model.addSketch(Part_1_doc, model.standardPlane("XOZ")) +SketchProjection_2 = Sketch_3.addProjection(model.selection("EDGE", "Edge_1_1"), True) +SketchBSpline_2 = SketchProjection_2.createdFeature() +model.do() + +Sketch_4 = model.addSketch(Part_1_doc, model.standardPlane("YOZ")) +SketchProjection_3 = Sketch_4.addProjection(model.selection("EDGE", "Edge_1_1"), True) +SketchBSpline_3 = SketchProjection_3.createdFeature() +model.do() + +model.end() + +from GeomAPI import * +import math + +TOLERANCE = 1.e-7 + +def checkProjection(theBSpline3D, theBSpline2D, theFlags): + assert(theBSpline2D.isEdge() and theBSpline2D.edge().isBSpline()) + poles2D = GeomAPI_BSpline(GeomAPI_Curve(theBSpline2D)).poles() + poles3D = theBSpline3D.poles() + assert(poles2D.size() == poles3D.size()) + for p2d, p3d in zip(poles2D, poles3D): + assert(math.fabs((p2d.x() - p3d.x()) * theFlags.x()) < TOLERANCE and + math.fabs((p2d.y() - p3d.y()) * theFlags.y()) < TOLERANCE and + math.fabs((p2d.z() - p3d.z()) * theFlags.z()) < TOLERANCE) + + +bspline0 = GeomAPI_BSpline(GeomAPI_Curve(Edge_1.results()[-1].resultSubShapePair()[0].shape())) + +bsplineShape1 = SketchBSpline_1.results()[-1].resultSubShapePair()[0].shape() +checkProjection(bspline0, bsplineShape1, GeomAPI_Pnt(1, 1, 0)) + +bsplineShape2 = SketchBSpline_2.results()[-1].resultSubShapePair()[0].shape() +checkProjection(bspline0, bsplineShape2, GeomAPI_Pnt(1, 0, 1)) + +bsplineShape3 = SketchBSpline_3.results()[-1].resultSubShapePair()[0].shape() +checkProjection(bspline0, bsplineShape3, GeomAPI_Pnt(0, 1, 1)) + +assert(model.checkPythonDump()) diff --git a/src/SketchPlugin/Test/TestRemoveBSpline.py b/src/SketchPlugin/Test/TestRemoveBSpline.py new file mode 100644 index 000000000..d9f4461c1 --- /dev/null +++ b/src/SketchPlugin/Test/TestRemoveBSpline.py @@ -0,0 +1,108 @@ +# 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 +# + +""" + Test removing B-spline curve and its construstion elements +""" + +from salome.shaper import model +from ModelAPI import * + +def assertNbSubs(theSketch, theNbPoints, theNbLines, theNbEllipses, theNbInternalConstraints): + model.testNbSubFeatures(theSketch, "SketchPoint", theNbPoints) + model.testNbSubFeatures(theSketch, "SketchLine", theNbLines) + model.testNbSubFeatures(theSketch, "SketchBSpline", theNbEllipses) + model.testNbSubFeatures(theSketch, "SketchConstraintCoincidenceInternal", theNbInternalConstraints) + +model.begin() +partSet = model.moduleDocument() +Part_1 = model.addPart(partSet) +Part_1_doc = Part_1.document() +Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY")) +SketchBSpline_1_poles = [(-30, -10), (-15, 20), (0, -10), (15, 20), (30, -10)] +SketchBSpline_1 = Sketch_1.addSpline(SketchBSpline_1_poles) +controlPoles = SketchBSpline_1.controlPoles(auxiliary = [0, 1, 2, 3, 4]) +controlLines = SketchBSpline_1.controlPolygon(auxiliary = [0, 1, 2, 3]) +model.do() +model.end() + +DEFAULT_DOF = len(SketchBSpline_1_poles) * 2 +DEFAULT_POINTS = len(SketchBSpline_1_poles) +DEFAULT_LINES = len(SketchBSpline_1_poles) - 1 +DEFAULT_BSPLINES = 1 +DEAFULT_INTERNALS = len(controlPoles) + len(controlLines) * 2 + +assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES, DEFAULT_BSPLINES, DEAFULT_INTERNALS) +assert(model.dof(Sketch_1) == DEFAULT_DOF) + +# Test 1. Remove auxiliary points one by one. +for pnt in controlPoles: + model.begin() + removeFeaturesAndReferences(FeatureSet([pnt.feature()])) + model.end() + + assertNbSubs(Sketch_1, DEFAULT_POINTS - 1, DEFAULT_LINES, DEFAULT_BSPLINES, DEAFULT_INTERNALS - 1) + assert(model.dof(Sketch_1) == DEFAULT_DOF) + model.undo() + assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES, DEFAULT_BSPLINES, DEAFULT_INTERNALS) + assert(model.dof(Sketch_1) == DEFAULT_DOF) + +# Test 2. Remove auxiliary lines one by one. +for ln in controlLines: + model.begin() + removeFeaturesAndReferences(FeatureSet([ln.feature()])) + model.end() + + assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES - 1, DEFAULT_BSPLINES, DEAFULT_INTERNALS - 2) + assert(model.dof(Sketch_1) == DEFAULT_DOF) + model.undo() + assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES, DEFAULT_BSPLINES, DEAFULT_INTERNALS) + assert(model.dof(Sketch_1) == DEFAULT_DOF) + +# Test 3. Remove the B-spline curve. +model.begin() +removeFeaturesAndReferences(FeatureSet([SketchBSpline_1.feature()])) +model.end() + +assertNbSubs(Sketch_1, 0, 0, 0, 0) +assert(model.dof(Sketch_1) == 0) +model.undo() +assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES, DEFAULT_BSPLINES, DEAFULT_INTERNALS) +assert(model.dof(Sketch_1) == DEFAULT_DOF) + +# Test 4. Remove some construction elements, make non-auxiliary a couple of the rest and check the dumping. +model.begin() +partSet = model.moduleDocument() +Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("XOY")) +SketchBSpline_2_poles = [(-30, -10), (-15, -40), (0, -10), (15, -40), (30, -10)] +SketchBSpline_2 = Sketch_2.addSpline(SketchBSpline_2_poles) +controlPoles2 = SketchBSpline_2.controlPoles(auxiliary = [0, 1, 2, 3, 4]) +controlLines2 = SketchBSpline_2.controlPolygon(auxiliary = [0, 1, 2, 3]) +model.do() +model.end() + +model.begin() +controlPoles2[1].setAuxiliary(False) +controlLines2[2].setAuxiliary(False) +removeFeaturesAndReferences(FeatureSet([controlPoles2[2].feature(), controlLines2[0].feature()])) +model.end() + +assertNbSubs(Sketch_2, DEFAULT_POINTS - 1, DEFAULT_LINES - 1, DEFAULT_BSPLINES, DEAFULT_INTERNALS - 3) + +assert(model.checkPythonDump()) -- 2.39.2