From ff7623851b6e426109d12aef2da79638af84b55e Mon Sep 17 00:00:00 2001 From: azv Date: Mon, 30 Dec 2019 17:55:24 +0300 Subject: [PATCH] Issue #17347: B-Splines in Sketcher Process point-on-bspline constraint be the sketch solver. --- src/GeomAPI/CMakeLists.txt | 2 + src/GeomAPI/GeomAPI_BSpline2d.cpp | 129 ++++++++++++++++++ src/GeomAPI/GeomAPI_BSpline2d.h | 63 +++++++++ src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.cpp | 66 ++++----- src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.h | 15 +- src/SketchPlugin/SketchPlugin_BSpline.cpp | 15 +- src/SketchPlugin/SketchPlugin_BSpline.h | 7 + .../SketchPlugin_MacroBSpline.cpp | 32 ++++- src/SketchPlugin/SketchPlugin_MacroBSpline.h | 1 + .../PlaneGCSSolver/CMakeLists.txt | 2 + .../PlaneGCSSolver_AttributeBuilder.cpp | 32 ++++- .../PlaneGCSSolver_FeatureBuilder.cpp | 13 +- .../PlaneGCSSolver_GeoExtensions.cpp | 87 ++++++++++++ .../PlaneGCSSolver_GeoExtensions.h | 53 +++++++ .../PlaneGCSSolver/PlaneGCSSolver_Storage.cpp | 2 + .../PlaneGCSSolver/PlaneGCSSolver_Tools.cpp | 39 +++++- .../SketchSolver_ConstraintCoincidence.cpp | 22 ++- .../SketchSolver_ConstraintCoincidence.h | 1 + 18 files changed, 504 insertions(+), 77 deletions(-) create mode 100644 src/GeomAPI/GeomAPI_BSpline2d.cpp create mode 100644 src/GeomAPI/GeomAPI_BSpline2d.h create mode 100644 src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_GeoExtensions.cpp create mode 100644 src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_GeoExtensions.h diff --git a/src/GeomAPI/CMakeLists.txt b/src/GeomAPI/CMakeLists.txt index cade6fc2f..0fda17637 100644 --- a/src/GeomAPI/CMakeLists.txt +++ b/src/GeomAPI/CMakeLists.txt @@ -25,6 +25,7 @@ INCLUDE(UnitTest) SET(PROJECT_HEADERS GeomAPI.h + GeomAPI_BSpline2d.h GeomAPI_Circ.h GeomAPI_Circ2d.h GeomAPI_Interface.h @@ -71,6 +72,7 @@ SET(PROJECT_HEADERS ) SET(PROJECT_SOURCES + GeomAPI_BSpline2d.cpp GeomAPI_Circ.cpp GeomAPI_Circ2d.cpp GeomAPI_Interface.cpp diff --git a/src/GeomAPI/GeomAPI_BSpline2d.cpp b/src/GeomAPI/GeomAPI_BSpline2d.cpp new file mode 100644 index 000000000..ca5e18914 --- /dev/null +++ b/src/GeomAPI/GeomAPI_BSpline2d.cpp @@ -0,0 +1,129 @@ +// 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 +#include +#include + +#include + +#define MY_BSPLINE (*(implPtr())) + + +static Handle_Geom2d_BSplineCurve* newBSpline2d( + const std::list >& thePoles, + const std::list& theWeights, + const int theDegree, + const bool thePeriodic) +{ + int aNbKnots = (int)thePoles.size() - theDegree + 1; + if (aNbKnots < 2) + return new Handle_Geom2d_BSplineCurve(); + + // collect arrays of poles, weights, knots and multiplicities + TColgp_Array1OfPnt2d aPoles(1, (int)thePoles.size()); + TColStd_Array1OfReal aWeights(1, (int)theWeights.size()); + TColStd_Array1OfReal aKnots(1, aNbKnots); + TColStd_Array1OfInteger aMults(1, aNbKnots); + + int anIndex = 1; + for (std::list::const_iterator aPIt = thePoles.begin(); + aPIt != thePoles.end(); ++aPIt, ++anIndex) + aPoles.SetValue(anIndex, gp_Pnt2d((*aPIt)->x(), (*aPIt)->y())); + anIndex = 1; + for (std::list::const_iterator aWIt = theWeights.begin(); + aWIt != theWeights.end(); ++aWIt, ++anIndex) + aWeights.SetValue(anIndex, *aWIt); + anIndex = 1; + static const double aStartParam = 0.0; + static const double aEndParam = 1.0; + double aStep = aEndParam / (aNbKnots - 1); + for (double aKnot = aStartParam; anIndex < aNbKnots; ++anIndex, aKnot += aStep) + aKnots.SetValue(anIndex, aKnot); + aKnots.ChangeLast() = aEndParam; + anIndex = 1; + aMults.SetValue(anIndex, theDegree + 1); + for (++anIndex; anIndex < aNbKnots; ++anIndex) + aMults.SetValue(anIndex, 1); + aMults.SetValue(aNbKnots, theDegree + 1); + + Handle(Geom2d_BSplineCurve) aCurve = + new Geom2d_BSplineCurve(aPoles, aWeights, aKnots, aMults, theDegree, thePeriodic); + return new Handle_Geom2d_BSplineCurve(aCurve); +} + +static Handle_Geom2d_BSplineCurve* newBSpline2d( + const std::list >& thePoles, + const std::list& theWeights, + const bool thePeriodic) +{ + int aDegree = 3; + if ((int)thePoles.size() <= aDegree) + aDegree = (int)thePoles.size() - 1; + if (aDegree <= 0) + return new Handle_Geom2d_BSplineCurve(); + return newBSpline2d(thePoles, theWeights, aDegree, thePeriodic); +} + + +GeomAPI_BSpline2d::GeomAPI_BSpline2d(const std::list >& thePoles, + const std::list& theWeights, + const bool thePeriodic) + : GeomAPI_Interface(newBSpline2d(thePoles, theWeights, thePeriodic)) +{ + if (isNull()) + throw Standard_ConstructionError("GeomAPI_BSpline2d: Impossible to create B-spline curve"); +} + +GeomAPI_BSpline2d::GeomAPI_BSpline2d(const std::list >& thePoles, + const std::list& theWeights, + const int theDegree, + const bool thePeriodic) + : GeomAPI_Interface(newBSpline2d(thePoles, theWeights, theDegree, thePeriodic)) +{ + if (isNull()) + throw Standard_ConstructionError("GeomAPI_BSpline2d: Impossible to create B-spline curve"); +} + +bool GeomAPI_BSpline2d::isNull() const +{ + return MY_BSPLINE.IsNull(); +} + +int GeomAPI_BSpline2d::degree() const +{ + return MY_BSPLINE->Degree(); +} + +void GeomAPI_BSpline2d::D0(const double theU, std::shared_ptr& thePoint) +{ + gp_Pnt2d aPnt; + MY_BSPLINE->D0(theU, aPnt); + thePoint.reset(new GeomAPI_Pnt2d(aPnt.X(), aPnt.Y())); +} + +void GeomAPI_BSpline2d::D1(const double theU, std::shared_ptr& thePoint, + std::shared_ptr& theDerivative) +{ + gp_Pnt2d aPnt; + gp_Vec2d aVec; + MY_BSPLINE->D1(theU, aPnt, aVec); + thePoint.reset(new GeomAPI_Pnt2d(aPnt.X(), aPnt.Y())); + theDerivative.reset(new GeomAPI_XY(aVec.X(), aVec.Y())); +} diff --git a/src/GeomAPI/GeomAPI_BSpline2d.h b/src/GeomAPI/GeomAPI_BSpline2d.h new file mode 100644 index 000000000..290458693 --- /dev/null +++ b/src/GeomAPI/GeomAPI_BSpline2d.h @@ -0,0 +1,63 @@ +// 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 GeomAPI_BSpline2d_H_ +#define GeomAPI_BSpline2d_H_ + +#include + +#include +#include + +class GeomAPI_Pnt2d; +class GeomAPI_XY; + +/** \class GeomAPI_BSpline2d + * \ingroup DataModel + * \brief B-spline curve in 2D + */ +class GeomAPI_BSpline2d : public GeomAPI_Interface +{ +public: + /// Creation of B-spline curve defined by list of poles and weights + GEOMAPI_EXPORT GeomAPI_BSpline2d(const std::list >& thePoles, + const std::list& theWeights, + const bool thePeriodic = false); + + /// Creation of B-spline curve defined by list of poles and weights + GEOMAPI_EXPORT GeomAPI_BSpline2d(const std::list >& thePoles, + const std::list& theWeights, + const int theDegree, + const bool thePeriodic = false); + + /// Returns true if curve is not initialized + GEOMAPI_EXPORT bool isNull() const; + + /// Returns degree of the curve + GEOMAPI_EXPORT int degree() const; + + /// \brief Calculate point on B-spline curve accrding to the given parameter + GEOMAPI_EXPORT void D0(const double theU, std::shared_ptr& thePoint); + + /// \brief Calculate point and first derivative for B-spline curve accrding to the given parameter + GEOMAPI_EXPORT void D1(const double theU, std::shared_ptr& thePoint, + std::shared_ptr& theDerivative); +}; + +#endif diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.cpp index 4e42c0a92..03145a117 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.cpp +++ b/src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.cpp @@ -20,7 +20,10 @@ #include #include +#include #include +#include +#include #include #include @@ -28,10 +31,11 @@ #include #include #include -#include +#include #include #include #include +#include #include #include @@ -268,49 +272,25 @@ std::shared_ptr GeomAlgoAPI_EdgeBuilder::ellipticArc( return aRes; } -GeomEdgePtr GeomAlgoAPI_EdgeBuilder::bspline(const std::vector& thePoles, - const std::vector& theWeights, - const bool thePeriodic) +GeomEdgePtr GeomAlgoAPI_EdgeBuilder::bsplineOnPlane( + const std::shared_ptr& thePlane, + const std::list& thePoles, + const std::list& theWeights, + const bool thePeriodic) { - int aDegree = 3; - if ((int)thePoles.size() <= aDegree) - aDegree = (int)thePoles.size() - 1; - if (aDegree <= 0) - return GeomEdgePtr(); - - int aNbKnots = (int)thePoles.size() - aDegree + 1; - - // collect arrays of poles, weights, knots and multiplicities - TColgp_Array1OfPnt aPoles(1, (int)thePoles.size()); - TColStd_Array1OfReal aWeights(1, (int)theWeights.size()); - TColStd_Array1OfReal aKnots(1, aNbKnots); - TColStd_Array1OfInteger aMults(1, aNbKnots); - - int anIndex = 1; - for (std::vector::const_iterator aPIt = thePoles.begin(); - aPIt != thePoles.end(); ++aPIt, ++anIndex) - aPoles.SetValue(anIndex, gp_Pnt((*aPIt)->x(), (*aPIt)->y(), (*aPIt)->z())); - anIndex = 1; - for (std::vector::const_iterator aWIt = theWeights.begin(); - aWIt != theWeights.end(); ++aWIt, ++anIndex) - aWeights.SetValue(anIndex, *aWIt); - anIndex = 1; - static const double aStartParam = 0.0; - static const double aEndParam = 1.0; - double aStep = aEndParam / (aNbKnots - 1); - for (double aKnot = aStartParam; anIndex < aNbKnots; ++anIndex, aKnot += aStep) - aKnots.SetValue(anIndex, aKnot); - aKnots.ChangeLast() = aEndParam; - anIndex = 1; - aMults.SetValue(anIndex, aDegree + 1); - for (++anIndex; anIndex < aNbKnots; ++anIndex) - aMults.SetValue(anIndex, 1); - aMults.SetValue(aNbKnots, aDegree + 1); - - Handle(Geom_BSplineCurve) aCurve = - new Geom_BSplineCurve(aPoles, aWeights, aKnots, aMults, aDegree, thePeriodic); - - BRepBuilderAPI_MakeEdge anEdgeBuilder(aCurve, aStartParam, aEndParam); + std::shared_ptr aBSplineCurve( + new GeomAPI_BSpline2d(thePoles, theWeights, thePeriodic)); + return bsplineOnPlane(thePlane, aBSplineCurve); +} + +GeomEdgePtr GeomAlgoAPI_EdgeBuilder::bsplineOnPlane( + const std::shared_ptr& thePlane, + const std::shared_ptr& theCurve) +{ + Handle(Geom_Curve) aCurve3D = GeomLib::To3d(thePlane->impl().Position().Ax2(), + theCurve->impl()); + + BRepBuilderAPI_MakeEdge anEdgeBuilder(aCurve3D); GeomEdgePtr aRes(new GeomAPI_Edge); TopoDS_Edge anEdge = anEdgeBuilder.Edge(); aRes->setImpl(new TopoDS_Shape(anEdge)); diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.h b/src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.h index d6185f3f5..ac4ca0286 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.h +++ b/src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.h @@ -29,6 +29,8 @@ #include #include +class GeomAPI_BSpline2d; + /**\class GeomAlgoAPI_EdgeBuilder * \ingroup DataAlgo * \brief Allows to create face-shapes by different parameters @@ -91,10 +93,15 @@ class GEOMALGOAPI_EXPORT GeomAlgoAPI_EdgeBuilder const std::shared_ptr& theStart, const std::shared_ptr& theEnd); - /// Creates B-spline edge - static GeomEdgePtr bspline(const std::vector& thePoles, - const std::vector& theWeights, - const bool thePeriodic); + /// Creates planar B-spline edge + static GeomEdgePtr bsplineOnPlane(const std::shared_ptr& thePlane, + const std::list >& thePoles, + const std::list& theWeights, + const bool thePeriodic); + + /// Creates planar B-spline edge + static GeomEdgePtr bsplineOnPlane(const std::shared_ptr& thePlane, + const std::shared_ptr& theCurve); }; #endif diff --git a/src/SketchPlugin/SketchPlugin_BSpline.cpp b/src/SketchPlugin/SketchPlugin_BSpline.cpp index f226e0657..64fa4fcac 100644 --- a/src/SketchPlugin/SketchPlugin_BSpline.cpp +++ b/src/SketchPlugin/SketchPlugin_BSpline.cpp @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -52,6 +53,7 @@ void SketchPlugin_BSpline::initDerivedClassAttributes() { data()->addAttribute(POLES_ID(), GeomDataAPI_Point2DArray::typeId()); data()->addAttribute(WEIGHTS_ID(), ModelAPI_AttributeDoubleArray::typeId()); + data()->addAttribute(DEGREE_ID(), ModelAPI_AttributeInteger::typeId()); data()->addAttribute(EXTERNAL_ID(), ModelAPI_AttributeSelection::typeId()); ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EXTERNAL_ID()); @@ -68,21 +70,20 @@ void SketchPlugin_BSpline::execute() std::dynamic_pointer_cast(attribute(POLES_ID())); AttributeDoubleArrayPtr aWeightsArray = data()->realArray(WEIGHTS_ID()); - // convert poles to 3D - std::vector aPoles3D; - aPoles3D.reserve(aPolesArray->size()); + // collect poles + std::list aPoles2D; for (int anIndex = 0; anIndex < aPolesArray->size(); ++anIndex) { GeomPnt2dPtr aPole = aPolesArray->pnt(anIndex); - aPoles3D.push_back(aSketch->to3D(aPole->x(), aPole->y())); + aPoles2D.push_back(aPole); } // collect weights - std::vector aWeights; - aWeights.reserve(aWeightsArray->size()); + std::list aWeights; for (int anIndex = 0; anIndex < aWeightsArray->size(); ++anIndex) aWeights.push_back(aWeightsArray->value(anIndex)); // create result non-periodic B-spline curve - GeomShapePtr anEdge = GeomAlgoAPI_EdgeBuilder::bspline(aPoles3D, aWeights, false); + GeomShapePtr anEdge = + GeomAlgoAPI_EdgeBuilder::bsplineOnPlane(aSketch->plane(), aPoles2D, aWeights, false); ResultConstructionPtr aResult = document()->createConstruction(data(), 0); aResult->setShape(anEdge); diff --git a/src/SketchPlugin/SketchPlugin_BSpline.h b/src/SketchPlugin/SketchPlugin_BSpline.h index c918a090c..303dc1f0b 100644 --- a/src/SketchPlugin/SketchPlugin_BSpline.h +++ b/src/SketchPlugin/SketchPlugin_BSpline.h @@ -51,6 +51,13 @@ public: return ID; } + /// attribute to store the degree of B-spline + inline static const std::string& DEGREE_ID() + { + static const std::string ID("degree"); + return ID; + } + /// Returns the kind of a feature SKETCHPLUGIN_EXPORT virtual const std::string& getKind() { diff --git a/src/SketchPlugin/SketchPlugin_MacroBSpline.cpp b/src/SketchPlugin/SketchPlugin_MacroBSpline.cpp index ee47982d8..0b81547a3 100644 --- a/src/SketchPlugin/SketchPlugin_MacroBSpline.cpp +++ b/src/SketchPlugin/SketchPlugin_MacroBSpline.cpp @@ -40,6 +40,8 @@ #include #include +#include + #include // Create Point feature coincident with the B-spline pole @@ -60,6 +62,7 @@ static void createInternalConstraint(SketchPlugin_Sketch* theSketch, SketchPlugin_MacroBSpline::SketchPlugin_MacroBSpline() : SketchPlugin_SketchEntity(), + myDegree(3), myIsPeriodic(false) { } @@ -138,6 +141,8 @@ FeaturePtr SketchPlugin_MacroBSpline::createBSplineFeature() { FeaturePtr aBSpline = sketch()->addFeature(SketchPlugin_BSpline::ID()); + aBSpline->integer(SketchPlugin_BSpline::DEGREE_ID())->setValue(myDegree); + AttributePoint2DArrayPtr aPoles = std::dynamic_pointer_cast( aBSpline->attribute(SketchPlugin_BSpline::POLES_ID())); AttributePoint2DArrayPtr aPolesMacro = @@ -207,17 +212,20 @@ AISObjectPtr SketchPlugin_MacroBSpline::getAISObject(AISObjectPtr thePrevious) if (!aSketch) return AISObjectPtr(); + static const bool PERIODIC = false; + AttributePoint2DArrayPtr aPolesArray = std::dynamic_pointer_cast(attribute(POLES_ID())); AttributeDoubleArrayPtr aWeightsArray = data()->realArray(WEIGHTS_ID()); + if (aPolesArray->size() < 2) + return AISObjectPtr(); + std::list aShapes; - // convert poles to 3D and collect weights - std::vector aPoles3D; - aPoles3D.reserve(aPolesArray->size()); - std::vector aWeights; - aWeights.reserve(aWeightsArray->size()); + // convert poles to vertices and collect weights + std::list aPoles2D; + std::list aWeights; for (int anIndex = 0; anIndex < aPolesArray->size(); ++anIndex) { double aWeight = aWeightsArray->value(anIndex); if (aWeight < 1.e-10) @@ -226,16 +234,26 @@ AISObjectPtr SketchPlugin_MacroBSpline::getAISObject(AISObjectPtr thePrevious) aWeights.push_back(aWeight); GeomPnt2dPtr aPole = aPolesArray->pnt(anIndex); + aPoles2D.push_back(aPole); GeomPointPtr aPole3D = aSketch->to3D(aPole->x(), aPole->y()); - aPoles3D.push_back(aPole3D); aShapes.push_back(GeomAlgoAPI_PointBuilder::vertex(aPole3D)); } // create result non-periodic B-spline curve - GeomShapePtr anEdge = GeomAlgoAPI_EdgeBuilder::bspline(aPoles3D, aWeights, false); + std::shared_ptr aBSplineCurve; + try { + aBSplineCurve.reset(new GeomAPI_BSpline2d(aPoles2D, aWeights, PERIODIC)); + } catch (...) { + // cannot build a B-spline curve + return AISObjectPtr(); + } + GeomShapePtr anEdge = + GeomAlgoAPI_EdgeBuilder::bsplineOnPlane(aSketch->plane(), aBSplineCurve); if (!anEdge) return AISObjectPtr(); + myDegree = aBSplineCurve->degree(); + aShapes.push_back(anEdge); GeomShapePtr aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes); diff --git a/src/SketchPlugin/SketchPlugin_MacroBSpline.h b/src/SketchPlugin/SketchPlugin_MacroBSpline.h index f74b5bb50..0137962ed 100644 --- a/src/SketchPlugin/SketchPlugin_MacroBSpline.h +++ b/src/SketchPlugin/SketchPlugin_MacroBSpline.h @@ -104,6 +104,7 @@ private: void createControlPolygon(FeaturePtr theBSpline, std::list& thePoles); void constraintsForPoles(const std::list& thePoles); + int myDegree; bool myIsPeriodic; }; diff --git a/src/SketchSolver/PlaneGCSSolver/CMakeLists.txt b/src/SketchSolver/PlaneGCSSolver/CMakeLists.txt index 59f33e0f6..61a812a8b 100644 --- a/src/SketchSolver/PlaneGCSSolver/CMakeLists.txt +++ b/src/SketchSolver/PlaneGCSSolver/CMakeLists.txt @@ -33,6 +33,7 @@ SET(PLANEGCSSOLVER_HEADERS PlaneGCSSolver_AngleWrapper.h PlaneGCSSolver_BooleanWrapper.h PlaneGCSSolver_Tools.h + PlaneGCSSolver_GeoExtensions.h ) SET(PLANEGCSSOLVER_SOURCES @@ -47,6 +48,7 @@ SET(PLANEGCSSOLVER_SOURCES PlaneGCSSolver_AngleWrapper.cpp PlaneGCSSolver_BooleanWrapper.cpp PlaneGCSSolver_Tools.cpp + PlaneGCSSolver_GeoExtensions.cpp ) SET(PLANEGCSSOLVER_BUILDER_HEADERS diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AttributeBuilder.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AttributeBuilder.cpp index 7ccedd950..c8a6cb264 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AttributeBuilder.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AttributeBuilder.cpp @@ -30,6 +30,8 @@ #include #include #include +#include +#include #include #include @@ -63,9 +65,17 @@ static EntityWrapperPtr createBoolean(const AttributePtr& theAttribute) static EntityWrapperPtr createScalar(const AttributePtr& theAttribute, PlaneGCSSolver_Storage* theStorage) { - AttributeDoublePtr aScalar = std::dynamic_pointer_cast(theAttribute); - if (!aScalar) - return EntityWrapperPtr(); + double aValue = 0.0; + AttributeDoublePtr aDouble = std::dynamic_pointer_cast(theAttribute); + if (aDouble) + aValue = aDouble->isInitialized() ? aDouble->value() : 0.0; + else { + AttributeIntegerPtr anInt = std::dynamic_pointer_cast(theAttribute); + if (anInt) + aValue = anInt->isInitialized() ? anInt->value() : 0.0; + else + return EntityWrapperPtr(); + } ScalarWrapperPtr aWrapper; // following attributes should be converted from degrees to radians @@ -77,11 +87,14 @@ static EntityWrapperPtr createScalar(const AttributePtr& theAttribute, (theAttribute->id() == SketchPlugin_MultiRotation::ANGLE_ID() && anOwner->getKind() == SketchPlugin_MultiRotation::ID())) aWrapper = ScalarWrapperPtr(new PlaneGCSSolver_AngleWrapper(createParameter(theStorage))); + else if (anOwner->getKind() == SketchPlugin_BSpline::ID() && + theAttribute->id() == SketchPlugin_BSpline::DEGREE_ID()) + // Degree of B-spline is not processed by the solver + aWrapper = ScalarWrapperPtr(new PlaneGCSSolver_ScalarWrapper(createParameter(nullptr))); else aWrapper = ScalarWrapperPtr(new PlaneGCSSolver_ScalarWrapper(createParameter(theStorage))); - if (aScalar->isInitialized()) - aWrapper->setValue(aScalar->value()); + aWrapper->setValue(aValue); return aWrapper; } @@ -93,11 +106,18 @@ static EntityWrapperPtr createScalarArray(const AttributePtr& theAttribute, if (!anArray || !anArray->isInitialized()) return EntityWrapperPtr(); + PlaneGCSSolver_Storage* aStorage = theStorage; + // Weights of B-spline curve are not processed by the solver + FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner()); + if (anOwner->getKind() == SketchPlugin_BSpline::ID() && + theAttribute->id() == SketchPlugin_BSpline::WEIGHTS_ID()) + aStorage = 0; + int aSize = anArray->size(); GCS::VEC_pD aParameters; aParameters.reserve(aSize); for (int index = 0; index < aSize; ++index) { - double* aParam = createParameter(theStorage); + double* aParam = createParameter(aStorage); *aParam = anArray->value(index); aParameters.push_back(aParam); } diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_FeatureBuilder.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_FeatureBuilder.cpp index 78dc0d7c9..b8ac3e1dd 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_FeatureBuilder.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_FeatureBuilder.cpp @@ -18,12 +18,13 @@ // #include +#include #include +#include #include #include #include #include -#include #include #include @@ -297,7 +298,7 @@ EntityWrapperPtr createEllipticArc(const AttributeEntityMap& theAttributes, EntityWrapperPtr createBSpline(const AttributeEntityMap& theAttributes) { - std::shared_ptr aNewSpline(new GCS::BSpline); + std::shared_ptr aNewSpline(new GCS::BSplineImpl); aNewSpline->degree = 3; aNewSpline->periodic = false; @@ -322,6 +323,11 @@ EntityWrapperPtr createBSpline(const AttributeEntityMap& theAttributes) std::dynamic_pointer_cast(anIt->second); aNewSpline->weights = anArray->array(); } + else if (anAttrID == SketchPlugin_BSpline::DEGREE_ID()) { + ScalarWrapperPtr aScalar = + std::dynamic_pointer_cast(anIt->second); + aNewSpline->degree = (int)aScalar->value(); + } } return EdgeWrapperPtr(new PlaneGCSSolver_EdgeWrapper(aNewSpline)); @@ -370,7 +376,8 @@ bool isAttributeApplicable(const std::string& theAttrName, const std::string& th } else if (theOwnerName == SketchPlugin_BSpline::ID()) { return theAttrName == SketchPlugin_BSpline::POLES_ID() || - theAttrName == SketchPlugin_BSpline::WEIGHTS_ID(); + theAttrName == SketchPlugin_BSpline::WEIGHTS_ID() || + theAttrName == SketchPlugin_BSpline::DEGREE_ID(); } // suppose that all remaining features are points diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_GeoExtensions.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_GeoExtensions.cpp new file mode 100644 index 000000000..a97976001 --- /dev/null +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_GeoExtensions.cpp @@ -0,0 +1,87 @@ +// 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 + +#include +#include +#include + +#include + +namespace GCS +{ + +DeriVector2 BSplineImpl::Value(double u, double du, double* derivparam) +{ + if (!isCacheValid()) + rebuildCache(); + + std::shared_ptr aValue; + std::shared_ptr aDeriv; + myCurve->D1(u, aValue, aDeriv); + + return DeriVector2(aValue->x(), aValue->y(), aDeriv->x() * du, aDeriv->y() * du); +} + +BSplineImpl* BSplineImpl::Copy() +{ + return new BSplineImpl(*this); +} + + +bool BSplineImpl::isCacheValid() const +{ + // curve has to be initialized + bool isValid = myCurve.get() && !myCurve->isNull(); + + static const double THE_TOLERANCE = 1.e-7; + // compare poles + isValid = isValid && poles.size() == myCachedPoles.size(); + std::list::const_iterator aCachePIt = myCachedPoles.begin(); + GCS::VEC_P::const_iterator aPolesIt = poles.begin(); + for (; isValid && aPolesIt != poles.end(); ++aPolesIt, ++aCachePIt) { + isValid = isValid && fabs((*aCachePIt)->x() - *aPolesIt->x) < THE_TOLERANCE + && fabs((*aCachePIt)->y() - *aPolesIt->y) < THE_TOLERANCE; + } + + // compare weights + isValid = isValid && weights.size() == myCachedWeights.size(); + std::list::const_iterator aCacheWIt = myCachedWeights.begin(); + GCS::VEC_pD::const_iterator aWeightsIt = weights.begin(); + for (; isValid && aWeightsIt != weights.end(); ++aWeightsIt, ++aCacheWIt) + isValid = isValid && fabs(*aCacheWIt - **aWeightsIt) < THE_TOLERANCE; + + return isValid; +} + +void BSplineImpl::rebuildCache() +{ + myCachedPoles.clear(); + myCachedWeights.clear(); + + for (GCS::VEC_P::iterator anIt = poles.begin(); anIt != poles.end(); ++anIt) + myCachedPoles.push_back(GeomPnt2dPtr(new GeomAPI_Pnt2d(*anIt->x, *anIt->y))); + for (GCS::VEC_pD::iterator anIt = weights.begin(); anIt != weights.end(); ++anIt) + myCachedWeights.push_back(**anIt); + + myCurve.reset(new GeomAPI_BSpline2d(myCachedPoles, myCachedWeights, degree, periodic)); +} + +} // namespace GCS diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_GeoExtensions.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_GeoExtensions.h new file mode 100644 index 000000000..87f66653c --- /dev/null +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_GeoExtensions.h @@ -0,0 +1,53 @@ +// 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 PlaneGCSSolver_GeomExtensions_H_ +#define PlaneGCSSolver_GeomExtensions_H_ + +#include + +#include +#include + +class GeomAPI_BSpline2d; +class GeomAPI_Pnt2d; + +namespace GCS { + /// \brife SHAPER's implementation of B-spline curves in PlaneGCS solver + class BSplineImpl : public BSpline + { + public: + virtual DeriVector2 Value(double u, double du, double* derivparam = 0); + + virtual BSplineImpl* Copy(); + + private: + /// Verify the cached curve satisfies to the parameters + bool isCacheValid() const; + /// Poles or weights are changed, cache curve has to be rebuilt + void rebuildCache(); + + private: + std::shared_ptr myCurve; /// cached B-spline curve + std::list > myCachedPoles; /// cached B-spline poles + std::list myCachedWeights; /// cached B-spline weights + }; +} + +#endif diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp index 9349f5c30..328b7144c 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp @@ -582,6 +582,8 @@ double* PlaneGCSSolver_Storage::createParameter() void PlaneGCSSolver_Storage::removeParameters(const GCS::SET_pD& theParams) { mySketchSolver->removeParameters(theParams); + for (GCS::SET_pD::iterator it = theParams.begin(); it != theParams.end(); ++it) + delete *it; } // indicates attribute containing in the external feature diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp index c1b83d3f8..5fe371915 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp @@ -77,7 +77,8 @@ static ConstraintWrapperPtr static ConstraintWrapperPtr createConstraintPointOnEntity(const SketchSolver_ConstraintType& theType, std::shared_ptr thePoint, - std::shared_ptr theEntity); + std::shared_ptr theEntity, + std::shared_ptr theValue); static ConstraintWrapperPtr createConstraintPointsCollinear(std::shared_ptr thePoint1, std::shared_ptr thePoint2, @@ -134,6 +135,7 @@ static GCS::SET_pD circleParameters(const EdgeWrapperPtr& theCircle); static GCS::SET_pD arcParameters(const EdgeWrapperPtr& theArc); static GCS::SET_pD ellipseParameters(const EdgeWrapperPtr& theEllipse); static GCS::SET_pD ellipticArcParameters(const EdgeWrapperPtr& theEllipticArc); +static GCS::SET_pD bsplineParameters(const EdgeWrapperPtr& theEdge); static double distance(const GCS::Point& thePnt1, const GCS::Point& thePnt2); @@ -221,8 +223,9 @@ ConstraintWrapperPtr PlaneGCSSolver_Tools::createConstraint( aResult = createConstraintCoincidence(aPoint1, aPoint2); break; case CONSTRAINT_PT_ON_CURVE: - aResult = anEntity1 ? createConstraintPointOnEntity(theType, aPoint1, anEntity1): - createConstraintPointsCollinear(aPoint1, aPoint2, GCS_POINT_WRAPPER(theEntity1)); + aResult = anEntity1 ? + createConstraintPointOnEntity(theType, aPoint1, anEntity1, GCS_SCALAR_WRAPPER(theValue)) : + createConstraintPointsCollinear(aPoint1, aPoint2, GCS_POINT_WRAPPER(theEntity1)); break; case CONSTRAINT_MIDDLE_POINT: aResult = createConstraintMiddlePoint(aPoint1, GCS_EDGE_WRAPPER(theEntity1), aPoint2); @@ -408,6 +411,8 @@ GCS::SET_pD PlaneGCSSolver_Tools::parameters(const EntityWrapperPtr& theEntity) return ellipseParameters(GCS_EDGE_WRAPPER(theEntity)); case ENTITY_ELLIPTIC_ARC: return ellipticArcParameters(GCS_EDGE_WRAPPER(theEntity)); + case ENTITY_BSPLINE: + return bsplineParameters(GCS_EDGE_WRAPPER(theEntity)); default: break; } return GCS::SET_pD(); @@ -440,7 +445,8 @@ ConstraintWrapperPtr createConstraintCoincidence( ConstraintWrapperPtr createConstraintPointOnEntity( const SketchSolver_ConstraintType& theType, std::shared_ptr thePoint, - std::shared_ptr theEntity) + std::shared_ptr theEntity, + std::shared_ptr theValue) { GCSConstraintPtr aNewConstr; @@ -466,6 +472,14 @@ ConstraintWrapperPtr createConstraintPointOnEntity( new GCS::ConstraintPointOnEllipse(*(thePoint->point()), *anEllipse)); break; } + case ENTITY_BSPLINE: { + std::list aConstraints; + aConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintCurveValue( + *thePoint->point(), thePoint->point()->x, *theEntity->entity(), theValue->scalar()))); + aConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintCurveValue( + *thePoint->point(), thePoint->point()->y, *theEntity->entity(), theValue->scalar()))); + return ConstraintWrapperPtr(new PlaneGCSSolver_ConstraintWrapper(aConstraints, theType)); + } default: return ConstraintWrapperPtr(); } @@ -813,6 +827,23 @@ GCS::SET_pD ellipticArcParameters(const EdgeWrapperPtr& theEllipticArc) return aParams; } +GCS::SET_pD bsplineParameters(const EdgeWrapperPtr& theEdge) +{ + GCS::SET_pD aParams; + + std::shared_ptr aBSpline = + std::dynamic_pointer_cast(theEdge->entity()); + + for (GCS::VEC_P::iterator it = aBSpline->poles.begin(); it != aBSpline->poles.end(); ++it) { + aParams.insert(it->x); + aParams.insert(it->y); + } + for (GCS::VEC_pD::iterator it = aBSpline->weights.begin(); it != aBSpline->weights.end(); ++it) + aParams.insert(*it); + + return aParams; +} + double distance(const GCS::Point& thePnt1, const GCS::Point& thePnt2) { double x = *thePnt1.x - *thePnt2.x; diff --git a/src/SketchSolver/SketchSolver_ConstraintCoincidence.cpp b/src/SketchSolver/SketchSolver_ConstraintCoincidence.cpp index f4b616b9e..990297396 100644 --- a/src/SketchSolver/SketchSolver_ConstraintCoincidence.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintCoincidence.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -224,7 +225,7 @@ void SketchSolver_ConstraintCoincidence::process() mySolverConstraint = PlaneGCSSolver_Tools::createConstraint( myBaseConstraint, getType(), - aValue, anAttributes[0], anAttributes[1], anAttributes[2], anAttributes[3]); + myAuxValue, anAttributes[0], anAttributes[1], anAttributes[2], anAttributes[3]); myStorage->subscribeUpdates(this, PlaneGCSSolver_UpdateCoincidence::GROUP()); myStorage->notify(myBaseConstraint); @@ -235,6 +236,13 @@ bool SketchSolver_ConstraintCoincidence::remove() myInSolver = false; myFeatureExtremities[0] = EntityWrapperPtr(); myFeatureExtremities[1] = EntityWrapperPtr(); + if (myAuxValue) { + std::shared_ptr aStorage = + std::dynamic_pointer_cast(myStorage); + GCS::SET_pD aParams; + aParams.insert(myAuxValue->scalar()); + aStorage->removeParameters(aParams); + } return SketchSolver_Constraint::remove(); } @@ -257,8 +265,16 @@ void SketchSolver_ConstraintCoincidence::getAttributes( theAttributes, myFeatureExtremities); } else if (theAttributes[2]) { myType = CONSTRAINT_PT_ON_CURVE; - // obtain extremity points of the coincident feature for further checking of multi-coincidence - getCoincidentFeatureExtremities(myBaseConstraint, myStorage, myFeatureExtremities); + // point-on-bspline requires additional parameter + if (theAttributes[2]->type() == ENTITY_BSPLINE) { + std::shared_ptr aStorage = + std::dynamic_pointer_cast(myStorage); + myAuxValue.reset(new PlaneGCSSolver_ScalarWrapper(aStorage->createParameter())); + } + else { + // obtain extremity points of the coincident feature for further checking of multi-coincidence + getCoincidentFeatureExtremities(myBaseConstraint, myStorage, myFeatureExtremities); + } } else myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE(); diff --git a/src/SketchSolver/SketchSolver_ConstraintCoincidence.h b/src/SketchSolver/SketchSolver_ConstraintCoincidence.h index 871314b92..f520b75d0 100644 --- a/src/SketchSolver/SketchSolver_ConstraintCoincidence.h +++ b/src/SketchSolver/SketchSolver_ConstraintCoincidence.h @@ -55,6 +55,7 @@ protected: protected: bool myInSolver; ///< shows the constraint is added to the solver EntityWrapperPtr myFeatureExtremities[2]; ///< extremities of a feature, a point is coincident to + ScalarWrapperPtr myAuxValue; ///< parameter on B-spline curve }; #endif -- 2.39.2