From a4461306d16531c21f019477c95101e370e551de Mon Sep 17 00:00:00 2001 From: azv Date: Fri, 17 Jan 2020 11:31:19 +0300 Subject: [PATCH] Issue #17347: B-Splines in Sketcher Python API for B-spline curves --- src/ModelHighAPI/ModelHighAPI.i | 81 ++- src/ModelHighAPI/ModelHighAPI_Double.cpp | 6 + src/ModelHighAPI/ModelHighAPI_Double.h | 3 + src/ModelHighAPI/ModelHighAPI_Dumper.cpp | 54 ++ src/ModelHighAPI/ModelHighAPI_Dumper.h | 8 + src/ModelHighAPI/ModelHighAPI_Tools.cpp | 26 +- src/ModelHighAPI/ModelHighAPI_Tools.h | 10 + src/SketchAPI/CMakeLists.txt | 2 + src/SketchAPI/SketchAPI.i | 75 +++ src/SketchAPI/SketchAPI_BSpline.cpp | 509 ++++++++++++++++++ src/SketchAPI/SketchAPI_BSpline.h | 158 ++++++ src/SketchAPI/SketchAPI_Projection.cpp | 4 + src/SketchAPI/SketchAPI_Sketch.cpp | 35 ++ src/SketchAPI/SketchAPI_Sketch.h | 21 + src/SketchAPI/SketchAPI_SketchEntity.cpp | 4 + src/SketchAPI/SketchAPI_swig.h | 1 + .../SketchPlugin_MacroBSpline.cpp | 4 - .../PlaneGCSSolver_FeatureBuilder.cpp | 10 +- .../PlaneGCSSolver/PlaneGCSSolver_Storage.cpp | 42 ++ 19 files changed, 1044 insertions(+), 9 deletions(-) create mode 100644 src/SketchAPI/SketchAPI_BSpline.cpp create mode 100644 src/SketchAPI/SketchAPI_BSpline.h diff --git a/src/ModelHighAPI/ModelHighAPI.i b/src/ModelHighAPI/ModelHighAPI.i index 72971cc01..442e1cd2a 100644 --- a/src/ModelHighAPI/ModelHighAPI.i +++ b/src/ModelHighAPI/ModelHighAPI.i @@ -362,8 +362,47 @@ } } + +%typemap(in) const std::list & (std::list temp) { + int newmem = 0; + if (PySequence_Check($input)) { + for (Py_ssize_t i = 0; i < PySequence_Size($input); ++i) { + PyObject * item = PySequence_GetItem($input, i); + if (PyLong_Check(item)) { + temp.push_back((int)PyLong_AsLong(item)); + } else { + PyErr_SetString(PyExc_TypeError, "argument must integet value."); + return NULL; + } + Py_DECREF(item); + } + $1 = &temp; + } else { + PyErr_SetString(PyExc_ValueError, "argument must be a tuple of integer values."); + return NULL; + } +} + +%typecheck(SWIG_TYPECHECK_POINTER) std::list, const std::list& { + int newmem = 0; + if (PySequence_Check($input)) { + for (Py_ssize_t i = 0; i < PySequence_Size($input); ++i) { + PyObject * item = PySequence_GetItem($input, i); + if (PyLong_Check(item)) { + $1 = 1; + } else { + $1 = 0; + break; + } + Py_DECREF(item); + } + } else { + $1 = 0; + } +} + + %typemap(in) const std::list & (std::list temp) { - double * temp_attribute; int newmem = 0; if (PyTuple_Check($input)) { for (Py_ssize_t i = 0; i < PyTuple_Size($input); ++i) { @@ -384,8 +423,6 @@ } %typecheck(SWIG_TYPECHECK_POINTER) std::list, const std::list& { - double * temp_object; - std::shared_ptr * temp_interface; int newmem = 0; if (PyTuple_Check($input)) { for (Py_ssize_t i = 0; i < PyTuple_Size($input); ++i) { @@ -403,6 +440,44 @@ } } + +%typemap(in) const std::list & (std::list temp) { + ModelHighAPI_Double * temp_double; + if (PySequence_Check($input)) { + for (Py_ssize_t i = 0; i < PySequence_Size($input); ++i) { + PyObject * item = PySequence_GetItem($input, i); + if (PyFloat_Check(item) || PyLong_Check(item)) { + temp.push_back(ModelHighAPI_Double(PyFloat_AsDouble(item))); + } else if (PyUnicode_Check(item)) { + temp.push_back(ModelHighAPI_Double(PyUnicode_AsUTF8(item))); + } else if ((SWIG_ConvertPtr(item, (void **)&temp_double, $1_descriptor, SWIG_POINTER_EXCEPTION)) == 0) { + temp.push_back(*temp_double); + } else { + PyErr_SetString(PyExc_ValueError, "argument must be a list of ModelHighAPI_Double, float, int or string."); + return NULL; + } + Py_DECREF(item); + } + $1 = &temp; + } else { + PyErr_SetString(PyExc_ValueError, "argument must be a list of ModelHighAPI_Double, float, int or string."); + return NULL; + } +} + +%typecheck(SWIG_TYPECHECK_POINTER) std::list, const std::list & { + if (PySequence_Check($input)) { + for (Py_ssize_t i = 0; i < PySequence_Size($input) && $1; ++i) { + PyObject * item = PySequence_GetItem($input, i); + $1 = ((PyFloat_Check(item) || PyLong_Check(item) || PyUnicode_Check(item)) && !PyBool_Check(item)) ? 1 : 0; + Py_DECREF(item); + } + } else { + $1 = 0; + } +} + + // all supported interfaces %include "ModelHighAPI_Double.h" %include "ModelHighAPI_Dumper.h" diff --git a/src/ModelHighAPI/ModelHighAPI_Double.cpp b/src/ModelHighAPI/ModelHighAPI_Double.cpp index 35370c819..33c52647d 100644 --- a/src/ModelHighAPI/ModelHighAPI_Double.cpp +++ b/src/ModelHighAPI/ModelHighAPI_Double.cpp @@ -46,6 +46,12 @@ ModelHighAPI_Double::~ModelHighAPI_Double() { } +double ModelHighAPI_Double::value() const +{ + // needed for array of double, which supports no text + return myDouble; +} + //-------------------------------------------------------------------------------------- void ModelHighAPI_Double::fillAttribute( const std::shared_ptr & theAttribute) const diff --git a/src/ModelHighAPI/ModelHighAPI_Double.h b/src/ModelHighAPI/ModelHighAPI_Double.h index 6861a7c0a..9fe5df536 100644 --- a/src/ModelHighAPI/ModelHighAPI_Double.h +++ b/src/ModelHighAPI/ModelHighAPI_Double.h @@ -60,6 +60,9 @@ public: const ModelHighAPI_Double & theY, const ModelHighAPI_Double & theZ) const; + /// Value of the attribute + MODELHIGHAPI_EXPORT double value() const; + private: enum VariantType { VT_DOUBLE, VT_STRING } myVariantType; double myDouble; diff --git a/src/ModelHighAPI/ModelHighAPI_Dumper.cpp b/src/ModelHighAPI/ModelHighAPI_Dumper.cpp index 9df987e61..677e31be7 100644 --- a/src/ModelHighAPI/ModelHighAPI_Dumper.cpp +++ b/src/ModelHighAPI/ModelHighAPI_Dumper.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -30,9 +31,11 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -1082,6 +1085,43 @@ ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<( return *this; } +ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<( + const std::shared_ptr& thePointArray) +{ + static const int aThreshold = 4; + static bool aDumpAsIs = false; + static std::string aSeparator = ""; + // if number of elements in the list if greater than a threshold, + // dump it in a separate line with specific name + int aSize = thePointArray->size(); + if (aDumpAsIs || aSize <= aThreshold) { + *myDumpStorage << "["; + GeomPnt2dPtr aPoint = thePointArray->pnt(0); + *myDumpStorage << "(" << aPoint->x() << ", " << aPoint->y() << ")"; + for (int anIndex = 1; anIndex < aSize; ++anIndex) { + aPoint = thePointArray->pnt(anIndex); + *myDumpStorage << "," << aSeparator << " (" << aPoint->x() << ", " << aPoint->y() << ")"; + } + *myDumpStorage << aSeparator << "]"; + } + else { + // name of list + FeaturePtr anOwner = ModelAPI_Feature::feature(thePointArray->owner()); + std::string aListName = name(anOwner) + "_" + thePointArray->id(); + // reserve dumped buffer and store list "as is" + myDumpStorage->reserveBuffer(); + aDumpAsIs = true; + aSeparator = std::string("\n") + std::string(aListName.size() + 3, ' '); + *this << aListName << " = " << thePointArray << "\n"; + aDumpAsIs = false; + aSeparator = ""; + // append reserved data to the end of the current buffer + myDumpStorage->restoreReservedBuffer(); + *myDumpStorage << aListName; + } + return *this; +} + ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<( const std::shared_ptr& theAttrBool) { @@ -1111,6 +1151,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& theAttrStr) { diff --git a/src/ModelHighAPI/ModelHighAPI_Dumper.h b/src/ModelHighAPI/ModelHighAPI_Dumper.h index 2bbc29435..f9114176d 100644 --- a/src/ModelHighAPI/ModelHighAPI_Dumper.h +++ b/src/ModelHighAPI/ModelHighAPI_Dumper.h @@ -36,10 +36,12 @@ class GeomAPI_Dir; class GeomDataAPI_Dir; class GeomDataAPI_Point; class GeomDataAPI_Point2D; +class GeomDataAPI_Point2DArray; class ModelAPI_Attribute; class ModelAPI_AttributeBoolean; class ModelAPI_AttributeDouble; +class ModelAPI_AttributeDoubleArray; class ModelAPI_AttributeInteger; class ModelAPI_AttributeRefAttr; class ModelAPI_AttributeRefAttrList; @@ -262,6 +264,9 @@ public: /// "X, Y" MODELHIGHAPI_EXPORT ModelHighAPI_Dumper& operator<<(const std::shared_ptr& thePoint); + /// Dump GeomDataAPI_Point2DArray as a list of 2D points + MODELHIGHAPI_EXPORT + ModelHighAPI_Dumper& operator<<(const std::shared_ptr& thePointArray); /// Dump AttributeBoolean MODELHIGHAPI_EXPORT @@ -272,6 +277,9 @@ public: /// Dump AttributeDouble MODELHIGHAPI_EXPORT ModelHighAPI_Dumper& operator<<(const std::shared_ptr& theAttrReal); + /// Dump AttributeDoubleArray + MODELHIGHAPI_EXPORT + ModelHighAPI_Dumper& operator<<(const std::shared_ptr& theArray); /// Dump AttributeString MODELHIGHAPI_EXPORT ModelHighAPI_Dumper& operator<<(const std::shared_ptr& theAttrStr); diff --git a/src/ModelHighAPI/ModelHighAPI_Tools.cpp b/src/ModelHighAPI/ModelHighAPI_Tools.cpp index 8f1938720..e2b0e3cbd 100644 --- a/src/ModelHighAPI/ModelHighAPI_Tools.cpp +++ b/src/ModelHighAPI/ModelHighAPI_Tools.cpp @@ -27,10 +27,12 @@ #include #include #include +#include //-------------------------------------------------------------------------------------- #include #include #include +#include #include #include #include @@ -239,6 +241,29 @@ void fillAttribute(const std::list & theValue, theAttribute->setValue(anIndex, it->intValue()); // use only values, no text support in array } +//-------------------------------------------------------------------------------------- +void fillAttribute(const std::list & theValue, + const std::shared_ptr & theAttribute) +{ + theAttribute->setSize(int(theValue.size())); + + int anIndex = 0; + for (auto it = theValue.begin(); it != theValue.end(); ++it, ++anIndex) + theAttribute->setValue(anIndex, it->value()); // use only values, no text support in array +} + +//-------------------------------------------------------------------------------------- +void fillAttribute(const std::list > & theValue, + const std::shared_ptr & theAttribute) +{ + theAttribute->setSize(int(theValue.size())); + + int anIndex = 0; + for (auto it = theValue.begin(); it != theValue.end(); ++it, ++anIndex) + theAttribute->setPnt(anIndex, *it); +} + +//-------------------------------------------------------------------------------------- void fillAttribute(const ModelHighAPI_Double & theX, const ModelHighAPI_Double & theY, const ModelHighAPI_Double & theZ, @@ -247,7 +272,6 @@ void fillAttribute(const ModelHighAPI_Double & theX, theX.fillAttribute(theAttribute, theX, theY, theZ); } - //================================================================================================== GeomAPI_Shape::ShapeType shapeTypeByStr(std::string theShapeTypeStr) { diff --git a/src/ModelHighAPI/ModelHighAPI_Tools.h b/src/ModelHighAPI/ModelHighAPI_Tools.h index d0fc586ca..e46596c3e 100644 --- a/src/ModelHighAPI/ModelHighAPI_Tools.h +++ b/src/ModelHighAPI/ModelHighAPI_Tools.h @@ -37,9 +37,11 @@ class GeomAPI_Pnt2d; class GeomDataAPI_Dir; class GeomDataAPI_Point; class GeomDataAPI_Point2D; +class GeomDataAPI_Point2DArray; //-------------------------------------------------------------------------------------- class ModelAPI_AttributeBoolean; class ModelAPI_AttributeDouble; +class ModelAPI_AttributeDoubleArray; class ModelAPI_AttributeIntArray; class ModelAPI_AttributeInteger; class ModelAPI_AttributeRefAttr; @@ -146,6 +148,14 @@ MODELHIGHAPI_EXPORT void fillAttribute(const std::list & theValue, const std::shared_ptr & theAttribute); +MODELHIGHAPI_EXPORT +void fillAttribute(const std::list & theValue, + const std::shared_ptr & theAttribute); + +MODELHIGHAPI_EXPORT +void fillAttribute(const std::list > & theValue, + const std::shared_ptr & theAttribute); + MODELHIGHAPI_EXPORT void fillAttribute(const ModelHighAPI_Double & theX, const ModelHighAPI_Double & theY, diff --git a/src/SketchAPI/CMakeLists.txt b/src/SketchAPI/CMakeLists.txt index 9d2b423d8..c81d857be 100644 --- a/src/SketchAPI/CMakeLists.txt +++ b/src/SketchAPI/CMakeLists.txt @@ -22,6 +22,7 @@ INCLUDE(Common) SET(PROJECT_HEADERS SketchAPI.h SketchAPI_Arc.h + SketchAPI_BSpline.h SketchAPI_Circle.h SketchAPI_Constraint.h SketchAPI_ConstraintAngle.h @@ -45,6 +46,7 @@ SET(PROJECT_HEADERS SET(PROJECT_SOURCES SketchAPI_Arc.cpp + SketchAPI_BSpline.cpp SketchAPI_Circle.cpp SketchAPI_Constraint.cpp SketchAPI_ConstraintAngle.cpp diff --git a/src/SketchAPI/SketchAPI.i b/src/SketchAPI/SketchAPI.i index 07f596c21..e2a43e68d 100644 --- a/src/SketchAPI/SketchAPI.i +++ b/src/SketchAPI/SketchAPI.i @@ -45,6 +45,8 @@ %include "std_shared_ptr.i" // function with named parameters +%feature("kwargs") SketchAPI_BSpline::controlPoles; +%feature("kwargs") SketchAPI_BSpline::controlPolygon; %feature("kwargs") SketchAPI_Ellipse::construction; %feature("kwargs") SketchAPI_EllipticArc::construction; %feature("kwargs") SketchAPI_Sketch::setAngle; @@ -58,6 +60,7 @@ %shared_ptr(SketchAPI_MacroEllipse) %shared_ptr(SketchAPI_EllipticArc) %shared_ptr(SketchAPI_MacroEllipticArc) +%shared_ptr(SketchAPI_BSpline) %shared_ptr(SketchAPI_Constraint) %shared_ptr(SketchAPI_ConstraintAngle) %shared_ptr(SketchAPI_IntersectionPoint) @@ -75,6 +78,7 @@ %template(InterfaceList) std::list >; %template(EntityList) std::list >; %template(SketchPointList) std::list >; +%template(GeomPnt2dList) std::list >; // std::pair -> [] %template(PointRefAttrPair) std::pair, ModelHighAPI_RefAttr>; @@ -336,6 +340,76 @@ // fix compilarion error: 'res*' was not declared in this scope %typemap(freearg) const std::pair, ModelHighAPI_RefAttr> & {} + +%typemap(in) const std::list > & (std::list > temp) { + std::shared_ptr * temp_point = 0; + int newmem = 0; + if (PySequence_Check($input)) { + for (Py_ssize_t i = 0; i < PySequence_Size($input); ++i) { + PyObject * item = PySequence_GetItem($input, i); + if (PyTuple_Check(item)) { + if (PyTuple_Size(item) == 2) { + double x = (double)PyFloat_AsDouble(PySequence_GetItem(item, 0)); + double y = (double)PyFloat_AsDouble(PySequence_GetItem(item, 1)); + temp.push_back(std::shared_ptr(new GeomAPI_Pnt2d(x, y))); + } else { + PyErr_SetString(PyExc_TypeError, "argument must a list of 2D points."); + return NULL; + } + } else + if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_point, $descriptor(std::shared_ptr *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) { + temp.push_back(*temp_point); + if (temp_point && (newmem & SWIG_CAST_NEW_MEMORY)) { + delete temp_point; + } + } else { + PyErr_SetString(PyExc_TypeError, "argument must a list of 2D points."); + return NULL; + } + Py_DECREF(item); + } + $1 = &temp; + } else { + PyErr_SetString(PyExc_ValueError, "argument must be a tuple of lists."); + return NULL; + } +} + +%typecheck(SWIG_TYPECHECK_POINTER) std::list >, const std::list >& { + std::shared_ptr * temp_point = 0; + int newmem = 0; + if (PySequence_Check($input)) { + for (Py_ssize_t i = 0; i < PySequence_Size($input) && $1; ++i) { + PyObject * item = PySequence_GetItem($input, i); + if (PyTuple_Check(item)) { + if (PyTuple_Size(item) == 2) { + if (PyNumber_Check(PySequence_GetItem(item, 0)) && PyNumber_Check(PySequence_GetItem(item, 1))) { + $1 = 1; + } else { + $1 = 0; + } + } else { + $1 = 0; + } + } else + if ((SWIG_ConvertPtrAndOwn(item, (void **)&temp_point, $descriptor(std::shared_ptr *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) { + if (temp_point) { + $1 = 1; + } else { + $1 = 0; + } + } + Py_DECREF(item); + } + } else { + $1 = 0; + } +} + +// fix compilarion error: 'res*' was not declared in this scope +%typemap(freearg) const std::list > & {} + + // all supported interfaces (the order is very important according dependencies: base class first) %include "SketchAPI_SketchEntity.h" %include "SketchAPI_Point.h" @@ -349,6 +423,7 @@ %include "SketchAPI_MacroEllipse.h" %include "SketchAPI_EllipticArc.h" %include "SketchAPI_MacroEllipticArc.h" +%include "SketchAPI_BSpline.h" %include "SketchAPI_Projection.h" %include "SketchAPI_Mirror.h" %include "SketchAPI_Translation.h" diff --git a/src/SketchAPI/SketchAPI_BSpline.cpp b/src/SketchAPI/SketchAPI_BSpline.cpp new file mode 100644 index 000000000..9023d703b --- /dev/null +++ b/src/SketchAPI/SketchAPI_BSpline.cpp @@ -0,0 +1,509 @@ +// Copyright (C) 2019-2020 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "SketchAPI_BSpline.h" + +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + + +SketchAPI_BSpline::SketchAPI_BSpline(const std::shared_ptr & theFeature) + : SketchAPI_SketchEntity(theFeature) +{ + initialize(); +} + +SketchAPI_BSpline::SketchAPI_BSpline(const std::shared_ptr& theFeature, + const std::list& thePoles, + const std::list& theWeights) + : SketchAPI_SketchEntity(theFeature) +{ + if (initialize()) { + setByDegreePolesAndWeights(ModelHighAPI_Integer(-1), thePoles, theWeights); + } +} + +SketchAPI_BSpline::SketchAPI_BSpline(const std::shared_ptr& theFeature, + const int theDegree, + const std::list& thePoles, + const std::list& theWeights, + const std::list& theKnots, + const std::list& theMults) + : SketchAPI_SketchEntity(theFeature) +{ + if (initialize()) { + if (theKnots.empty() || theMults.empty()) + setByDegreePolesAndWeights(theDegree, thePoles, theWeights); + else + setByParameters(theDegree, thePoles, theWeights, theKnots, theMults); + } +} + +SketchAPI_BSpline::SketchAPI_BSpline(const std::shared_ptr& theFeature, + const ModelHighAPI_Selection& theExternal) + : SketchAPI_SketchEntity(theFeature) +{ + if (initialize()) { + setByExternal(theExternal); + } +} + +SketchAPI_BSpline::SketchAPI_BSpline(const std::shared_ptr& theFeature, + const std::string& theExternalName) + : SketchAPI_SketchEntity(theFeature) +{ + if (initialize()) { + setByExternalName(theExternalName); + } +} + +SketchAPI_BSpline::~SketchAPI_BSpline() +{ +} + +void SketchAPI_BSpline::setByDegreePolesAndWeights(const ModelHighAPI_Integer& theDegree, + const std::list& thePoles, + const std::list& theWeights) +{ + std::list aWeights; + if (theWeights.size() <= 1) { + // prepare array of equal weights + aWeights.assign(thePoles.size(), + theWeights.empty() ? ModelHighAPI_Double(1.0) : theWeights.front()); + } + else + aWeights = theWeights; + + ModelHighAPI_Integer aDegree = theDegree; + std::list aKnots; + std::list aMults; + getDefaultParameters(thePoles, aWeights, aDegree, aKnots, aMults); + + setByParameters(aDegree, thePoles, aWeights, aKnots, aMults); +} + +void SketchAPI_BSpline::setByParameters(const ModelHighAPI_Integer& theDegree, + const std::list& thePoles, + const std::list& theWeights, + const std::list& theKnots, + const std::list& theMults) +{ + fillAttribute(theDegree, degree()); + + fillAttribute(thePoles, poles()); + if (theWeights.size() <= 1) { + // prepare array of equal weights + std::list aWeights(thePoles.size(), + theWeights.empty() ? ModelHighAPI_Double(1.0) : theWeights.front()); + fillAttribute(aWeights, weights()); + } + else + fillAttribute(theWeights, weights()); + + fillAttribute(theKnots, knots()); + fillAttribute(theMults, multiplicities()); + + setStartAndEndPoints(); + execute(); +} + +void SketchAPI_BSpline::setStartAndEndPoints() +{ + fillAttribute(poles()->pnt(0), startPoint()); + fillAttribute(poles()->pnt(poles()->size() - 1), endPoint()); +} + +void SketchAPI_BSpline::setByExternal(const ModelHighAPI_Selection & theExternal) +{ + fillAttribute(theExternal, external()); + execute(); +} + +void SketchAPI_BSpline::setByExternalName(const std::string & theExternalName) +{ + fillAttribute(ModelHighAPI_Selection("EDGE", theExternalName), external()); + execute(); +} + +static CompositeFeaturePtr sketchForFeature(FeaturePtr theFeature) +{ + const std::set& aRefs = theFeature->data()->refsToMe(); + for (std::set::const_iterator anIt = aRefs.begin(); anIt != aRefs.end(); ++anIt) + if ((*anIt)->id() == SketchPlugin_Sketch::FEATURES_ID()) + return std::dynamic_pointer_cast((*anIt)->owner()); + return CompositeFeaturePtr(); +} + +static void createInternalConstraint(const CompositeFeaturePtr& theSketch, + const AttributePoint2DPtr& thePoint, + const AttributePoint2DArrayPtr& thePoles, + const int thePoleIndex) +{ + FeaturePtr aConstraint = theSketch->addFeature(SketchPlugin_ConstraintCoincidenceInternal::ID()); + aConstraint->refattr(SketchPlugin_Constraint::ENTITY_A())->setAttr(thePoint); + aConstraint->refattr(SketchPlugin_Constraint::ENTITY_B())->setAttr(thePoles); + aConstraint->integer(SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_B()) + ->setValue(thePoleIndex); + aConstraint->execute(); +} + +static void createPole(const CompositeFeaturePtr& theSketch, + const FeaturePtr& theBSpline, + const AttributePoint2DArrayPtr& thePoles, + const int thePoleIndex, + const bool theAuxiliary, + std::list& theEntities) +{ + GeomPnt2dPtr aPole = thePoles->pnt(thePoleIndex); + + FeaturePtr aPointFeature = theSketch->addFeature(SketchPlugin_Point::ID()); + AttributePoint2DPtr aCoord = std::dynamic_pointer_cast( + aPointFeature->attribute(SketchPlugin_Point::COORD_ID())); + aCoord->setValue(aPole); + aPointFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(theBSpline); + aPointFeature->execute(); + + std::ostringstream aName; + aName << theBSpline->name() << "_" << thePoles->id() << "_" << thePoleIndex; + aPointFeature->data()->setName(aName.str()); + aPointFeature->lastResult()->data()->setName(aName.str()); + + aPointFeature->boolean(SketchPlugin_Point::AUXILIARY_ID())->setValue(theAuxiliary); + + createInternalConstraint(theSketch, aCoord, thePoles, thePoleIndex); + + theEntities.push_back(aPointFeature); +} + +static void createSegment(const CompositeFeaturePtr& theSketch, + const FeaturePtr& theBSpline, + const AttributePoint2DArrayPtr& thePoles, + const int theStartPoleIndex, + const bool theAuxiliary, + std::list& theEntities) +{ + GeomPnt2dPtr aStartPoint = thePoles->pnt(theStartPoleIndex); + GeomPnt2dPtr aEndPoint = thePoles->pnt(theStartPoleIndex + 1); + + FeaturePtr aLineFeature = theSketch->addFeature(SketchPlugin_Line::ID()); + AttributePoint2DPtr aLineStart = std::dynamic_pointer_cast( + aLineFeature->attribute(SketchPlugin_Line::START_ID())); + aLineStart->setValue(aStartPoint); + AttributePoint2DPtr aLineEnd = std::dynamic_pointer_cast( + aLineFeature->attribute(SketchPlugin_Line::END_ID())); + aLineEnd->setValue(aEndPoint); + aLineFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(theBSpline); + aLineFeature->execute(); + + std::ostringstream aName; + aName << theBSpline->name() << "_segment_" << theStartPoleIndex << "_" << theStartPoleIndex + 1; + aLineFeature->data()->setName(aName.str()); + aLineFeature->lastResult()->data()->setName(aName.str()); + + aLineFeature->boolean(SketchPlugin_Line::AUXILIARY_ID())->setValue(theAuxiliary); + + createInternalConstraint(theSketch, aLineStart, thePoles, theStartPoleIndex); + createInternalConstraint(theSketch, aLineEnd, thePoles, theStartPoleIndex + 1); + + theEntities.push_back(aLineFeature); +} + +static void toMapOfAuxIndices(const std::list& theRegular, + const std::list& theAuxiliary, + std::map& theIndices) +{ + for (auto it = theRegular.begin(); it != theRegular.end(); ++it) + theIndices[*it] = false; + for (auto it = theAuxiliary.begin(); it != theAuxiliary.end(); ++it) + theIndices[*it] = true; +} + +std::list > SketchAPI_BSpline::controlPoles( + const std::list& regular, + const std::list& auxiliary) const +{ + std::map anAux; + toMapOfAuxIndices(regular, auxiliary, anAux); + + std::list anEntities; + + FeaturePtr aBSpline = feature(); + CompositeFeaturePtr aSketch = sketchForFeature(aBSpline); + AttributePoint2DArrayPtr aPoles = poles(); + + for (auto it = anAux.begin(); it != anAux.end(); ++it) + createPole(aSketch, aBSpline, aPoles, it->first, it->second, anEntities); + + return SketchAPI_SketchEntity::wrap(anEntities); +} + +std::list > SketchAPI_BSpline::controlPolygon( + const std::list& regular, + const std::list& auxiliary) const +{ + std::map anAux; + toMapOfAuxIndices(regular, auxiliary, anAux); + + std::list anEntities; + + FeaturePtr aBSpline = feature(); + CompositeFeaturePtr aSketch = sketchForFeature(aBSpline); + AttributePoint2DArrayPtr aPoles = poles(); + + for (auto it = anAux.begin(); it != anAux.end(); ++it) + createSegment(aSketch, aBSpline, aPoles, it->first, it->second, anEntities); + + return SketchAPI_SketchEntity::wrap(anEntities); +} + + +void SketchAPI_BSpline::getDefaultParameters( + const std::list >& thePoles, + const std::list& theWeights, + ModelHighAPI_Integer& theDegree, + std::list& theKnots, + std::list& theMults) const +{ + std::shared_ptr aBSplineCurve; + try { + std::list aWeights; + for (std::list::const_iterator it = theWeights.begin(); + it != theWeights.end(); ++it) + aWeights.push_back(it->value()); + + if (theDegree.intValue() < 0) + aBSplineCurve.reset(new GeomAPI_BSpline2d(thePoles, aWeights)); + else + aBSplineCurve.reset(new GeomAPI_BSpline2d(theDegree.intValue(), thePoles, aWeights)); + } + catch (...) { + // cannot build a B-spline curve + return; + } + + theDegree = aBSplineCurve->degree(); + std::list aKnots = aBSplineCurve->knots(); + std::list aMults = aBSplineCurve->mults(); + theKnots.assign(aKnots.begin(), aKnots.end()); + theMults.assign(aMults.begin(), aMults.end()); +} + +void SketchAPI_BSpline::checkDefaultParameters(bool& isDefaultDegree, + bool& isDefaultWeights, + bool& isDefaultKnotsMults) const +{ + static const double TOLERANCE = 1.e-7; + + AttributePoint2DArrayPtr aPolesAttr = poles(); + AttributeDoubleArrayPtr aWeightsAttr = weights(); + AttributeDoubleArrayPtr aKnotsAttr = knots(); + AttributeIntArrayPtr aMultsAttr = multiplicities(); + + std::list aPoles; + std::list aWeights; + isDefaultWeights = true; + for (int anIndex = 0; anIndex < aPolesAttr->size(); ++anIndex) { + aPoles.push_back(aPolesAttr->pnt(anIndex)); + double aCurWeight = aWeightsAttr->value(anIndex); + isDefaultWeights = isDefaultWeights && fabs(aCurWeight - 1.0) < TOLERANCE; + aWeights.push_back(aCurWeight); + } + + ModelHighAPI_Integer aDegree(-1); + std::list aKnots; + std::list aMults; + getDefaultParameters(aPoles, aWeights, aDegree, aKnots, aMults); + isDefaultDegree = aDegree.intValue() == degree()->value(); + if (!isDefaultDegree) { + // recalculate knots and multiplicities with the actual degree + aDegree = degree()->value(); + getDefaultParameters(aPoles, aWeights, aDegree, aKnots, aMults); + } + + isDefaultKnotsMults = aKnotsAttr->size() == (int)aKnots.size() + && aMultsAttr->size() == (int)aMults.size(); + if (isDefaultKnotsMults) { + std::list::iterator anIt = aKnots.begin(); + for (int anIndex = 0; isDefaultKnotsMults && anIt != aKnots.end(); ++anIt, ++anIndex) + isDefaultKnotsMults = fabs(anIt->value() - aKnotsAttr->value(anIndex)) < TOLERANCE; + } + if (isDefaultKnotsMults) { + std::list::iterator anIt = aMults.begin(); + for (int anIndex = 0; isDefaultKnotsMults && anIt != aMults.end(); ++anIt, ++anIndex) + isDefaultKnotsMults = anIt->intValue() == aMultsAttr->value(anIndex); + } + + isDefaultDegree = isDefaultDegree && isDefaultKnotsMults; + isDefaultWeights = isDefaultWeights && isDefaultKnotsMults; +} + + +static void bsplineAuxiliaryFeature(const AttributeRefAttrPtr& theReference, + FeaturePtr& thePoint, + FeaturePtr& theSegment) +{ + ObjectPtr anAuxObject; + if (theReference->isObject()) + anAuxObject = theReference->object(); + else + anAuxObject = theReference->attr()->owner(); + + FeaturePtr anAuxFeature = ModelAPI_Feature::feature(anAuxObject); + if (anAuxFeature->getKind() == SketchPlugin_Point::ID()) + thePoint = anAuxFeature; + else if (anAuxFeature->getKind() == SketchPlugin_Line::ID() && + theReference->attr()->id() == SketchPlugin_Line::START_ID()) { + // process only coincidence with start point + theSegment = anAuxFeature; + } +} + +static void collectAuxiliaryFeatures(FeaturePtr theBSpline, + std::map& thePoints, + std::map& theSegments) +{ + const std::set& aRefs = theBSpline->data()->refsToMe(); + for (std::set::const_iterator aRefIt = aRefs.begin(); + aRefIt != aRefs.end(); ++aRefIt) { + FeaturePtr anOwner = ModelAPI_Feature::feature((*aRefIt)->owner()); + if (anOwner->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID()) { + // process internal constraints only + AttributeRefAttrPtr aRefAttrA = anOwner->refattr(SketchPlugin_Constraint::ENTITY_A()); + AttributeRefAttrPtr aRefAttrB = anOwner->refattr(SketchPlugin_Constraint::ENTITY_B()); + AttributePtr anAttrA = aRefAttrA->attr(); + AttributePtr anAttrB = aRefAttrB->attr(); + + AttributeIntegerPtr aPoleIndex; + FeaturePtr aPoint, aLine; + if (anAttrA && anAttrA->attributeType() == GeomDataAPI_Point2DArray::typeId()) { + aPoleIndex = anOwner->integer(SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_A()); + bsplineAuxiliaryFeature(aRefAttrB, aPoint, aLine); + } + else if (anAttrB && anAttrB->attributeType() == GeomDataAPI_Point2DArray::typeId()) { + aPoleIndex = anOwner->integer(SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_B()); + bsplineAuxiliaryFeature(aRefAttrA, aPoint, aLine); + } + + if (aPoint) + thePoints[aPoleIndex->value()] = aPoint; + else if (aLine) + theSegments[aPoleIndex->value()] = aLine; + } + } +} + +void SketchAPI_BSpline::dump(ModelHighAPI_Dumper& theDumper) const +{ + if (isCopy()) + return; // no need to dump copied feature + + FeaturePtr aBase = feature(); + const std::string& aSketchName = theDumper.parentName(aBase); + + AttributeSelectionPtr anExternal = aBase->selection(SketchPlugin_SketchEntity::EXTERNAL_ID()); + if (anExternal->context()) { + // B-spline is external + theDumper << aBase << " = " << aSketchName << ".addSpline(" << anExternal << ")" << std::endl; + } else { + // check if some B-spline parameters are default and should not be dumped + bool isDefaultDegree, isDefaultWeights, isDefaultKnotsMults; + checkDefaultParameters(isDefaultDegree, isDefaultWeights, isDefaultKnotsMults); + + theDumper << aBase << " = " << aSketchName << ".addSpline("; + if (!isDefaultDegree) + theDumper << degree() << ", "; + theDumper << poles(); + if (!isDefaultWeights) + theDumper << ", " << weights(); + if (!isDefaultKnotsMults) + theDumper << ", " << knots() << ", " << multiplicities(); + theDumper << ")" << std::endl; + } + // dump "auxiliary" flag if necessary + SketchAPI_SketchEntity::dump(theDumper); + + // dump control polygon + std::map anAuxPoles, anAuxSegments; + collectAuxiliaryFeatures(aBase, anAuxPoles, anAuxSegments); + + if (!anAuxPoles.empty()) + dumpControlPolygon(theDumper, aBase, "controlPoles", anAuxPoles); + if (!anAuxSegments.empty()) + dumpControlPolygon(theDumper, aBase, "controlPolygon", anAuxSegments); +} + +static void dumpList(ModelHighAPI_Dumper& theDumper, + const std::string& theAttrName, + const std::set& theIndices) +{ + theDumper << theAttrName << " = ["; + std::set::const_iterator it = theIndices.begin(); + theDumper << *it; + for (++it; it != theIndices.end(); ++it) + theDumper << ", " << *it; + theDumper << "]"; +} + +void SketchAPI_BSpline::dumpControlPolygon( + ModelHighAPI_Dumper& theDumper, + const FeaturePtr& theBSpline, + const std::string& theMethod, + const std::map& theAuxFeatures) const +{ + theDumper << "["; + bool isFirst = true; + // dump features and split them to auxiliary and regular + std::set aRegular, anAuxiliary; + for (std::map::const_iterator it = theAuxFeatures.begin(); + it != theAuxFeatures.end(); ++it) { + if (!isFirst) + theDumper << ", "; + theDumper << theDumper.name(it->second, false); + theDumper.doNotDumpFeature(it->second); + isFirst = false; + + if (it->second->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()) + anAuxiliary.insert(it->first); + else + aRegular.insert(it->first); + } + theDumper << "] = " << theDumper.name(theBSpline) << "." << theMethod << "("; + if (!aRegular.empty()) { + dumpList(theDumper, "regular", aRegular); + if (!anAuxiliary.empty()) + theDumper << ", "; + } + if (!anAuxiliary.empty()) + dumpList(theDumper, "auxiliary", anAuxiliary); + theDumper << ")" << std::endl; +} diff --git a/src/SketchAPI/SketchAPI_BSpline.h b/src/SketchAPI/SketchAPI_BSpline.h new file mode 100644 index 000000000..70370ad0b --- /dev/null +++ b/src/SketchAPI/SketchAPI_BSpline.h @@ -0,0 +1,158 @@ +// Copyright (C) 2019-2020 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef SketchAPI_BSpline_H_ +#define SketchAPI_BSpline_H_ + +#include "SketchAPI.h" +#include "SketchAPI_SketchEntity.h" + +#include + +#include + +#include + +class ModelHighAPI_Double; +class ModelHighAPI_Integer; +class ModelHighAPI_Selection; + +/// \class SketchAPI_BSpline +/// \ingroup CPPHighAPI +/// \brief Interface for BSpline feature. +class SketchAPI_BSpline : public SketchAPI_SketchEntity +{ +public: + /// Constructor without values. + SKETCHAPI_EXPORT + explicit SketchAPI_BSpline(const std::shared_ptr& theFeature); + + /// Constructor with values. + SKETCHAPI_EXPORT SketchAPI_BSpline( + const std::shared_ptr& theFeature, + const std::list >& thePoles, + const std::list& theWeights = std::list()); + + /// Constructor with values. + SKETCHAPI_EXPORT SketchAPI_BSpline( + const std::shared_ptr& theFeature, + const int theDegree, + const std::list >& thePoles, + const std::list& theWeights = std::list(), + const std::list& theKnots = std::list(), + const std::list& theMults = std::list()); + + /// Constructor with external. + SKETCHAPI_EXPORT + SketchAPI_BSpline(const std::shared_ptr& theFeature, + const ModelHighAPI_Selection& theExternal); + + /// Constructor with external. + SKETCHAPI_EXPORT + SketchAPI_BSpline(const std::shared_ptr& theFeature, + const std::string& theExternalName); + + /// Destructor. + SKETCHAPI_EXPORT + virtual ~SketchAPI_BSpline(); + + INTERFACE_8(SketchPlugin_BSpline::ID(), + poles, SketchPlugin_BSpline::POLES_ID(), + GeomDataAPI_Point2DArray, /** B-spline poles */, + weights, SketchPlugin_BSpline::WEIGHTS_ID(), + ModelAPI_AttributeDoubleArray, /** B-spline weights */, + knots, SketchPlugin_BSpline::KNOTS_ID(), + ModelAPI_AttributeDoubleArray, /** B-spline knots */, + multiplicities, SketchPlugin_BSpline::MULTS_ID(), + ModelAPI_AttributeIntArray, /** Knots multiplicities */, + degree, SketchPlugin_BSpline::DEGREE_ID(), + ModelAPI_AttributeInteger, /** B-spline degree */, + startPoint, SketchPlugin_BSpline::START_ID(), + GeomDataAPI_Point2D, /** First pole of B-spline */, + endPoint, SketchPlugin_BSpline::END_ID(), + GeomDataAPI_Point2D, /** Last pole of B-spline */, + external, SketchPlugin_BSpline::EXTERNAL_ID(), + ModelAPI_AttributeSelection, /** External */) + + /// Set by poles and weights. + SKETCHAPI_EXPORT + void setByDegreePolesAndWeights(const ModelHighAPI_Integer& theDegree, + const std::list >& thePoles, + const std::list& theWeights); + + /// Initialize by full set of B-spline parameters. + SKETCHAPI_EXPORT + void setByParameters(const ModelHighAPI_Integer& theDegree, + const std::list >& thePoles, + const std::list& theWeights, + const std::list& theKnots, + const std::list& theMults); + + /// Set by external. + SKETCHAPI_EXPORT + void setByExternal(const ModelHighAPI_Selection& theExternal); + + /// Set by external name. + SKETCHAPI_EXPORT + void setByExternalName(const std::string& theExternalName); + + /// Generate list of construction points coincident with B-spline poles + SKETCHAPI_EXPORT + std::list > controlPoles( + const std::list& regular = std::list(), + const std::list& auxiliary = std::list()) const; + + /// Generate control polygon for B-spline curve + SKETCHAPI_EXPORT + std::list > controlPolygon( + const std::list& regular = std::list(), + const std::list& auxiliary = std::list()) const; + + /// Dump wrapped feature + SKETCHAPI_EXPORT + virtual void dump(ModelHighAPI_Dumper& theDumper) const; + +private: + /// Initialize start and end points of B-spline and apply internal coincidence + /// constraint to keep them on the corresponding pole. + void setStartAndEndPoints(); + + /// Compute default B-spline parameters (degree, knots and multiplicities) + /// basing on hte given poles and weights + void getDefaultParameters(const std::list >& thePoles, + const std::list& theWeights, + ModelHighAPI_Integer& theDegree, + std::list& theKnots, + std::list& theMults) const; + + /// Check what parameters of B-spline are default + void checkDefaultParameters(bool& isDefaultDegree, + bool& isDefaultWeights, + bool& isDefaultKnotsMults) const; + + void dumpControlPolygon(ModelHighAPI_Dumper& theDumper, + const FeaturePtr& theBSpline, + const std::string& theMethod, + const std::map& theAuxFeatures) const; +}; + +/// Pointer on B-spline object. +typedef std::shared_ptr BSplinePtr; + +#endif // SketchAPI_BSpline_H_ diff --git a/src/SketchAPI/SketchAPI_Projection.cpp b/src/SketchAPI/SketchAPI_Projection.cpp index 4baf94150..3e1a3f789 100644 --- a/src/SketchAPI/SketchAPI_Projection.cpp +++ b/src/SketchAPI/SketchAPI_Projection.cpp @@ -20,12 +20,14 @@ #include "SketchAPI_Projection.h" #include +#include #include #include #include #include #include +#include #include #include #include @@ -108,6 +110,8 @@ std::shared_ptr SketchAPI_Projection::createdFeature() c anEntity.reset(new SketchAPI_Ellipse(aProjectedFeature)); else if (aProjectedFeature->getKind() == SketchPlugin_EllipticArc::ID()) anEntity.reset(new SketchAPI_EllipticArc(aProjectedFeature)); + else if (aProjectedFeature->getKind() == SketchPlugin_BSpline::ID()) + anEntity.reset(new SketchAPI_BSpline(aProjectedFeature)); else if (aProjectedFeature->getKind() == SketchPlugin_Point::ID()) anEntity.reset(new SketchAPI_Point(aProjectedFeature)); diff --git a/src/SketchAPI/SketchAPI_Sketch.cpp b/src/SketchAPI/SketchAPI_Sketch.cpp index 25cac9e71..d1d2967b1 100644 --- a/src/SketchAPI/SketchAPI_Sketch.cpp +++ b/src/SketchAPI/SketchAPI_Sketch.cpp @@ -53,6 +53,7 @@ #include //-------------------------------------------------------------------------------------- #include "SketchAPI_Arc.h" +#include "SketchAPI_BSpline.h" #include "SketchAPI_Circle.h" #include "SketchAPI_Ellipse.h" #include "SketchAPI_EllipticArc.h" @@ -697,6 +698,40 @@ std::shared_ptr SketchAPI_Sketch::addEllipticArc( return EllipticArcPtr(new SketchAPI_EllipticArc(aFeature, theExternalName)); } +//-------------------------------------------------------------------------------------- +std::shared_ptr SketchAPI_Sketch::addSpline( + const std::list >& thePoles, + const std::list& theWeights) +{ + FeaturePtr aFeature = compositeFeature()->addFeature(SketchPlugin_BSpline::ID()); + return BSplinePtr(new SketchAPI_BSpline(aFeature, thePoles, theWeights)); +} + +std::shared_ptr SketchAPI_Sketch::addSpline( + const int theDegree, + const std::list >& thePoles, + const std::list& theWeights, + const std::list& theKnots, + const std::list& theMults) +{ + FeaturePtr aFeature = compositeFeature()->addFeature(SketchPlugin_BSpline::ID()); + return BSplinePtr(new SketchAPI_BSpline(aFeature, + theDegree, thePoles, theWeights, theKnots, theMults)); +} + +std::shared_ptr SketchAPI_Sketch::addSpline( + const ModelHighAPI_Selection & theExternal) +{ + FeaturePtr aFeature = compositeFeature()->addFeature(SketchPlugin_BSpline::ID()); + return BSplinePtr(new SketchAPI_BSpline(aFeature, theExternal)); +} + +std::shared_ptr SketchAPI_Sketch::addSpline(const std::string & theExternalName) +{ + FeaturePtr aFeature = compositeFeature()->addFeature(SketchPlugin_BSpline::ID()); + return BSplinePtr(new SketchAPI_BSpline(aFeature, theExternalName)); +} + //-------------------------------------------------------------------------------------- std::shared_ptr SketchAPI_Sketch::addProjection( const ModelHighAPI_Selection & theExternalFeature, diff --git a/src/SketchAPI/SketchAPI_Sketch.h b/src/SketchAPI/SketchAPI_Sketch.h index f1787c936..4ea404be6 100644 --- a/src/SketchAPI/SketchAPI_Sketch.h +++ b/src/SketchAPI/SketchAPI_Sketch.h @@ -46,6 +46,7 @@ class SketchAPI_Ellipse; class SketchAPI_MacroEllipse; class SketchAPI_EllipticArc; class SketchAPI_MacroEllipticArc; +class SketchAPI_BSpline; class SketchAPI_IntersectionPoint; class SketchAPI_Line; class SketchAPI_Mirror; @@ -324,6 +325,26 @@ public: SKETCHAPI_EXPORT std::shared_ptr addEllipticArc(const std::string & theExternalName); + /// Add B-spline + SKETCHAPI_EXPORT + std::shared_ptr addSpline( + const std::list >& thePoles, + const std::list& theWeights = std::list()); + /// Add B-spline + SKETCHAPI_EXPORT + std::shared_ptr addSpline( + const int theDegree, + const std::list >& thePoles, + const std::list& theWeights = std::list(), + const std::list& theKnots = std::list(), + const std::list& theMults = std::list()); + /// Add B-spline + SKETCHAPI_EXPORT + std::shared_ptr addSpline(const ModelHighAPI_Selection & theExternal); + /// Add B-spline + SKETCHAPI_EXPORT + std::shared_ptr addSpline(const std::string & theExternalName); + /// Add projection SKETCHAPI_EXPORT std::shared_ptr addProjection( diff --git a/src/SketchAPI/SketchAPI_SketchEntity.cpp b/src/SketchAPI/SketchAPI_SketchEntity.cpp index 467e04349..d169c52de 100644 --- a/src/SketchAPI/SketchAPI_SketchEntity.cpp +++ b/src/SketchAPI/SketchAPI_SketchEntity.cpp @@ -19,6 +19,7 @@ #include "SketchAPI_SketchEntity.h" #include +#include #include #include #include @@ -30,6 +31,7 @@ #include #include +#include #include #include #include @@ -103,6 +105,8 @@ SketchAPI_SketchEntity::wrap(const std::list > aResult.push_back(std::shared_ptr(new SketchAPI_Ellipse(*anIt))); else if ((*anIt)->getKind() == SketchPlugin_EllipticArc::ID()) aResult.push_back(std::shared_ptr(new SketchAPI_EllipticArc(*anIt))); + else if ((*anIt)->getKind() == SketchPlugin_BSpline::ID()) + aResult.push_back(std::shared_ptr(new SketchAPI_BSpline(*anIt))); else if ((*anIt)->getKind() == SketchPlugin_Point::ID()) aResult.push_back(std::shared_ptr(new SketchAPI_Point(*anIt))); else if ((*anIt)->getKind() == SketchPlugin_IntersectionPoint::ID()) diff --git a/src/SketchAPI/SketchAPI_swig.h b/src/SketchAPI/SketchAPI_swig.h index 93788350b..28370b70c 100644 --- a/src/SketchAPI/SketchAPI_swig.h +++ b/src/SketchAPI/SketchAPI_swig.h @@ -31,6 +31,7 @@ #include "SketchAPI_MacroEllipse.h" #include "SketchAPI_EllipticArc.h" #include "SketchAPI_MacroEllipticArc.h" + #include "SketchAPI_BSpline.h" #include "SketchAPI_Constraint.h" #include "SketchAPI_ConstraintAngle.h" #include "SketchAPI_IntersectionPoint.h" diff --git a/src/SketchPlugin/SketchPlugin_MacroBSpline.cpp b/src/SketchPlugin/SketchPlugin_MacroBSpline.cpp index 63826c7da..282004946 100644 --- a/src/SketchPlugin/SketchPlugin_MacroBSpline.cpp +++ b/src/SketchPlugin/SketchPlugin_MacroBSpline.cpp @@ -183,14 +183,10 @@ FeaturePtr SketchPlugin_MacroBSpline::createBSplineFeature() AttributePoint2DPtr aStartPoint = std::dynamic_pointer_cast( aBSpline->attribute(SketchPlugin_BSpline::START_ID())); aStartPoint->setValue(aPoles->pnt(0)); - // internal constraint to keep position of the point - createInternalConstraint(aSketch, aStartPoint, aPoles, 0); AttributePoint2DPtr aEndPoint = std::dynamic_pointer_cast( aBSpline->attribute(SketchPlugin_BSpline::END_ID())); aEndPoint->setValue(aPoles->pnt(aPoles->size() - 1)); - // internal constraint to keep position of the point - createInternalConstraint(aSketch, aEndPoint, aPoles, aPoles->size() - 1); aBSpline->boolean(SketchPlugin_BSpline::AUXILIARY_ID())->setValue( boolean(AUXILIARY_ID())->value()); diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_FeatureBuilder.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_FeatureBuilder.cpp index 499dfe1af..8db97df1a 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_FeatureBuilder.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_FeatureBuilder.cpp @@ -301,6 +301,8 @@ EntityWrapperPtr createBSpline(const AttributeEntityMap& theAttributes) aNewSpline->degree = 3; aNewSpline->periodic = false; + std::map anAdditionalAttributes; + AttributeEntityMap::const_iterator anIt = theAttributes.begin(); for (; anIt != theAttributes.end(); ++anIt) { const std::string& anAttrID = anIt->first->id(); @@ -321,6 +323,10 @@ EntityWrapperPtr createBSpline(const AttributeEntityMap& theAttributes) std::dynamic_pointer_cast(anIt->second); aNewSpline->degree = (int)aScalar->value(); } + else if (anAttrID == SketchPlugin_BSpline::START_ID() || + anAttrID == SketchPlugin_BSpline::END_ID()) { + anAdditionalAttributes[anAttrID] = anIt->second; + } else { ScalarArrayWrapperPtr anArray = std::dynamic_pointer_cast(anIt->second); @@ -337,5 +343,7 @@ EntityWrapperPtr createBSpline(const AttributeEntityMap& theAttributes) } } - return EdgeWrapperPtr(new PlaneGCSSolver_EdgeWrapper(aNewSpline)); + EdgeWrapperPtr aWrapper(new PlaneGCSSolver_EdgeWrapper(aNewSpline)); + aWrapper->setAdditionalAttributes(anAdditionalAttributes); + return aWrapper; } diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp index 3c1e8fa43..c190ae1b9 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -367,6 +368,45 @@ static void createEllipticArcConstraints( constraintsToSolver(aConstraint, theSolver); } +static void createBSplineConstraints( + const EntityWrapperPtr& theCurve, + const SolverPtr& theSolver, + const ConstraintID theConstraintID, + std::map& theConstraints) +{ + // set start and end point of B-spline equal to first and last pole correspondingly + EdgeWrapperPtr anEdge = std::dynamic_pointer_cast(theCurve); + std::shared_ptr aBSpline = + std::dynamic_pointer_cast(anEdge->entity()); + + std::list aBSplineConstraints; + + const std::map& anAdditional = anEdge->additionalAttributes(); + PointWrapperPtr aStartPoint = std::dynamic_pointer_cast( + anAdditional.at(SketchPlugin_BSpline::START_ID())); + + const GCS::Point& sp = *aStartPoint->point(); + const GCS::Point& p0 = aBSpline->poles.front(); + aBSplineConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintEqual(p0.x, sp.x))); + aBSplineConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintEqual(p0.y, sp.y))); + + PointWrapperPtr aEndPoint = std::dynamic_pointer_cast( + anAdditional.at(SketchPlugin_BSpline::END_ID())); + + const GCS::Point& ep = *aEndPoint->point(); + const GCS::Point& pN = aBSpline->poles.back(); + aBSplineConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintEqual(pN.x, ep.x))); + aBSplineConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintEqual(pN.y, ep.y))); + + ConstraintWrapperPtr aWrapper( + new PlaneGCSSolver_ConstraintWrapper(aBSplineConstraints, CONSTRAINT_UNKNOWN)); + aWrapper->setId(theConstraintID); + if (theSolver) + constraintsToSolver(aWrapper, theSolver); + + theConstraints[theCurve] = aWrapper; +} + void PlaneGCSSolver_Storage::createAuxiliaryConstraints(const EntityWrapperPtr& theEntity) { if (!theEntity || theEntity->isExternal()) @@ -380,6 +420,8 @@ void PlaneGCSSolver_Storage::createAuxiliaryConstraints(const EntityWrapperPtr& createEllipticArcConstraints(theEntity, mySketchSolver, ++myConstraintLastID, myAuxConstraintMap); } + else if (theEntity->type() == ENTITY_BSPLINE) + createBSplineConstraints(theEntity, mySketchSolver, ++myConstraintLastID, myAuxConstraintMap); } void PlaneGCSSolver_Storage::removeAuxiliaryConstraints(const EntityWrapperPtr& theEntity) -- 2.39.2