From 7b9662e1e63565ccfb95255f2b154d53357d091e Mon Sep 17 00:00:00 2001 From: azv Date: Fri, 10 Jan 2020 13:36:22 +0300 Subject: [PATCH] Issue #17347: B-Splines in Sketcher Projection of B-splines --- src/GeomAPI/CMakeLists.txt | 2 + src/GeomAPI/GeomAPI_BSpline.cpp | 73 +++ src/GeomAPI/GeomAPI_BSpline.h | 60 +++ src/GeomAPI/GeomAPI_BSpline2d.cpp | 73 ++- src/GeomAPI/GeomAPI_BSpline2d.h | 12 +- src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.cpp | 13 +- src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.h | 8 +- src/SketchPlugin/SketchPlugin_BSpline.cpp | 29 +- src/SketchPlugin/SketchPlugin_BSpline.h | 14 + .../SketchPlugin_MacroBSpline.cpp | 21 +- src/SketchPlugin/SketchPlugin_MacroBSpline.h | 2 + src/SketchPlugin/SketchPlugin_Projection.cpp | 446 ++++++++++++------ src/SketchPlugin/SketchPlugin_Projection.h | 30 ++ src/SketchPlugin/SketchPlugin_Validators.cpp | 13 +- .../PlaneGCSSolver_AttributeBuilder.cpp | 42 +- .../PlaneGCSSolver_FeatureBuilder.cpp | 21 +- .../PlaneGCSSolver_GeoExtensions.cpp | 8 +- .../PlaneGCSSolver_GeoExtensions.h | 2 + 18 files changed, 653 insertions(+), 216 deletions(-) create mode 100644 src/GeomAPI/GeomAPI_BSpline.cpp create mode 100644 src/GeomAPI/GeomAPI_BSpline.h diff --git a/src/GeomAPI/CMakeLists.txt b/src/GeomAPI/CMakeLists.txt index 0fda17637..267c703a9 100644 --- a/src/GeomAPI/CMakeLists.txt +++ b/src/GeomAPI/CMakeLists.txt @@ -25,6 +25,7 @@ INCLUDE(UnitTest) SET(PROJECT_HEADERS GeomAPI.h + GeomAPI_BSpline.h GeomAPI_BSpline2d.h GeomAPI_Circ.h GeomAPI_Circ2d.h @@ -72,6 +73,7 @@ SET(PROJECT_HEADERS ) SET(PROJECT_SOURCES + GeomAPI_BSpline.cpp GeomAPI_BSpline2d.cpp GeomAPI_Circ.cpp GeomAPI_Circ2d.cpp diff --git a/src/GeomAPI/GeomAPI_BSpline.cpp b/src/GeomAPI/GeomAPI_BSpline.cpp new file mode 100644 index 000000000..f73076908 --- /dev/null +++ b/src/GeomAPI/GeomAPI_BSpline.cpp @@ -0,0 +1,73 @@ +// 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 + +#define MY_BSPLINE (*(implPtr())) + +GeomAPI_BSpline::GeomAPI_BSpline(const GeomCurvePtr& theCurve) +{ + GeomCurvePtr anUntrimmedCurve = theCurve->basisCurve(); + Handle(Geom_Curve) aCurve = anUntrimmedCurve->impl(); + Handle(Geom_BSplineCurve) aBSpl = Handle(Geom_BSplineCurve)::DownCast(aCurve); + if (aBSpl.IsNull()) + throw Standard_ConstructionError("GeomAPI_BSpline: Curve is not a B-spline"); + setImpl(new Handle_Geom_BSplineCurve(aBSpl)); +} + +int GeomAPI_BSpline::degree() const +{ + return MY_BSPLINE->Degree(); +} + +std::list GeomAPI_BSpline::poles() const +{ + const TColgp_Array1OfPnt& aBSplPoles = MY_BSPLINE->Poles(); + + std::list aPoles; + for (int anIndex = aBSplPoles.Lower(); anIndex <= aBSplPoles.Upper(); ++anIndex) { + const gp_Pnt& aPoint = aBSplPoles.Value(anIndex); + aPoles.push_back(GeomPointPtr(new GeomAPI_Pnt(aPoint.X(), aPoint.Y(), aPoint.Z()))); + } + return aPoles; +} + +std::list GeomAPI_BSpline::weights() const +{ + std::list aWeights; + const TColStd_Array1OfReal* aBSplWeights = MY_BSPLINE->Weights(); + if (aBSplWeights) + aWeights.assign(aBSplWeights->begin(), aBSplWeights->end()); + return aWeights; +} + +std::list GeomAPI_BSpline::knots() const +{ + const TColStd_Array1OfReal& aBSplKnots = MY_BSPLINE->Knots(); + return std::list(aBSplKnots.begin(), aBSplKnots.end()); +} + +std::list GeomAPI_BSpline::mults() const +{ + const TColStd_Array1OfInteger& aBSplMults = MY_BSPLINE->Multiplicities(); + return std::list(aBSplMults.begin(), aBSplMults.end()); +} diff --git a/src/GeomAPI/GeomAPI_BSpline.h b/src/GeomAPI/GeomAPI_BSpline.h new file mode 100644 index 000000000..ae067d0fa --- /dev/null +++ b/src/GeomAPI/GeomAPI_BSpline.h @@ -0,0 +1,60 @@ +// 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_BSpline_H_ +#define GeomAPI_BSpline_H_ + +#include +#include + +#include +#include + +class GeomAPI_Pnt; + +/**\class GeomAPI_BSpline + * \ingroup DataModel + * \brief B-spline in 3D + */ +class GeomAPI_BSpline : public GeomAPI_Interface +{ +public: + /// Creation of B-spline defined by a curve + GEOMAPI_EXPORT GeomAPI_BSpline(const GeomCurvePtr& theCurve); + + /// Degree of B-spline curve + GEOMAPI_EXPORT int degree() const; + + /// Poles of B-spline curve + GEOMAPI_EXPORT std::list > poles() const; + + /// Weights of B-spline poles + GEOMAPI_EXPORT std::list weights() const; + + /// Knots of B-spline curve + GEOMAPI_EXPORT std::list knots() const; + + /// Multiplicities of B-spline knots + GEOMAPI_EXPORT std::list mults() const; +}; + +//! Pointer on the object +typedef std::shared_ptr GeomBSplinePtr; + +#endif diff --git a/src/GeomAPI/GeomAPI_BSpline2d.cpp b/src/GeomAPI/GeomAPI_BSpline2d.cpp index ca5e18914..de07f9299 100644 --- a/src/GeomAPI/GeomAPI_BSpline2d.cpp +++ b/src/GeomAPI/GeomAPI_BSpline2d.cpp @@ -29,18 +29,16 @@ static Handle_Geom2d_BSplineCurve* newBSpline2d( const std::list >& thePoles, const std::list& theWeights, + const std::list& theKnots, + const std::list& theMults, 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); + TColStd_Array1OfReal aKnots(1, (int)theKnots.size()); + TColStd_Array1OfInteger aMults(1, (int)theMults.size()); int anIndex = 1; for (std::list::const_iterator aPIt = thePoles.begin(); @@ -51,21 +49,43 @@ static Handle_Geom2d_BSplineCurve* newBSpline2d( aWIt != theWeights.end(); ++aWIt, ++anIndex) aWeights.SetValue(anIndex, *aWIt); anIndex = 1; + for (std::list::const_iterator aKIt = theKnots.begin(); + aKIt != theKnots.end(); ++aKIt, ++anIndex) + aKnots.SetValue(anIndex, *aKIt); + anIndex = 1; + for (std::list::const_iterator aMIt = theMults.begin(); + aMIt != theMults.end(); ++aMIt, ++anIndex) + aMults.SetValue(anIndex, *aMIt); + + 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 int theDegree, + const bool thePeriodic) +{ + int aNbKnots = (int)thePoles.size() - theDegree + 1; + if (aNbKnots < 2) + return new Handle_Geom2d_BSplineCurve(); + static const double aStartParam = 0.0; static const double aEndParam = 1.0; double aStep = aEndParam / (aNbKnots - 1); + int anIndex = 1; + std::list aKnots; 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); + aKnots.push_back(aKnot); + aKnots.push_back(aEndParam); - Handle(Geom2d_BSplineCurve) aCurve = - new Geom2d_BSplineCurve(aPoles, aWeights, aKnots, aMults, theDegree, thePeriodic); - return new Handle_Geom2d_BSplineCurve(aCurve); + std::list aMults(aNbKnots - 2, 1); + aMults.push_front(theDegree + 1); + aMults.push_back(theDegree + 1); + + return newBSpline2d(thePoles, theWeights, aKnots, aMults, theDegree, thePeriodic); } static Handle_Geom2d_BSplineCurve* newBSpline2d( @@ -91,11 +111,14 @@ GeomAPI_BSpline2d::GeomAPI_BSpline2d(const std::list >& thePoles, +GeomAPI_BSpline2d::GeomAPI_BSpline2d(const int theDegree, + const std::list >& thePoles, const std::list& theWeights, - const int theDegree, + const std::list& theKnots, + const std::list& theMults, const bool thePeriodic) - : GeomAPI_Interface(newBSpline2d(thePoles, theWeights, theDegree, thePeriodic)) + : GeomAPI_Interface(newBSpline2d(thePoles, theWeights, theKnots, theMults, + theDegree, thePeriodic)) { if (isNull()) throw Standard_ConstructionError("GeomAPI_BSpline2d: Impossible to create B-spline curve"); @@ -111,6 +134,18 @@ int GeomAPI_BSpline2d::degree() const return MY_BSPLINE->Degree(); } +std::list GeomAPI_BSpline2d::knots() const +{ + const TColStd_Array1OfReal& aBSplKnots = MY_BSPLINE->Knots(); + return std::list(aBSplKnots.begin(), aBSplKnots.end()); +} + +std::list GeomAPI_BSpline2d::mults() const +{ + const TColStd_Array1OfInteger& aBSplMults = MY_BSPLINE->Multiplicities(); + return std::list(aBSplMults.begin(), aBSplMults.end()); +} + void GeomAPI_BSpline2d::D0(const double theU, std::shared_ptr& thePoint) { gp_Pnt2d aPnt; diff --git a/src/GeomAPI/GeomAPI_BSpline2d.h b/src/GeomAPI/GeomAPI_BSpline2d.h index 290458693..0960bd403 100644 --- a/src/GeomAPI/GeomAPI_BSpline2d.h +++ b/src/GeomAPI/GeomAPI_BSpline2d.h @@ -41,9 +41,11 @@ public: const bool thePeriodic = false); /// Creation of B-spline curve defined by list of poles and weights - GEOMAPI_EXPORT GeomAPI_BSpline2d(const std::list >& thePoles, + GEOMAPI_EXPORT GeomAPI_BSpline2d(const int theDegree, + const std::list >& thePoles, const std::list& theWeights, - const int theDegree, + const std::list& theKnots = std::list(), + const std::list& theMults = std::list(), const bool thePeriodic = false); /// Returns true if curve is not initialized @@ -52,6 +54,12 @@ public: /// Returns degree of the curve GEOMAPI_EXPORT int degree() const; + /// Knots of the curve + GEOMAPI_EXPORT std::list knots() const; + + /// Multiplicities of the knots + GEOMAPI_EXPORT std::list mults() const; + /// \brief Calculate point on B-spline curve accrding to the given parameter GEOMAPI_EXPORT void D0(const double theU, std::shared_ptr& thePoint); diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.cpp index 03145a117..3badacb17 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.cpp +++ b/src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.cpp @@ -20,9 +20,9 @@ #include #include +#include #include #include -#include #include #include @@ -273,21 +273,24 @@ std::shared_ptr GeomAlgoAPI_EdgeBuilder::ellipticArc( } GeomEdgePtr GeomAlgoAPI_EdgeBuilder::bsplineOnPlane( - const std::shared_ptr& thePlane, + const std::shared_ptr& thePlane, const std::list& thePoles, const std::list& theWeights, + const std::list& theKnots, + const std::list& theMults, + const int theDegree, const bool thePeriodic) { std::shared_ptr aBSplineCurve( - new GeomAPI_BSpline2d(thePoles, theWeights, thePeriodic)); + new GeomAPI_BSpline2d(theDegree, thePoles, theWeights, theKnots, theMults, thePeriodic)); return bsplineOnPlane(thePlane, aBSplineCurve); } GeomEdgePtr GeomAlgoAPI_EdgeBuilder::bsplineOnPlane( - const std::shared_ptr& thePlane, + const std::shared_ptr& thePlane, const std::shared_ptr& theCurve) { - Handle(Geom_Curve) aCurve3D = GeomLib::To3d(thePlane->impl().Position().Ax2(), + Handle(Geom_Curve) aCurve3D = GeomLib::To3d(thePlane->impl().Ax2(), theCurve->impl()); BRepBuilderAPI_MakeEdge anEdgeBuilder(aCurve3D); diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.h b/src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.h index ac4ca0286..3b6a8c760 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.h +++ b/src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.h @@ -29,6 +29,7 @@ #include #include +class GeomAPI_Ax3; class GeomAPI_BSpline2d; /**\class GeomAlgoAPI_EdgeBuilder @@ -94,13 +95,16 @@ class GEOMALGOAPI_EXPORT GeomAlgoAPI_EdgeBuilder const std::shared_ptr& theEnd); /// Creates planar B-spline edge - static GeomEdgePtr bsplineOnPlane(const std::shared_ptr& thePlane, + static GeomEdgePtr bsplineOnPlane(const std::shared_ptr& thePlane, const std::list >& thePoles, const std::list& theWeights, + const std::list& theKnots, + const std::list& theMults, + const int theDegree, const bool thePeriodic); /// Creates planar B-spline edge - static GeomEdgePtr bsplineOnPlane(const std::shared_ptr& thePlane, + static GeomEdgePtr bsplineOnPlane(const std::shared_ptr& thePlane, const std::shared_ptr& theCurve); }; diff --git a/src/SketchPlugin/SketchPlugin_BSpline.cpp b/src/SketchPlugin/SketchPlugin_BSpline.cpp index 64fa4fcac..89090e4fe 100644 --- a/src/SketchPlugin/SketchPlugin_BSpline.cpp +++ b/src/SketchPlugin/SketchPlugin_BSpline.cpp @@ -22,27 +22,17 @@ #include -////#include -////#include -////#include -////#include #include -////#include #include #include +#include #include #include #include #include -////#include -//// -////static const double tolerance = 1e-7; -////static const double paramTolerance = 1.e-4; -////static const double PI = 3.141592653589793238463; - SketchPlugin_BSpline::SketchPlugin_BSpline() : SketchPlugin_SketchEntity() @@ -53,6 +43,8 @@ void SketchPlugin_BSpline::initDerivedClassAttributes() { data()->addAttribute(POLES_ID(), GeomDataAPI_Point2DArray::typeId()); data()->addAttribute(WEIGHTS_ID(), ModelAPI_AttributeDoubleArray::typeId()); + data()->addAttribute(KNOTS_ID(), ModelAPI_AttributeDoubleArray::typeId()); + data()->addAttribute(MULTS_ID(), ModelAPI_AttributeIntArray::typeId()); data()->addAttribute(DEGREE_ID(), ModelAPI_AttributeInteger::typeId()); data()->addAttribute(EXTERNAL_ID(), ModelAPI_AttributeSelection::typeId()); @@ -69,6 +61,9 @@ void SketchPlugin_BSpline::execute() AttributePoint2DArrayPtr aPolesArray = std::dynamic_pointer_cast(attribute(POLES_ID())); AttributeDoubleArrayPtr aWeightsArray = data()->realArray(WEIGHTS_ID()); + AttributeDoubleArrayPtr aKnotsArray = data()->realArray(KNOTS_ID()); + AttributeIntArrayPtr aMultsArray = data()->intArray(MULTS_ID()); + AttributeIntegerPtr aDegreeAttr = data()->integer(DEGREE_ID()); // collect poles std::list aPoles2D; @@ -80,10 +75,18 @@ void SketchPlugin_BSpline::execute() std::list aWeights; for (int anIndex = 0; anIndex < aWeightsArray->size(); ++anIndex) aWeights.push_back(aWeightsArray->value(anIndex)); + // collect knots + std::list aKnots; + for (int anIndex = 0; anIndex < aKnotsArray->size(); ++anIndex) + aKnots.push_back(aKnotsArray->value(anIndex)); + // collect multiplicities + std::list aMults; + for (int anIndex = 0; anIndex < aMultsArray->size(); ++anIndex) + aMults.push_back(aMultsArray->value(anIndex)); // create result non-periodic B-spline curve - GeomShapePtr anEdge = - GeomAlgoAPI_EdgeBuilder::bsplineOnPlane(aSketch->plane(), aPoles2D, aWeights, false); + GeomShapePtr anEdge = GeomAlgoAPI_EdgeBuilder::bsplineOnPlane(aSketch->coordinatePlane(), + aPoles2D, aWeights, aKnots, aMults, aDegreeAttr->value(), 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 303dc1f0b..5a99005f0 100644 --- a/src/SketchPlugin/SketchPlugin_BSpline.h +++ b/src/SketchPlugin/SketchPlugin_BSpline.h @@ -58,6 +58,20 @@ public: return ID; } + /// list of B-spline knots + inline static const std::string& KNOTS_ID() + { + static const std::string ID("knots"); + return ID; + } + + /// list of B-spline multiplicities + inline static const std::string& MULTS_ID() + { + static const std::string ID("multiplicities"); + 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 0b81547a3..b1701c1b7 100644 --- a/src/SketchPlugin/SketchPlugin_MacroBSpline.cpp +++ b/src/SketchPlugin/SketchPlugin_MacroBSpline.cpp @@ -157,6 +157,22 @@ FeaturePtr SketchPlugin_MacroBSpline::createBSplineFeature() for (int index = 0; index < aSize; ++index) aWeights->setValue(index, aWeightsMacro->value(index)); + AttributeDoubleArrayPtr aKnots = + aBSpline->data()->realArray(SketchPlugin_BSpline::KNOTS_ID()); + aSize = (int)myKnots.size(); + aKnots->setSize(aSize); + std::list::iterator aKIt = myKnots.begin(); + for (int index = 0; index < aSize; ++index, ++aKIt) + aKnots->setValue(index, *aKIt); + + AttributeIntArrayPtr aMults = + aBSpline->data()->intArray(SketchPlugin_BSpline::MULTS_ID()); + aSize = (int)myMultiplicities.size(); + aMults->setSize(aSize); + std::list::iterator aMIt = myMultiplicities.begin(); + for (int index = 0; index < aSize; ++index, ++aMIt) + aMults->setValue(index, *aMIt); + aBSpline->boolean(SketchPlugin_BSpline::AUXILIARY_ID())->setValue( boolean(AUXILIARY_ID())->value()); @@ -248,11 +264,14 @@ AISObjectPtr SketchPlugin_MacroBSpline::getAISObject(AISObjectPtr thePrevious) return AISObjectPtr(); } GeomShapePtr anEdge = - GeomAlgoAPI_EdgeBuilder::bsplineOnPlane(aSketch->plane(), aBSplineCurve); + GeomAlgoAPI_EdgeBuilder::bsplineOnPlane(aSketch->coordinatePlane(), aBSplineCurve); if (!anEdge) return AISObjectPtr(); + // store transient parameters of B-spline curve myDegree = aBSplineCurve->degree(); + myKnots = aBSplineCurve->knots(); + myMultiplicities = aBSplineCurve->mults(); 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 0137962ed..7515cadb5 100644 --- a/src/SketchPlugin/SketchPlugin_MacroBSpline.h +++ b/src/SketchPlugin/SketchPlugin_MacroBSpline.h @@ -104,6 +104,8 @@ private: void createControlPolygon(FeaturePtr theBSpline, std::list& thePoles); void constraintsForPoles(const std::list& thePoles); + std::list myKnots; + std::list myMultiplicities; int myDegree; bool myIsPeriodic; }; diff --git a/src/SketchPlugin/SketchPlugin_Projection.cpp b/src/SketchPlugin/SketchPlugin_Projection.cpp index e04031fee..e041299b0 100644 --- a/src/SketchPlugin/SketchPlugin_Projection.cpp +++ b/src/SketchPlugin/SketchPlugin_Projection.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -31,6 +32,8 @@ #include #include #include +#include +#include #include #include #include @@ -39,6 +42,7 @@ #include +#include #include #include #include @@ -49,6 +53,7 @@ #include #include #include +#include #include @@ -145,6 +150,14 @@ static const std::set& ARC_PROJECTION() return aProj; } +static const std::set& BSPLINE_PROJECTION() +{ + static std::set aProj; + if (aProj.empty()) + aProj.insert(SketchPlugin_BSpline::ID()); + return aProj; +} + static const std::set& possibleProjectionTypes(GeomEdgePtr theEdge, GeomVertexPtr theVertex) @@ -160,6 +173,8 @@ static const std::set& possibleProjectionTypes(GeomEdgePtr theEdge, else return ARC_PROJECTION(); } + else + return BSPLINE_PROJECTION(); } static const std::set DUMMY; return DUMMY; @@ -196,8 +211,6 @@ void SketchPlugin_Projection::computeProjection(const std::string& theID) // if the type of feature differs with already selected, remove it and create once again bool isRebuild = rebuildProjectedFeature(aProjection, aProjType); - std::shared_ptr aSketchPlane = sketch()->plane(); - ResultConstructionPtr aResult = std::dynamic_pointer_cast(lastResult()); if (!isRebuild && aResult && aResult->shape() && theID == EXTERNAL_FEATURE_ID()) { @@ -208,158 +221,14 @@ void SketchPlugin_Projection::computeProjection(const std::string& theID) keepCurrentFeature(); - if (aVertex) { - std::shared_ptr aPrjPnt = aSketchPlane->project(aVertex->point()); - std::shared_ptr aPntInSketch = sketch()->to2D(aPrjPnt); - - rebuildProjectedFeature(aProjection, POINT_PROJECTION(), SketchPlugin_Point::ID()); + bool isProjected = false; + if (aVertex) + isProjected = projectPoint(aProjection, aVertex->point()); + else + isProjected = projectEdge(aProjection, anEdge); - // update coordinates of projection - std::dynamic_pointer_cast( - aProjection->attribute(SketchPlugin_Point::COORD_ID()))->setValue(aPntInSketch); - } - else if (anEdge->isLine()) { - std::shared_ptr aFirst = aSketchPlane->project(anEdge->firstPoint()); - std::shared_ptr aLast = aSketchPlane->project(anEdge->lastPoint()); - - std::shared_ptr aFirstInSketch = sketch()->to2D(aFirst); - std::shared_ptr aLastInSketch = sketch()->to2D(aLast); - if (aFirstInSketch->distance(aLastInSketch) < tolerance) - return; // line is semi-orthogonal to the sketch plane - - rebuildProjectedFeature(aProjection, LINE_PROJECTION(), SketchPlugin_Line::ID()); - - // update attributes of projection - std::shared_ptr aStartPnt = std::dynamic_pointer_cast( - aProjection->attribute(SketchPlugin_Line::START_ID())); - std::shared_ptr aEndPnt = std::dynamic_pointer_cast( - aProjection->attribute(SketchPlugin_Line::END_ID())); - aStartPnt->setValue(aFirstInSketch); - aEndPnt->setValue(aLastInSketch); - } - else if (anEdge->isCircle() || anEdge->isArc() || anEdge->isEllipse()) { - GeomAlgoAPI_Projection aProjAlgo(aSketchPlane); - GeomCurvePtr aProjectedCurve = aProjAlgo.project(anEdge); - - if (aProjectedCurve->isCircle()) { - GeomAPI_Circ aCircle(aProjectedCurve); - GeomPointPtr aCenter = aSketchPlane->project(aCircle.center()); - GeomPnt2dPtr aCenterInSketch = sketch()->to2D(aCenter); - - if (aProjectedCurve->isTrimmed()) { - // ARC is a projection - rebuildProjectedFeature(aProjection, ARC_PROJECTION(), SketchPlugin_Arc::ID()); - - GeomPointPtr aFirst = aProjectedCurve->getPoint(aProjectedCurve->startParam()); - GeomPointPtr aLast = aProjectedCurve->getPoint(aProjectedCurve->endParam()); - GeomPnt2dPtr aFirstInSketch = sketch()->to2D(aSketchPlane->project(aFirst)); - GeomPnt2dPtr aLastInSketch = sketch()->to2D(aSketchPlane->project(aLast)); - - double aNormalsDot = aCircle.normal()->dot(aSketchPlane->direction()); - if (fabs(fabs(aNormalsDot) - 1.0) > tolerance) - return; // arc is not in the plane, parallel to the sketch plane - - bool isInversed = aNormalsDot < 0.; - - bool aWasBlocked = aProjection->data()->blockSendAttributeUpdated(true); - - // update attributes of projection - std::shared_ptr aCenterPnt = - std::dynamic_pointer_cast( - aProjection->attribute(SketchPlugin_Arc::CENTER_ID())); - std::shared_ptr aStartPnt = - std::dynamic_pointer_cast( - aProjection->attribute(SketchPlugin_Arc::START_ID())); - std::shared_ptr aEndPnt = - std::dynamic_pointer_cast( - aProjection->attribute(SketchPlugin_Arc::END_ID())); - aStartPnt->setValue(aFirstInSketch); - aEndPnt->setValue(aLastInSketch); - aCenterPnt->setValue(aCenterInSketch); - aProjection->boolean(SketchPlugin_Arc::REVERSED_ID())->setValue(isInversed); - - aProjection->data()->blockSendAttributeUpdated(aWasBlocked); - } - else { - // CIRCLE is a projection - rebuildProjectedFeature(aProjection, CIRCLE_ELLIPSE_PROJECTION(), - SketchPlugin_Circle::ID()); - - // update attributes of projection - std::shared_ptr aCenterPnt = - std::dynamic_pointer_cast( - aProjection->attribute(SketchPlugin_Circle::CENTER_ID())); - aCenterPnt->setValue(aCenterInSketch); - aProjection->real(SketchPlugin_Circle::RADIUS_ID())->setValue(aCircle.radius()); - } - } - else if (aProjectedCurve->isEllipse()) { - GeomAPI_Ellipse anEllipse(aProjectedCurve); - GeomPointPtr aCenter = aSketchPlane->project(anEllipse.center()); - GeomPnt2dPtr aCenterInSketch = sketch()->to2D(aCenter); - GeomPointPtr aFocus = aSketchPlane->project(anEllipse.firstFocus()); - GeomPnt2dPtr aFocusInSketch = sketch()->to2D(aFocus); - - if (aProjectedCurve->isTrimmed()) { - // ELLIPTIC ARC is a projection - rebuildProjectedFeature(aProjection, ARC_PROJECTION(), SketchPlugin_EllipticArc::ID()); - - GeomPointPtr aFirst = aProjectedCurve->getPoint(aProjectedCurve->startParam()); - GeomPointPtr aLast = aProjectedCurve->getPoint(aProjectedCurve->endParam()); - GeomPnt2dPtr aFirstInSketch = sketch()->to2D(aSketchPlane->project(aFirst)); - GeomPnt2dPtr aLastInSketch = sketch()->to2D(aSketchPlane->project(aLast)); - - double aNormalsDot = anEllipse.normal()->dot(aSketchPlane->direction()); - if (fabs(fabs(aNormalsDot) - 1.0) > tolerance) - return; // arc is not in the plane, parallel to the sketch plane - - bool isInversed = aNormalsDot < 0.; - - bool aWasBlocked = aProjection->data()->blockSendAttributeUpdated(true); - - // update attributes of projection - std::shared_ptr aCenterPnt = - std::dynamic_pointer_cast( - aProjection->attribute(SketchPlugin_EllipticArc::CENTER_ID())); - std::shared_ptr aFocusPnt = - std::dynamic_pointer_cast( - aProjection->attribute(SketchPlugin_EllipticArc::FIRST_FOCUS_ID())); - std::shared_ptr aStartPnt = - std::dynamic_pointer_cast( - aProjection->attribute(SketchPlugin_EllipticArc::START_POINT_ID())); - std::shared_ptr aEndPnt = - std::dynamic_pointer_cast( - aProjection->attribute(SketchPlugin_EllipticArc::END_POINT_ID())); - aStartPnt->setValue(aFirstInSketch); - aEndPnt->setValue(aLastInSketch); - aCenterPnt->setValue(aCenterInSketch); - aFocusPnt->setValue(aFocusInSketch); - aProjection->boolean(SketchPlugin_EllipticArc::REVERSED_ID())->setValue(isInversed); - - aProjection->data()->blockSendAttributeUpdated(aWasBlocked); - } - else { - // ELLIPSE is a projection - rebuildProjectedFeature(aProjection, CIRCLE_ELLIPSE_PROJECTION(), - SketchPlugin_Ellipse::ID()); - - // update attributes of projection - std::shared_ptr aCenterPnt = - std::dynamic_pointer_cast( - aProjection->attribute(SketchPlugin_Ellipse::CENTER_ID())); - aCenterPnt->setValue(aCenterInSketch); - std::shared_ptr aFocusPnt = - std::dynamic_pointer_cast( - aProjection->attribute(SketchPlugin_Ellipse::FIRST_FOCUS_ID())); - aFocusPnt->setValue(aFocusInSketch); - aProjection->real(SketchPlugin_Ellipse::MINOR_RADIUS_ID())->setValue( - anEllipse.minorRadius()); - } - } - else - return; - } else - return; + if (!isProjected) + return; // projection is not computed, stop processing aProjection->boolean(COPY_ID())->setValue(true); aProjection->execute(); @@ -407,3 +276,274 @@ bool SketchPlugin_Projection::rebuildProjectedFeature( theProjection = sketch()->addFeature(theRequestedFeature); return isRebuild; } + +bool SketchPlugin_Projection::projectPoint(FeaturePtr& theProjection, const GeomPointPtr& thePoint) +{ + std::shared_ptr aSketchPlane = sketch()->plane(); + + std::shared_ptr aPrjPnt = aSketchPlane->project(thePoint); + std::shared_ptr aPntInSketch = sketch()->to2D(aPrjPnt); + + rebuildProjectedFeature(theProjection, POINT_PROJECTION(), SketchPlugin_Point::ID()); + + // update coordinates of projection + std::dynamic_pointer_cast( + theProjection->attribute(SketchPlugin_Point::COORD_ID()))->setValue(aPntInSketch); + return true; +} + +bool SketchPlugin_Projection::projectSegment(FeaturePtr& theProjection, const GeomEdgePtr& theEdge) +{ + std::shared_ptr aSketchPlane = sketch()->plane(); + + std::shared_ptr aFirst = aSketchPlane->project(theEdge->firstPoint()); + std::shared_ptr aLast = aSketchPlane->project(theEdge->lastPoint()); + + std::shared_ptr aFirstInSketch = sketch()->to2D(aFirst); + std::shared_ptr aLastInSketch = sketch()->to2D(aLast); + if (aFirstInSketch->distance(aLastInSketch) < tolerance) + return false; // line is semi-orthogonal to the sketch plane + + rebuildProjectedFeature(theProjection, LINE_PROJECTION(), SketchPlugin_Line::ID()); + + // update attributes of projection + std::shared_ptr aStartPnt = std::dynamic_pointer_cast( + theProjection->attribute(SketchPlugin_Line::START_ID())); + std::shared_ptr aEndPnt = std::dynamic_pointer_cast( + theProjection->attribute(SketchPlugin_Line::END_ID())); + aStartPnt->setValue(aFirstInSketch); + aEndPnt->setValue(aLastInSketch); + + return true; +} + +bool SketchPlugin_Projection::projectEdge(FeaturePtr& theProjection, const GeomEdgePtr& theEdge) +{ + if (theEdge->isLine()) + return projectSegment(theProjection, theEdge); + + std::shared_ptr aSketchPlane = sketch()->plane(); + + GeomAlgoAPI_Projection aProjAlgo(aSketchPlane); + GeomCurvePtr aProjectedCurve = aProjAlgo.project(theEdge); + + bool isOk = false; + if (aProjectedCurve->isCircle()) { + if (aProjectedCurve->isTrimmed()) { + // ARC is a projection + isOk = fillArc(theProjection, aProjectedCurve, aSketchPlane); + } + else { + // CIRCLE is a projection + isOk = fillCircle(theProjection, aProjectedCurve, aSketchPlane); + } + } + else if (aProjectedCurve->isEllipse()) { + if (aProjectedCurve->isTrimmed()) { + // ELLIPTIC ARC is a projection + isOk = fillEllipticArc(theProjection, aProjectedCurve, aSketchPlane); + } + else { + // ELLIPSE is a projection + isOk = fillEllipse(theProjection, aProjectedCurve, aSketchPlane); + } + } + else + isOk = fillBSpline(theProjection, aProjectedCurve, aSketchPlane); + + return isOk; +} + +bool SketchPlugin_Projection::fillArc(FeaturePtr& theProjection, + const GeomCurvePtr& theArc, + const GeomPlanePtr& thePlane) +{ + rebuildProjectedFeature(theProjection, ARC_PROJECTION(), SketchPlugin_Arc::ID()); + + GeomAPI_Circ aCircle(theArc); + + double aNormalsDot = aCircle.normal()->dot(thePlane->direction()); + if (fabs(fabs(aNormalsDot) - 1.0) > tolerance) + return false; // arc is not in the plane, parallel to the sketch plane + + bool isInversed = aNormalsDot < 0.; + + GeomPointPtr aCenter = thePlane->project(aCircle.center()); + GeomPnt2dPtr aCenterInSketch = sketch()->to2D(aCenter); + + GeomPointPtr aFirst = theArc->getPoint(theArc->startParam()); + GeomPnt2dPtr aFirstInSketch = sketch()->to2D(thePlane->project(aFirst)); + + GeomPointPtr aLast = theArc->getPoint(theArc->endParam()); + GeomPnt2dPtr aLastInSketch = sketch()->to2D(thePlane->project(aLast)); + + bool aWasBlocked = theProjection->data()->blockSendAttributeUpdated(true); + + // update attributes of projection + std::shared_ptr aCenterPnt = + std::dynamic_pointer_cast( + theProjection->attribute(SketchPlugin_Arc::CENTER_ID())); + std::shared_ptr aStartPnt = + std::dynamic_pointer_cast( + theProjection->attribute(SketchPlugin_Arc::START_ID())); + std::shared_ptr aEndPnt = + std::dynamic_pointer_cast( + theProjection->attribute(SketchPlugin_Arc::END_ID())); + aStartPnt->setValue(aFirstInSketch); + aEndPnt->setValue(aLastInSketch); + aCenterPnt->setValue(aCenterInSketch); + theProjection->boolean(SketchPlugin_Arc::REVERSED_ID())->setValue(isInversed); + + theProjection->data()->blockSendAttributeUpdated(aWasBlocked); + return true; +} + +bool SketchPlugin_Projection::fillCircle(FeaturePtr& theProjection, + const GeomCurvePtr& theCircle, + const GeomPlanePtr& thePlane) +{ + rebuildProjectedFeature(theProjection, CIRCLE_ELLIPSE_PROJECTION(), SketchPlugin_Circle::ID()); + + GeomAPI_Circ aCircle(theCircle); + GeomPointPtr aCenter = thePlane->project(aCircle.center()); + GeomPnt2dPtr aCenterInSketch = sketch()->to2D(aCenter); + + // update attributes of projection + std::shared_ptr aCenterPnt = + std::dynamic_pointer_cast( + theProjection->attribute(SketchPlugin_Circle::CENTER_ID())); + aCenterPnt->setValue(aCenterInSketch); + theProjection->real(SketchPlugin_Circle::RADIUS_ID())->setValue(aCircle.radius()); + return true; +} + +bool SketchPlugin_Projection::fillEllipse(FeaturePtr& theProjection, + const GeomCurvePtr& theEllipse, + const GeomPlanePtr& thePlane) +{ + rebuildProjectedFeature(theProjection, CIRCLE_ELLIPSE_PROJECTION(), SketchPlugin_Ellipse::ID()); + + GeomAPI_Ellipse anEllipse(theEllipse); + GeomPointPtr aCenter = thePlane->project(anEllipse.center()); + GeomPnt2dPtr aCenterInSketch = sketch()->to2D(aCenter); + GeomPointPtr aFocus = thePlane->project(anEllipse.firstFocus()); + GeomPnt2dPtr aFocusInSketch = sketch()->to2D(aFocus); + + // update attributes of projection + std::shared_ptr aCenterPnt = + std::dynamic_pointer_cast( + theProjection->attribute(SketchPlugin_Ellipse::CENTER_ID())); + aCenterPnt->setValue(aCenterInSketch); + std::shared_ptr aFocusPnt = + std::dynamic_pointer_cast( + theProjection->attribute(SketchPlugin_Ellipse::FIRST_FOCUS_ID())); + aFocusPnt->setValue(aFocusInSketch); + theProjection->real(SketchPlugin_Ellipse::MINOR_RADIUS_ID())->setValue(anEllipse.minorRadius()); + return true; +} + +bool SketchPlugin_Projection::fillEllipticArc(FeaturePtr& theProjection, + const GeomCurvePtr& theEllipticArc, + const GeomPlanePtr& thePlane) +{ + rebuildProjectedFeature(theProjection, ARC_PROJECTION(), SketchPlugin_EllipticArc::ID()); + + GeomAPI_Ellipse anEllipse(theEllipticArc); + + double aNormalsDot = anEllipse.normal()->dot(thePlane->direction()); + if (fabs(fabs(aNormalsDot) - 1.0) > tolerance) + return false; // arc is not in the plane, parallel to the sketch plane + + bool isInversed = aNormalsDot < 0.; + + GeomPointPtr aCenter = thePlane->project(anEllipse.center()); + GeomPnt2dPtr aCenterInSketch = sketch()->to2D(aCenter); + GeomPointPtr aFocus = thePlane->project(anEllipse.firstFocus()); + GeomPnt2dPtr aFocusInSketch = sketch()->to2D(aFocus); + + GeomPointPtr aFirst = theEllipticArc->getPoint(theEllipticArc->startParam()); + GeomPnt2dPtr aFirstInSketch = sketch()->to2D(thePlane->project(aFirst)); + GeomPointPtr aLast = theEllipticArc->getPoint(theEllipticArc->endParam()); + GeomPnt2dPtr aLastInSketch = sketch()->to2D(thePlane->project(aLast)); + + bool aWasBlocked = theProjection->data()->blockSendAttributeUpdated(true); + + // update attributes of projection + std::shared_ptr aCenterPnt = + std::dynamic_pointer_cast( + theProjection->attribute(SketchPlugin_EllipticArc::CENTER_ID())); + std::shared_ptr aFocusPnt = + std::dynamic_pointer_cast( + theProjection->attribute(SketchPlugin_EllipticArc::FIRST_FOCUS_ID())); + std::shared_ptr aStartPnt = + std::dynamic_pointer_cast( + theProjection->attribute(SketchPlugin_EllipticArc::START_POINT_ID())); + std::shared_ptr aEndPnt = + std::dynamic_pointer_cast( + theProjection->attribute(SketchPlugin_EllipticArc::END_POINT_ID())); + aStartPnt->setValue(aFirstInSketch); + aEndPnt->setValue(aLastInSketch); + aCenterPnt->setValue(aCenterInSketch); + aFocusPnt->setValue(aFocusInSketch); + theProjection->boolean(SketchPlugin_EllipticArc::REVERSED_ID())->setValue(isInversed); + + theProjection->data()->blockSendAttributeUpdated(aWasBlocked); + return true; +} + +bool SketchPlugin_Projection::fillBSpline(FeaturePtr& theProjection, + const GeomCurvePtr& theCurve, + const GeomPlanePtr& thePlane) +{ + rebuildProjectedFeature(theProjection, BSPLINE_PROJECTION(), SketchPlugin_BSpline::ID()); + + GeomAPI_BSpline aBSpline(theCurve); + + theProjection->integer(SketchPlugin_BSpline::DEGREE_ID())->setValue(aBSpline.degree()); + + AttributePoint2DArrayPtr aPolesAttr = std::dynamic_pointer_cast( + theProjection->attribute(SketchPlugin_BSpline::POLES_ID())); + std::list aPoles = aBSpline.poles(); + aPolesAttr->setSize((int)aPoles.size()); + std::list::iterator anIt = aPoles.begin(); + for (int anIndex = 0; anIt != aPoles.end(); ++anIt, ++anIndex) { + GeomPnt2dPtr aPoleInSketch = sketch()->to2D(*anIt); + aPolesAttr->setPnt(anIndex, aPoleInSketch); + } + + AttributeDoubleArrayPtr aWeightsAttr = + theProjection->data()->realArray(SketchPlugin_BSpline::WEIGHTS_ID()); + std::list aWeights = aBSpline.weights(); + if (aWeights.empty()) { // rational B-spline + int aSize = (int)aPoles.size(); + aWeightsAttr->setSize(aSize); + for (int anIndex = 0; anIndex < aSize; ++anIndex) + aWeightsAttr->setValue(anIndex, 1.0); + } + else { // non-rational B-spline + aWeightsAttr->setSize((int)aWeights.size()); + std::list::iterator anIt = aWeights.begin(); + for (int anIndex = 0; anIt != aWeights.end(); ++anIt, ++anIndex) + aWeightsAttr->setValue(anIndex, *anIt); + } + + AttributeDoubleArrayPtr aKnotsAttr = + theProjection->data()->realArray(SketchPlugin_BSpline::KNOTS_ID()); + std::list aKnots = aBSpline.knots(); + int aSize = (int)aKnots.size(); + aKnotsAttr->setSize(aSize); + std::list::iterator aKIt = aKnots.begin(); + for (int index = 0; index < aSize; ++index, ++aKIt) + aKnotsAttr->setValue(index, *aKIt); + + AttributeIntArrayPtr aMultsAttr = + theProjection->data()->intArray(SketchPlugin_BSpline::MULTS_ID()); + std::list aMultiplicities = aBSpline.mults(); + aSize = (int)aMultiplicities.size(); + aMultsAttr->setSize(aSize); + std::list::iterator aMIt = aMultiplicities.begin(); + for (int index = 0; index < aSize; ++index, ++aMIt) + aMultsAttr->setValue(index, *aMIt); + + return true; +} diff --git a/src/SketchPlugin/SketchPlugin_Projection.h b/src/SketchPlugin/SketchPlugin_Projection.h index 40fd6301a..b820daf99 100644 --- a/src/SketchPlugin/SketchPlugin_Projection.h +++ b/src/SketchPlugin/SketchPlugin_Projection.h @@ -22,6 +22,8 @@ #include "SketchPlugin_SketchEntity.h" +class GeomAPI_Curve; + /** \class SketchPlugin_Projection * \ingroup Plugins * \brief Feature for creation of external feature as a projection onto the sketch plane. @@ -88,6 +90,34 @@ private: /// \brief Find projection of a feature onto sketch plane void computeProjection(const std::string& theID); + /// \brief Project point to the sketch plane + bool projectPoint(FeaturePtr& theProjection, const std::shared_ptr& thePoint); + /// \brief Project segment to the sketch plane + bool projectSegment(FeaturePtr& theProjection, const std::shared_ptr& theEdge); + /// \brief Project any edge to sketch plane + bool projectEdge(FeaturePtr& theProjection, const std::shared_ptr& theEdge); + + /// \brief Fill attributes of the Arc feature + bool fillArc(FeaturePtr& theProjection, + const std::shared_ptr& theArc, + const std::shared_ptr& thePlane); + /// \brief Fill attributes of the Circle feature + bool fillCircle(FeaturePtr& theProjection, + const std::shared_ptr& theCircle, + const std::shared_ptr& thePlane); + /// \brief Fill attributes of the Ellipse feature + bool fillEllipse(FeaturePtr& theProjection, + const std::shared_ptr& theEllipse, + const std::shared_ptr& thePlane); + /// \brief Fill attributes of the EllipticArc feature + bool fillEllipticArc(FeaturePtr& theProjection, + const std::shared_ptr& theEllipticArc, + const std::shared_ptr& thePlane); + /// \brief Fill attributes of the B-spline feature + bool fillBSpline(FeaturePtr& theProjection, + const std::shared_ptr& theCurve, + const std::shared_ptr& thePlane); + /// \brief Delete already calculated projected feature /// if the selection of the projection is changed /// \param[in/out] theProjection projected feature diff --git a/src/SketchPlugin/SketchPlugin_Validators.cpp b/src/SketchPlugin/SketchPlugin_Validators.cpp index a974f7437..cf8d1ca4a 100644 --- a/src/SketchPlugin/SketchPlugin_Validators.cpp +++ b/src/SketchPlugin/SketchPlugin_Validators.cpp @@ -1125,38 +1125,35 @@ bool SketchPlugin_ProjectionValidator::isValid(const AttributePtr& theAttribute, std::shared_ptr aNormal = aPlane->direction(); std::shared_ptr anOrigin = aPlane->location(); + bool aValid = true; if (anEdge->isLine()) { std::shared_ptr aLine = anEdge->line(); std::shared_ptr aLineDir = aLine->direction(); double aDot = fabs(aNormal->dot(aLineDir)); - bool aValid = fabs(aDot - 1.0) >= tolerance * tolerance; + aValid = fabs(aDot - 1.0) >= tolerance * tolerance; if (!aValid) theError = "Error: Line is orthogonal to the sketch plane."; - return aValid; } else if (anEdge->isCircle() || anEdge->isArc()) { std::shared_ptr aCircle = anEdge->circle(); std::shared_ptr aCircNormal = aCircle->normal(); double aDot = fabs(aNormal->dot(aCircNormal)); - bool aValid = aDot >= tolerance * tolerance; + aValid = aDot >= tolerance * tolerance; if (!aValid) theError.arg(anEdge->isCircle() ? "Error: Circle is orthogonal to the sketch plane." : "Error: Arc is orthogonal to the sketch plane."); - return aValid; } else if (anEdge->isEllipse()) { std::shared_ptr anEllipse = anEdge->ellipse(); std::shared_ptr anEllipseNormal = anEllipse->normal(); double aDot = fabs(aNormal->dot(anEllipseNormal)); - bool aValid = fabs(aDot - 1.0) <= tolerance * tolerance; + aValid = fabs(aDot - 1.0) <= tolerance * tolerance; if (!aValid) theError.arg(anEdge->isClosed() ? "Error: Ellipse is orthogonal to the sketch plane." : "Error: Elliptic Arc is orthogonal to the sketch plane."); - return aValid; } - theError = "Error: Selected object is not supported for projection."; - return false; + return aValid; } diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AttributeBuilder.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AttributeBuilder.cpp index c8a6cb264..bce4d90d6 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AttributeBuilder.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AttributeBuilder.cpp @@ -101,24 +101,52 @@ static EntityWrapperPtr createScalar(const AttributePtr& theAttribute, static EntityWrapperPtr createScalarArray(const AttributePtr& theAttribute, PlaneGCSSolver_Storage* theStorage) { - AttributeDoubleArrayPtr anArray = - std::dynamic_pointer_cast(theAttribute); - if (!anArray || !anArray->isInitialized()) + class ArrayAttribute { + public: + ArrayAttribute(AttributePtr theAttribute) + { + myDouble = std::dynamic_pointer_cast(theAttribute); + myInteger = std::dynamic_pointer_cast(theAttribute); + } + + bool isInitialized() const + { + return (myDouble && myDouble->isInitialized()) || (myInteger && myInteger->isInitialized()); + } + + int size() const + { + return myDouble.get() ? myDouble->size() : myInteger->size(); + } + + double value(const int theIndex) const + { + return myDouble.get() ? myDouble->value(theIndex) : myInteger->value(theIndex); + } + + private: + AttributeDoubleArrayPtr myDouble; + AttributeIntArrayPtr myInteger; + } anArray(theAttribute); + + if (!anArray.isInitialized()) return EntityWrapperPtr(); PlaneGCSSolver_Storage* aStorage = theStorage; - // Weights of B-spline curve are not processed by the solver + // Weights, knots and multiplicities 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()) + (theAttribute->id() == SketchPlugin_BSpline::WEIGHTS_ID() || + theAttribute->id() == SketchPlugin_BSpline::KNOTS_ID() || + theAttribute->id() == SketchPlugin_BSpline::MULTS_ID())) aStorage = 0; - int aSize = anArray->size(); + int aSize = anArray.size(); GCS::VEC_pD aParameters; aParameters.reserve(aSize); for (int index = 0; index < aSize; ++index) { double* aParam = createParameter(aStorage); - *aParam = anArray->value(index); + *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 b8ac3e1dd..de163985d 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_FeatureBuilder.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_FeatureBuilder.cpp @@ -318,16 +318,25 @@ EntityWrapperPtr createBSpline(const AttributeEntityMap& theAttributes) aNewSpline->start = aNewSpline->poles.front(); aNewSpline->end = aNewSpline->poles.back(); } - else if (anAttrID == SketchPlugin_BSpline::WEIGHTS_ID()) { - ScalarArrayWrapperPtr anArray = - 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(); } + else { + ScalarArrayWrapperPtr anArray = + std::dynamic_pointer_cast(anIt->second); + if (anAttrID == SketchPlugin_BSpline::WEIGHTS_ID()) + aNewSpline->weights = anArray->array(); + else if (anAttrID == SketchPlugin_BSpline::KNOTS_ID()) + aNewSpline->knots = anArray->array(); + else if (anAttrID == SketchPlugin_BSpline::MULTS_ID()) { + const GCS::VEC_pD& aValues = anArray->array(); + aNewSpline->mult.reserve(aValues.size()); + for (GCS::VEC_pD::const_iterator anIt = aValues.begin(); anIt != aValues.end(); ++anIt) + aNewSpline->mult.push_back((int)(**anIt)); + } + } } return EdgeWrapperPtr(new PlaneGCSSolver_EdgeWrapper(aNewSpline)); @@ -377,6 +386,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::KNOTS_ID() || + theAttrName == SketchPlugin_BSpline::MULTS_ID() || theAttrName == SketchPlugin_BSpline::DEGREE_ID(); } diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_GeoExtensions.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_GeoExtensions.cpp index a97976001..ade6eeaa7 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_GeoExtensions.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_GeoExtensions.cpp @@ -75,13 +75,19 @@ void BSplineImpl::rebuildCache() { myCachedPoles.clear(); myCachedWeights.clear(); + myCachedKnots.clear(); + myCachedMultiplicities.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); + for (GCS::VEC_pD::iterator anIt = knots.begin(); anIt != knots.end(); ++anIt) + myCachedKnots.push_back(**anIt); + myCachedMultiplicities.assign(mult.begin(), mult.end()); - myCurve.reset(new GeomAPI_BSpline2d(myCachedPoles, myCachedWeights, degree, periodic)); + myCurve.reset(new GeomAPI_BSpline2d(degree, myCachedPoles, myCachedWeights, + myCachedKnots, myCachedMultiplicities, periodic)); } } // namespace GCS diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_GeoExtensions.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_GeoExtensions.h index 87f66653c..9bc62e327 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_GeoExtensions.h +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_GeoExtensions.h @@ -47,6 +47,8 @@ namespace GCS { std::shared_ptr myCurve; /// cached B-spline curve std::list > myCachedPoles; /// cached B-spline poles std::list myCachedWeights; /// cached B-spline weights + std::list myCachedKnots; /// cached B-spline knots + std::list myCachedMultiplicities; /// cached B-spline multiplicities }; } -- 2.39.2