# make a working copy of report
cp -f coverage.info.noext covfile
# remove all reports of GUI and external parts (for all the next kinds of reports)
-# RefAttrList is unused type of attribute for now
-for MASK in '*wrap*' 'moc_*' 'XAO_*' 'SketcherPrs_*' 'GeomAlgoImpl_*' 'ModuleBase_*' '*Widget*' '*Splitter*' '*RefAttrList*'; do
+for MASK in '*wrap*' 'moc_*' 'XAO_*' 'SketcherPrs_*' 'GeomAlgoImpl_*' 'ModuleBase_*' '*Widget*' '*Splitter*'; do
lcov -r covfile ${MASK} --output-file covfile_res -q
mv -f covfile_res covfile
done
Config_Prop::IntSpin, SKETCH_WIDTH);
Config_PropManager::registerProp(SKETCH_TAB_NAME, "angular_tolerance", "Angular tolerance",
Config_Prop::DblSpin, "0.04");
+ Config_PropManager::registerProp(SKETCH_TAB_NAME, "spline_weight", "Default spline weight",
+ Config_Prop::DblSpin, "1.0");
Config_PropManager::registerProp(SKETCH_TAB_NAME, "rotate_to_plane",
"Rotate to plane when selected", Config_Prop::Boolean, "false");
Config_PropManager::registerProp(SKETCH_TAB_NAME, "operation_cursor",
SET(PROJECT_HEADERS
GeomAPI.h
+ GeomAPI_BSpline.h
+ GeomAPI_BSpline2d.h
GeomAPI_Circ.h
GeomAPI_Circ2d.h
GeomAPI_Interface.h
)
SET(PROJECT_SOURCES
+ GeomAPI_BSpline.cpp
+ GeomAPI_BSpline2d.cpp
GeomAPI_Circ.cpp
GeomAPI_Circ2d.cpp
GeomAPI_Interface.cpp
%shared_ptr(GeomAPI_Ax2)
%shared_ptr(GeomAPI_Ax3)
%shared_ptr(GeomAPI_Box)
+%shared_ptr(GeomAPI_BSpline)
+%shared_ptr(GeomAPI_BSpline2d)
%shared_ptr(GeomAPI_Circ)
%shared_ptr(GeomAPI_Circ2d)
%shared_ptr(GeomAPI_Cone)
}
}
-%typemap(in) double & (double temp) {
- if (PyLong_Check($input)) {
- temp = PyLong_AsLong($input);
- $1 = &temp;
- }
+%typemap(in, numinputs=0) double & (double temp) {
+ $1 = &temp;
}
%typemap(argout) double & {
- $result = PyFloat_FromDouble(*$1);
+ $result = SWIG_Python_AppendOutput($result, PyFloat_FromDouble(*$1));
}
+// std::dynamic_pointer_cast
+template<class T1, class T2> std::shared_ptr<T1> shared_ptr_cast(std::shared_ptr<T2> theObject);
+%template(shapeToEdge) shared_ptr_cast<GeomAPI_Edge, GeomAPI_Shape>;
+
// all supported interfaces
%include "GeomAPI_Interface.h"
%include "GeomAPI_Ax2.h"
%include "GeomAPI_Ax3.h"
%include "GeomAPI_Box.h"
+%include "GeomAPI_BSpline.h"
+%include "GeomAPI_BSpline2d.h"
%include "GeomAPI_Circ.h"
%include "GeomAPI_Circ2d.h"
%include "GeomAPI_Cone.h"
--- /dev/null
+// 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 <GeomAPI_BSpline.h>
+#include <GeomAPI_Pnt.h>
+
+#include <Geom_BSplineCurve.hxx>
+
+#define MY_BSPLINE (*(implPtr<Handle_Geom_BSplineCurve>()))
+
+GeomAPI_BSpline::GeomAPI_BSpline(const GeomCurvePtr& theCurve)
+{
+ GeomCurvePtr anUntrimmedCurve = theCurve->basisCurve();
+ Handle(Geom_Curve) aCurve = anUntrimmedCurve->impl<Handle(Geom_Curve)>();
+ 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<GeomPointPtr> GeomAPI_BSpline::poles() const
+{
+ const TColgp_Array1OfPnt& aBSplPoles = MY_BSPLINE->Poles();
+
+ std::list<GeomPointPtr> 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<double> GeomAPI_BSpline::weights() const
+{
+ std::list<double> aWeights;
+ const TColStd_Array1OfReal* aBSplWeights = MY_BSPLINE->Weights();
+ if (aBSplWeights)
+ aWeights.assign(aBSplWeights->begin(), aBSplWeights->end());
+ return aWeights;
+}
+
+std::list<double> GeomAPI_BSpline::knots() const
+{
+ const TColStd_Array1OfReal& aBSplKnots = MY_BSPLINE->Knots();
+ return std::list<double>(aBSplKnots.begin(), aBSplKnots.end());
+}
+
+std::list<int> GeomAPI_BSpline::mults() const
+{
+ const TColStd_Array1OfInteger& aBSplMults = MY_BSPLINE->Multiplicities();
+ return std::list<int>(aBSplMults.begin(), aBSplMults.end());
+}
--- /dev/null
+// 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 <GeomAPI_Interface.h>
+#include <GeomAPI_Curve.h>
+
+#include <list>
+#include <memory>
+
+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<std::shared_ptr<GeomAPI_Pnt> > poles() const;
+
+ /// Weights of B-spline poles
+ GEOMAPI_EXPORT std::list<double> weights() const;
+
+ /// Knots of B-spline curve
+ GEOMAPI_EXPORT std::list<double> knots() const;
+
+ /// Multiplicities of B-spline knots
+ GEOMAPI_EXPORT std::list<int> mults() const;
+};
+
+//! Pointer on the object
+typedef std::shared_ptr<GeomAPI_BSpline> GeomBSplinePtr;
+
+#endif
--- /dev/null
+// 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 <GeomAPI_BSpline2d.h>
+#include <GeomAPI_Pnt2d.h>
+#include <GeomAPI_XY.h>
+
+#include <Geom2d_BSplineCurve.hxx>
+#include <Geom2dAPI_ProjectPointOnCurve.hxx>
+#include <GeomLib_Tool.hxx>
+#include <Precision.hxx>
+
+#define MY_BSPLINE (*(implPtr<Handle_Geom2d_BSplineCurve>()))
+
+
+static Handle_Geom2d_BSplineCurve* newBSpline2d(
+ const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+ const std::list<double>& theWeights,
+ const int theDegree,
+ const bool thePeriodic);
+
+
+static Handle_Geom2d_BSplineCurve* newBSpline2d(
+ const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+ const std::list<double>& theWeights,
+ const std::list<double>& theKnots,
+ const std::list<int>& theMults,
+ const int theDegree,
+ const bool thePeriodic)
+{
+ if (theKnots.empty() || theMults.empty())
+ return newBSpline2d(thePoles, theWeights, theDegree, thePeriodic);
+
+ int anAuxPole = 0;
+ if (thePeriodic && thePoles.front()->distance(thePoles.back()) < Precision::Confusion())
+ anAuxPole = -1;
+
+ // collect arrays of poles, weights, knots and multiplicities
+ TColgp_Array1OfPnt2d aPoles(1, (int)thePoles.size() + anAuxPole);
+ TColStd_Array1OfReal aWeights(1, (int)theWeights.size() + anAuxPole);
+ TColStd_Array1OfReal aKnots(1, (int)theKnots.size());
+ TColStd_Array1OfInteger aMults(1, (int)theMults.size());
+
+ int anIndex = 1;
+ for (std::list<GeomPnt2dPtr>::const_iterator aPIt = thePoles.begin();
+ aPIt != thePoles.end() && anIndex <= aPoles.Upper(); ++aPIt, ++anIndex)
+ aPoles.SetValue(anIndex, gp_Pnt2d((*aPIt)->x(), (*aPIt)->y()));
+ anIndex = 1;
+ for (std::list<double>::const_iterator aWIt = theWeights.begin();
+ aWIt != theWeights.end() && anIndex <= aWeights.Upper(); ++aWIt, ++anIndex)
+ aWeights.SetValue(anIndex, *aWIt);
+ anIndex = 1;
+ for (std::list<double>::const_iterator aKIt = theKnots.begin();
+ aKIt != theKnots.end(); ++aKIt, ++anIndex)
+ aKnots.SetValue(anIndex, *aKIt);
+ anIndex = 1;
+ for (std::list<int>::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);
+}
+
+Handle_Geom2d_BSplineCurve* newBSpline2d(
+ const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+ const std::list<double>& theWeights,
+ const int theDegree,
+ const bool thePeriodic)
+{
+ std::list<std::shared_ptr<GeomAPI_Pnt2d> > aPoles = thePoles;
+ std::list<double> aWeights = theWeights;
+ int aMult = theDegree + 1;
+ int aNbKnots = (int)thePoles.size() - theDegree + 1;
+ if (thePeriodic) {
+ if (aPoles.front()->distance(aPoles.back()) < Precision::Confusion()) {
+ aPoles.pop_back();
+ aWeights.pop_back();
+ }
+ aMult = 1;
+ aNbKnots = (int)aPoles.size() + 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<double> aKnots;
+ for (double aKnot = aStartParam; anIndex < aNbKnots; ++anIndex, aKnot += aStep)
+ aKnots.push_back(aKnot);
+ aKnots.push_back(aEndParam);
+
+ std::list<int> aMults(aNbKnots - 2, 1);
+ aMults.push_front(aMult);
+ aMults.push_back(aMult);
+
+ return newBSpline2d(aPoles, aWeights, aKnots, aMults, theDegree, thePeriodic);
+}
+
+static Handle_Geom2d_BSplineCurve* newBSpline2d(
+ const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+ const std::list<double>& 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<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+ const std::list<double>& 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 int theDegree,
+ const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+ const std::list<double>& theWeights,
+ const std::list<double>& theKnots,
+ const std::list<int>& theMults,
+ const bool thePeriodic)
+ : GeomAPI_Interface(newBSpline2d(thePoles, theWeights, theKnots, theMults,
+ 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();
+}
+
+std::list<double> GeomAPI_BSpline2d::knots() const
+{
+ const TColStd_Array1OfReal& aBSplKnots = MY_BSPLINE->Knots();
+ return std::list<double>(aBSplKnots.begin(), aBSplKnots.end());
+}
+
+std::list<int> GeomAPI_BSpline2d::mults() const
+{
+ const TColStd_Array1OfInteger& aBSplMults = MY_BSPLINE->Multiplicities();
+ return std::list<int>(aBSplMults.begin(), aBSplMults.end());
+}
+
+const bool GeomAPI_BSpline2d::parameter(const std::shared_ptr<GeomAPI_Pnt2d> thePoint,
+ const double theTolerance,
+ double& theParameter) const
+{
+ return GeomLib_Tool::Parameter(MY_BSPLINE, thePoint->impl<gp_Pnt2d>(),
+ theTolerance, theParameter) == Standard_True;
+}
+
+void GeomAPI_BSpline2d::D0(const double theU, std::shared_ptr<GeomAPI_Pnt2d>& 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<GeomAPI_Pnt2d>& thePoint,
+ std::shared_ptr<GeomAPI_XY>& 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()));
+}
--- /dev/null
+// 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 <GeomAPI_Interface.h>
+
+#include <list>
+#include <memory>
+
+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<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+ const std::list<double>& theWeights,
+ const bool thePeriodic = false);
+
+ /// Creation of B-spline curve defined by list of poles and weights
+ GEOMAPI_EXPORT GeomAPI_BSpline2d(const int theDegree,
+ const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+ const std::list<double>& theWeights,
+ const std::list<double>& theKnots = std::list<double>(),
+ const std::list<int>& theMults = std::list<int>(),
+ 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;
+
+ /// Knots of the curve
+ GEOMAPI_EXPORT std::list<double> knots() const;
+
+ /// Multiplicities of the knots
+ GEOMAPI_EXPORT std::list<int> mults() const;
+
+ /// \brief Computes the parameter of a given point on a circle. The point must be
+ /// located either on the circle itself or relatively to the latter
+ /// at a distance less than the tolerance value. Return FALSE if the point
+ /// is beyond the tolerance limit or if computation fails.
+ /// Max Tolerance value is currently limited to 1.e-4
+ /// \param[in] thePoint point of origin.
+ /// \param[in] theTolerance tolerance of computation.
+ /// \param[out] theParameter resulting parameter.
+ GEOMAPI_EXPORT const bool parameter(const std::shared_ptr<GeomAPI_Pnt2d> thePoint,
+ const double theTolerance,
+ double& theParameter) const;
+
+ /// \brief Calculate point on B-spline curve accrding to the given parameter
+ GEOMAPI_EXPORT void D0(const double theU, std::shared_ptr<GeomAPI_Pnt2d>& 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<GeomAPI_Pnt2d>& thePoint,
+ std::shared_ptr<GeomAPI_XY>& theDerivative);
+};
+
+#endif
#include <BRep_Tool.hxx>
#include <ElCLib.hxx>
#include <GCPnts_UniformAbscissa.hxx>
+#include <Geom_BSplineCurve.hxx>
#include <Geom_Curve.hxx>
#include <Geom_Line.hxx>
#include <Geom_Circle.hxx>
return false;
}
+bool GeomAPI_Edge::isBSpline() const
+{
+ const TopoDS_Shape& aShape = const_cast<GeomAPI_Edge*>(this)->impl<TopoDS_Shape>();
+ double aFirst, aLast;
+ Handle(Geom_Curve) aCurve = BRep_Tool::Curve((const TopoDS_Edge&)aShape, aFirst, aLast);
+ if (aCurve.IsNull()) // degenerative edge
+ return false;
+ while (aCurve->IsKind(STANDARD_TYPE(Geom_TrimmedCurve)))
+ aCurve = Handle(Geom_TrimmedCurve)::DownCast(aCurve)->BasisCurve();
+ return aCurve->IsKind(STANDARD_TYPE(Geom_BSplineCurve));
+}
+
std::shared_ptr<GeomAPI_Pnt> GeomAPI_Edge::firstPoint()
{
const TopoDS_Shape& aShape = const_cast<GeomAPI_Edge*>(this)->impl<TopoDS_Shape>();
return true;
}
-// LCOV_EXCL_START
+void GeomAPI_Edge::setRange(const double& theFirst, const double& theLast)
+{
+ TopoDS_Edge anEdge = impl<TopoDS_Edge>();
+ double aFirst, aLast;
+ Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
+ double aTolerance = BRep_Tool::Tolerance(anEdge);
+ if (aCurve->DynamicType() == STANDARD_TYPE(Geom_TrimmedCurve)) {
+ aCurve = Handle(Geom_TrimmedCurve)::DownCast(aCurve)->BasisCurve();
+ BRep_Builder().UpdateEdge(anEdge, aCurve, aTolerance);
+ }
+ BRep_Builder().Range(anEdge, theFirst, theLast);
+}
+
void GeomAPI_Edge::getRange(double& theFirst, double& theLast) const
{
const TopoDS_Shape& aShape = const_cast<GeomAPI_Edge*>(this)->impl<TopoDS_Shape>();
Handle(Geom_Curve) aCurve = BRep_Tool::Curve((const TopoDS_Edge&)aShape, theFirst, theLast);
}
+// LCOV_EXCL_START
bool GeomAPI_Edge::isInPlane(std::shared_ptr<GeomAPI_Pln> thePlane) const
{
double aFirst, aLast;
GEOMAPI_EXPORT
bool isEllipse() const;
+ /// Verifies that the edge is based on a B-spline curve
+ GEOMAPI_EXPORT
+ bool isBSpline() const;
+
/// Returns the first vertex coordinates of the edge
GEOMAPI_EXPORT
std::shared_ptr<GeomAPI_Pnt> firstPoint();
GEOMAPI_EXPORT
bool isEqual(const std::shared_ptr<GeomAPI_Shape> theEdge) const;
+ /// Change parametric range of the curve
+ GEOMAPI_EXPORT
+ void setRange(const double& theFirst, const double& theLast);
+
/// Returns range of parameter on the curve
GEOMAPI_EXPORT
void getRange(double& theFirst, double& theLast) const;
#include "GeomAPI_Ax2.h"
#include "GeomAPI_Ax3.h"
#include "GeomAPI_Box.h"
+ #include "GeomAPI_BSpline.h"
+ #include "GeomAPI_BSpline2d.h"
#include "GeomAPI_Circ.h"
#include "GeomAPI_Circ2d.h"
#include "GeomAPI_Cone.h"
#include <memory>
#include <string>
+ template<class T1, class T2>
+ std::shared_ptr<T1> shared_ptr_cast(std::shared_ptr<T2> theObject)
+ {
+ return std::dynamic_pointer_cast<T1>(theObject);
+ }
+
#endif /* SRC_GEOMAPI_GEOMAPI_SWIG_H_ */
#include <GeomAlgoAPI_EdgeBuilder.h>
#include <GeomAPI_Ax2.h>
+#include <GeomAPI_Ax3.h>
+#include <GeomAPI_BSpline2d.h>
#include <GeomAPI_Ellipse.h>
+#include <GeomAPI_Pnt2d.h>
#include <gp_Pln.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <TopoDS_Face.hxx>
#include <TopoDS.hxx>
#include <BRep_Tool.hxx>
+#include <Geom2d_BSplineCurve.hxx>
#include <Geom_Plane.hxx>
#include <Geom_CylindricalSurface.hxx>
#include <Geom_RectangularTrimmedSurface.hxx>
+#include <GeomLib.hxx>
#include <gp_Ax2.hxx>
#include <gp_Circ.hxx>
aRes->setImpl(new TopoDS_Shape(anEdge));
return aRes;
}
+
+GeomEdgePtr GeomAlgoAPI_EdgeBuilder::bsplineOnPlane(
+ const std::shared_ptr<GeomAPI_Ax3>& thePlane,
+ const std::list<GeomPnt2dPtr>& thePoles,
+ const std::list<double>& theWeights,
+ const std::list<double>& theKnots,
+ const std::list<int>& theMults,
+ const int theDegree,
+ const bool thePeriodic)
+{
+ std::shared_ptr<GeomAPI_BSpline2d> aBSplineCurve(
+ new GeomAPI_BSpline2d(theDegree, thePoles, theWeights, theKnots, theMults, thePeriodic));
+ return bsplineOnPlane(thePlane, aBSplineCurve);
+}
+
+GeomEdgePtr GeomAlgoAPI_EdgeBuilder::bsplineOnPlane(
+ const std::shared_ptr<GeomAPI_Ax3>& thePlane,
+ const std::shared_ptr<GeomAPI_BSpline2d>& theCurve)
+{
+ Handle(Geom_Curve) aCurve3D = GeomLib::To3d(thePlane->impl<gp_Ax3>().Ax2(),
+ theCurve->impl<Handle_Geom2d_BSplineCurve>());
+
+ BRepBuilderAPI_MakeEdge anEdgeBuilder(aCurve3D);
+ GeomEdgePtr aRes(new GeomAPI_Edge);
+ TopoDS_Edge anEdge = anEdgeBuilder.Edge();
+ aRes->setImpl(new TopoDS_Shape(anEdge));
+ return aRes;
+}
#include <GeomAPI_Lin.h>
#include <GeomAPI_Circ.h>
#include <memory>
+#include <vector>
+
+class GeomAPI_Ax3;
+class GeomAPI_BSpline2d;
/**\class GeomAlgoAPI_EdgeBuilder
* \ingroup DataAlgo
const double theMinorRadius,
const std::shared_ptr<GeomAPI_Pnt>& theStart,
const std::shared_ptr<GeomAPI_Pnt>& theEnd);
+
+ /// Creates planar B-spline edge
+ static GeomEdgePtr bsplineOnPlane(const std::shared_ptr<GeomAPI_Ax3>& thePlane,
+ const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+ const std::list<double>& theWeights,
+ const std::list<double>& theKnots,
+ const std::list<int>& theMults,
+ const int theDegree,
+ const bool thePeriodic);
+
+ /// Creates planar B-spline edge
+ static GeomEdgePtr bsplineOnPlane(const std::shared_ptr<GeomAPI_Ax3>& thePlane,
+ const std::shared_ptr<GeomAPI_BSpline2d>& theCurve);
};
#endif
GeomData_Point.h
GeomData_Dir.h
GeomData_Point2D.h
+ GeomData_Point2DArray.h
)
SET(PROJECT_SOURCES
GeomData_Point.cpp
GeomData_Dir.cpp
GeomData_Point2D.cpp
+ GeomData_Point2DArray.cpp
)
SET(PROJECT_LIBRARIES
--- /dev/null
+// 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 "GeomData_Point2DArray.h"
+
+#include <GeomAPI_Pnt2d.h>
+
+#include <ModelAPI_Data.h>
+#include <ModelAPI_Events.h>
+#include <ModelAPI_Expression.h>
+#include <ModelAPI_Feature.h>
+
+#include <cassert>
+
+GeomData_Point2DArray::GeomData_Point2DArray(TDF_Label& theLabel)
+ : myLab(theLabel)
+{
+ reinit();
+}
+
+void GeomData_Point2DArray::reinit()
+{
+ // check the attribute could be already presented in this doc (after load document)
+ myIsInitialized = myLab.FindAttribute(TDataStd_RealArray::GetID(), myArray) == Standard_True;
+}
+
+bool GeomData_Point2DArray::assign(std::shared_ptr<GeomDataAPI_Point2DArray> theOther)
+{
+ std::shared_ptr<GeomData_Point2DArray> anOther =
+ std::dynamic_pointer_cast<GeomData_Point2DArray>(theOther);
+ if (!anOther)
+ return false;
+
+ setSize(anOther->size());
+ myArray->ChangeArray(anOther->myArray->Array(), false);
+ owner()->data()->sendAttributeUpdated(this);
+
+ return true;
+}
+
+int GeomData_Point2DArray::size()
+{
+ if (myArray.IsNull() || !myArray->IsValid()) {
+ // this could be on undo and then redo creation of the attribute
+ // in result creation it may be uninitialized
+ myIsInitialized = myLab.FindAttribute(TDataStd_RealArray::GetID(), myArray) == Standard_True;
+ }
+ // checking the validity because attribute (as a field) may be presented,
+ // but without label: it is undoed
+ return (myArray.IsNull() || !myArray->IsValid()) ? 0 : myArray->Length() / 2;
+}
+
+void GeomData_Point2DArray::setSize(const int theSize)
+{
+ int aValuesSize = 2 * theSize;
+ if (myArray.IsNull() || !myArray->IsValid()) { // create array if it is not done yet
+ if (aValuesSize != 0) { // if size is zero, nothing to do (null array means there is no array)
+ myArray = TDataStd_RealArray::Set(myLab, 0, aValuesSize - 1);
+ owner()->data()->sendAttributeUpdated(this);
+ }
+ }
+ else { // reset the old array
+ if (aValuesSize) {
+ if (aValuesSize != myArray->Length()) { // old data is kept in the new array
+ Handle(TColStd_HArray1OfReal) aNewArray = new TColStd_HArray1OfReal(0, aValuesSize - 1);
+ for (int anIndex = 0; anIndex < aValuesSize && anIndex <= myArray->Upper(); ++anIndex)
+ aNewArray->SetValue(anIndex, myArray->Value(anIndex));
+ myArray->ChangeArray(aNewArray);
+ owner()->data()->sendAttributeUpdated(this);
+ }
+ }
+ else { // size is zero => array must be erased
+ if (!myArray.IsNull()) {
+ myArray.Nullify();
+ myLab.ForgetAttribute(TDataStd_RealArray::GetID());
+ owner()->data()->sendAttributeUpdated(this);
+ }
+ }
+ }
+}
+
+void GeomData_Point2DArray::setPnt(const int theIndex,
+ const double theX,
+ const double theY)
+{
+ if (myArray->Value(2 * theIndex) != theX || myArray->Value(2 * theIndex + 1) != theY) {
+ myArray->SetValue(2 * theIndex, theX);
+ myArray->SetValue(2 * theIndex + 1, theY);
+ owner()->data()->sendAttributeUpdated(this);
+ }
+}
+
+void GeomData_Point2DArray::setPnt(const int theIndex, const GeomPnt2dPtr& thePoint)
+{
+ setPnt(theIndex, thePoint->x(), thePoint->y());
+}
+
+GeomPnt2dPtr GeomData_Point2DArray::pnt(const int theIndex)
+{
+ GeomPnt2dPtr aPoint;
+ if (theIndex >= 0 && theIndex * 2 < myArray->Length())
+ aPoint.reset(new GeomAPI_Pnt2d(myArray->Value(2 * theIndex), myArray->Value(2 * theIndex + 1)));
+ return aPoint;
+}
--- /dev/null
+// 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 GeomData_Point2DArray_H_
+#define GeomData_Point2DArray_H_
+
+#include "GeomData.h"
+
+#include <GeomDataAPI_Point2DArray.h>
+
+#include <TDataStd_RealArray.hxx>
+#include <TDF_Label.hxx>
+
+/** \class GeomData_Point2DArray
+ * \ingroup DataModel
+ * \brief Attribute that contains an array of 2D points.
+ */
+class GeomData_Point2DArray : public GeomDataAPI_Point2DArray
+{
+ TDF_Label myLab; ///< the main label of the attribute
+ Handle_TDataStd_RealArray myArray; ///< array that keeps all coordinates of the points
+
+public:
+ /// Copy values from another array
+ /// \return \c true if the copy was successful
+ GEOMDATA_EXPORT virtual bool assign(std::shared_ptr<GeomDataAPI_Point2DArray> theOther);
+
+ /// Returns the size of the array (zero means that it is empty)
+ GEOMDATA_EXPORT virtual int size();
+
+ /// Sets the new size of the array. The previous data is erased.
+ GEOMDATA_EXPORT virtual void setSize(const int theSize);
+
+ /// Defines the value of the array by index [0; size-1]
+ GEOMDATA_EXPORT virtual void setPnt(const int theIndex,
+ const double theX, const double theY);
+
+ /// Defines the value of the array by index [0; size-1]
+ GEOMDATA_EXPORT virtual void setPnt(const int theIndex,
+ const std::shared_ptr<GeomAPI_Pnt2d>& thePoint);
+
+ /// Returns the value by the index
+ GEOMDATA_EXPORT virtual std::shared_ptr<GeomAPI_Pnt2d> pnt(const int theIndex);
+
+protected:
+ /// Initializes attributes
+ GEOMDATA_EXPORT GeomData_Point2DArray(TDF_Label& theLabel);
+ /// Reinitializes the internal state of the attribute (may be needed on undo/redo, abort, etc)
+ virtual void reinit();
+
+ friend class Model_Data;
+};
+
+#endif
GeomDataAPI_Point.h
GeomDataAPI_Dir.h
GeomDataAPI_Point2D.h
+ GeomDataAPI_Point2DArray.h
)
SET(PROJECT_SOURCES
GeomDataAPI_Point.cpp
GeomDataAPI_Dir.cpp
GeomDataAPI_Point2D.cpp
+ GeomDataAPI_Point2DArray.cpp
)
SET(PROJECT_LIBRARIES
%shared_ptr(GeomDataAPI_Point)
%shared_ptr(GeomDataAPI_Dir)
%shared_ptr(GeomDataAPI_Point2D)
+%shared_ptr(GeomDataAPI_Point2DArray)
// all supported interfaces
%include "GeomDataAPI_Point.h"
%include "GeomDataAPI_Dir.h"
%include "GeomDataAPI_Point2D.h"
+%include "GeomDataAPI_Point2DArray.h"
template<class T> std::shared_ptr<T> castTo(std::shared_ptr<ModelAPI_Attribute> theObject);
%template(geomDataAPI_Point) castTo<GeomDataAPI_Point>;
%template(geomDataAPI_Dir) castTo<GeomDataAPI_Dir>;
%template(geomDataAPI_Point2D) castTo<GeomDataAPI_Point2D>;
+%template(geomDataAPI_Point2DArray) castTo<GeomDataAPI_Point2DArray>;
--- /dev/null
+// 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 <GeomDataAPI_Point2DArray.h>
+
+std::string GeomDataAPI_Point2DArray::attributeType()
+{
+ return typeId();
+}
+
+GeomDataAPI_Point2DArray::GeomDataAPI_Point2DArray()
+{
+}
+
+GeomDataAPI_Point2DArray::~GeomDataAPI_Point2DArray()
+{
+}
--- /dev/null
+// 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 GeomDataAPI_Point2DArray_H_
+#define GeomDataAPI_Point2DArray_H_
+
+#include <GeomDataAPI.h>
+#include <ModelAPI_Attribute.h>
+
+class GeomAPI_Pnt2d;
+
+/**\class GeomDataAPI_Point2DArray
+ * \ingroup DataModel
+ * \brief Attribute that contains array of 2D point coordinates.
+ */
+
+class GeomDataAPI_Point2DArray : public ModelAPI_Attribute
+{
+public:
+ /// Copy values from another array
+ /// \return \c true if the copy was successful
+ GEOMDATAAPI_EXPORT virtual bool assign(std::shared_ptr<GeomDataAPI_Point2DArray> theOther) = 0;
+
+ /// Returns the size of the array (zero means that it is empty)
+ GEOMDATAAPI_EXPORT virtual int size() = 0;
+
+ /// Sets the new size of the array. The previous data is erased.
+ GEOMDATAAPI_EXPORT virtual void setSize(const int theSize) = 0;
+
+ /// Defines the value of the array by index [0; size-1]
+ GEOMDATAAPI_EXPORT virtual void setPnt(const int theIndex,
+ const double theX, const double theY) = 0;
+
+ /// Defines the value of the array by index [0; size-1]
+ GEOMDATAAPI_EXPORT virtual void setPnt(const int theIndex,
+ const std::shared_ptr<GeomAPI_Pnt2d>& thePoint) = 0;
+
+ /// Returns the value by the index
+ GEOMDATAAPI_EXPORT virtual std::shared_ptr<GeomAPI_Pnt2d> pnt(const int theIndex) = 0;
+
+ /// Returns the type of this class of attributes
+ static std::string typeId()
+ {
+ return std::string("Point2DArray");
+ }
+
+ /// Returns the type of this class of attributes, not static method
+ GEOMDATAAPI_EXPORT virtual std::string attributeType();
+
+protected:
+ /// Objects are created for features automatically
+ GEOMDATAAPI_EXPORT GeomDataAPI_Point2DArray();
+ GEOMDATAAPI_EXPORT virtual ~GeomDataAPI_Point2DArray();
+};
+
+typedef std::shared_ptr<GeomDataAPI_Point2DArray> AttributePoint2DArrayPtr;
+
+#endif
#include "GeomDataAPI_Point.h"
#include "GeomDataAPI_Dir.h"
#include "GeomDataAPI_Point2D.h"
+ #include "GeomDataAPI_Point2DArray.h"
#include <memory>
#include <string>
void Model_AttributeRefAttrList::append(ObjectPtr theObject)
{
- std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(theObject->data());
- myRef->Append(aData->label().Father()); // store label of the object
+ TDF_Label aLabel;
+ if (theObject) {
+ std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(theObject->data());
+ aLabel = aData->label().Father();
+ }
+
+ myRef->Append(aLabel); // store label of the object
myIDs->Append(""); // for the object store an empty string
// do it before the transaction finish to make just created/removed objects know dependencies
// and reference from composite feature is removed automatically
myIDs->Append(anIDIter.Value());
} else { // found, so need to update the dependencies
aOneisDeleted = true;
- ObjectPtr anObj = aDoc->objects()->object(aRefIter.Value());
+ ObjectPtr anObj;
+ if (!aRefIter.Value().IsNull())
+ anObj = aDoc->objects()->object(aRefIter.Value());
if (anObj.get()) {
REMOVE_BACK_REF(anObj);
}
#include <GeomDataAPI_Point.h>
#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
#include <GeomData_Point.h>
#include <GeomData_Point2D.h>
+#include <GeomData_Point2DArray.h>
#include <GeomData_Dir.h>
#include <Events_Loop.h>
#include <Events_InfoMessage.h>
}
anAttribute->myIsInitialized = anAllInitialized;
anAttr = anAttribute;
+ } else if (theAttrType == GeomData_Point2DArray::typeId()) {
+ anAttr = new GeomData_Point2DArray(anAttrLab);
}
+
if (anAttr) {
aResult = std::shared_ptr<ModelAPI_Attribute>(anAttr);
myAttrs[theID] = std::pair<AttributePtr, int>(aResult, anAttrIndex);
myMovedAttribute = AttributePtr();
}
-void ModelAPI_ObjectMovedMessage::setMovedAttribute(const AttributePtr& theMovedAttribute)
+void ModelAPI_ObjectMovedMessage::setMovedAttribute(const AttributePtr& theMovedAttribute,
+ const int thePointIndex)
{
myMovedAttribute = theMovedAttribute;
myMovedObject = ObjectPtr();
+ myMovedPointIndex = thePointIndex;
}
void ModelAPI_ObjectMovedMessage::setOriginalPosition(double theX, double theY)
{
ObjectPtr myMovedObject;
AttributePtr myMovedAttribute;
+ int myMovedPointIndex;
std::shared_ptr<GeomAPI_Pnt2d> myOriginalPosition;
std::shared_ptr<GeomAPI_Pnt2d> myCurrentPosition;
/// Set object which is being moved (if the message already contains attribute it will be cleared)
MODELAPI_EXPORT void setMovedObject(const ObjectPtr& theMovedObject);
/// Set attribute which is being moved (if the message already contains object it will be cleared)
- MODELAPI_EXPORT void setMovedAttribute(const AttributePtr& theMovedAttribute);
+ /// \param[in] theMovedAttribute moved attribute
+ /// \param[in] thePointIndex index of the point if the moved attribute is an array of points
+ MODELAPI_EXPORT void setMovedAttribute(const AttributePtr& theMovedAttribute,
+ const int thePointIndex = -1);
/// Return moved object
ObjectPtr movedObject() const
/// Return moved attribute
AttributePtr movedAttribute() const
{ return myMovedAttribute; }
+ /// Return index of the moved point
+ int movedPointIndex() const
+ { return myMovedPointIndex; }
/// Set original mouse position
MODELAPI_EXPORT void setOriginalPosition(double theX, double theY);
#include <memory>
#include <string>
- template<class T1, class T2>
- std::shared_ptr<T1> shared_ptr_cast(std::shared_ptr<T2> theObject)
- {
- return std::dynamic_pointer_cast<T1>(theObject);
- }
-
#endif /* SRC_MODELAPI_MODELAPI_SWIG_H_ */
}
}
+
+%typemap(in) const std::list<int> & (std::list<int> 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<int>, const std::list<int>& {
+ 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<double> & (std::list<double> temp) {
- double * temp_attribute;
int newmem = 0;
if (PyTuple_Check($input)) {
for (Py_ssize_t i = 0; i < PyTuple_Size($input); ++i) {
}
%typecheck(SWIG_TYPECHECK_POINTER) std::list<double>, const std::list<double>& {
- double * temp_object;
- std::shared_ptr<ModelHighAPI_Interface> * temp_interface;
int newmem = 0;
if (PyTuple_Check($input)) {
for (Py_ssize_t i = 0; i < PyTuple_Size($input); ++i) {
}
}
+
+%typemap(in) const std::list<ModelHighAPI_Double> & (std::list<ModelHighAPI_Double> 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<ModelHighAPI_Double>, const std::list<ModelHighAPI_Double> & {
+ if (PySequence_Check($input)) {
+ $1 = 1;
+ for (Py_ssize_t i = 0; i < PySequence_Size($input) && $1; ++i) {
+ PyObject * item = PySequence_GetItem($input, i);
+ $1 = ((PyFloat_Check(item) || PyLong_Check(item) || PyUnicode_Check(item)) && !PyBool_Check(item)) ? 1 : 0;
+ Py_DECREF(item);
+ }
+ } else {
+ $1 = 0;
+ }
+}
+
+
+%typemap(in) const std::list<ModelHighAPI_Integer> & (std::list<ModelHighAPI_Integer> temp) {
+ ModelHighAPI_Integer * temp_int;
+ if (PySequence_Check($input)) {
+ for (Py_ssize_t i = 0; i < PySequence_Size($input); ++i) {
+ PyObject * item = PySequence_GetItem($input, i);
+ if (PyLong_Check(item)) {
+ temp.push_back(ModelHighAPI_Integer(PyLong_AsLong(item)));
+ } else if (PyUnicode_Check(item)) {
+ temp.push_back(ModelHighAPI_Integer(PyUnicode_AsUTF8(item)));
+ } else if ((SWIG_ConvertPtr(item, (void **)&temp_int, $1_descriptor, SWIG_POINTER_EXCEPTION)) == 0) {
+ temp.push_back(*temp_int);
+ } else {
+ PyErr_SetString(PyExc_ValueError, "argument must be a list of ModelHighAPI_Integer, int or string.");
+ return NULL;
+ }
+ Py_DECREF(item);
+ }
+ $1 = &temp;
+ } else {
+ PyErr_SetString(PyExc_ValueError, "argument must be a list of ModelHighAPI_Integer, int or string.");
+ return NULL;
+ }
+}
+
+%typecheck(SWIG_TYPECHECK_POINTER) std::list<ModelHighAPI_Integer>, const std::list<ModelHighAPI_Integer> & {
+ if (PySequence_Check($input)) {
+ $1 = 1;
+ for (Py_ssize_t i = 0; i < PySequence_Size($input) && $1; ++i) {
+ PyObject * item = PySequence_GetItem($input, i);
+ $1 = ((PyLong_Check(item) || PyUnicode_Check(item)) && !PyBool_Check(item)) ? 1 : 0;
+ Py_DECREF(item);
+ }
+ } else {
+ $1 = 0;
+ }
+}
+
+
// all supported interfaces
%include "ModelHighAPI_Double.h"
%include "ModelHighAPI_Dumper.h"
{
}
+double ModelHighAPI_Double::value() const
+{
+ // needed for array of double, which supports no text
+ return myDouble;
+}
+
//--------------------------------------------------------------------------------------
void ModelHighAPI_Double::fillAttribute(
const std::shared_ptr<ModelAPI_AttributeDouble> & theAttribute) const
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;
#include <Config_PropManager.h>
#include <GeomAPI_Pnt.h>
+#include <GeomAPI_Pnt2d.h>
#include <GeomAPI_Dir.h>
#include <GeomAPI_ShapeExplorer.h>
#include <GeomAPI_ShapeIterator.h>
#include <GeomDataAPI_Dir.h>
#include <GeomDataAPI_Point.h>
#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
#include <ModelAPI_AttributeBoolean.h>
#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeDoubleArray.h>
#include <ModelAPI_AttributeIntArray.h>
#include <ModelAPI_AttributeInteger.h>
#include <ModelAPI_AttributeRefAttr.h>
return *this;
}
+ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
+ const std::shared_ptr<GeomDataAPI_Point2DArray>& 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<ModelAPI_AttributeBoolean>& theAttrBool)
{
return *this;
}
+ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
+ const std::shared_ptr<ModelAPI_AttributeIntArray>& 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<ModelAPI_AttributeDouble>& theAttrReal)
{
return *this;
}
+ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
+ const std::shared_ptr<ModelAPI_AttributeDoubleArray>& 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<ModelAPI_AttributeString>& theAttrStr)
{
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_AttributeIntArray;
class ModelAPI_AttributeInteger;
class ModelAPI_AttributeRefAttr;
class ModelAPI_AttributeRefAttrList;
/// "X, Y"
MODELHIGHAPI_EXPORT
ModelHighAPI_Dumper& operator<<(const std::shared_ptr<GeomDataAPI_Point2D>& thePoint);
+ /// Dump GeomDataAPI_Point2DArray as a list of 2D points
+ MODELHIGHAPI_EXPORT
+ ModelHighAPI_Dumper& operator<<(const std::shared_ptr<GeomDataAPI_Point2DArray>& thePointArray);
/// Dump AttributeBoolean
MODELHIGHAPI_EXPORT
/// Dump AttributeInteger
MODELHIGHAPI_EXPORT
ModelHighAPI_Dumper& operator<<(const std::shared_ptr<ModelAPI_AttributeInteger>& theAttrInt);
+ /// Dump AttributeIntArray
+ MODELHIGHAPI_EXPORT
+ ModelHighAPI_Dumper& operator<<(const std::shared_ptr<ModelAPI_AttributeIntArray>& theArray);
/// Dump AttributeDouble
MODELHIGHAPI_EXPORT
ModelHighAPI_Dumper& operator<<(const std::shared_ptr<ModelAPI_AttributeDouble>& theAttrReal);
+ /// Dump AttributeDoubleArray
+ MODELHIGHAPI_EXPORT
+ ModelHighAPI_Dumper& operator<<(const std::shared_ptr<ModelAPI_AttributeDoubleArray>& theArray);
/// Dump AttributeString
MODELHIGHAPI_EXPORT
ModelHighAPI_Dumper& operator<<(const std::shared_ptr<ModelAPI_AttributeString>& theAttrStr);
#include <GeomDataAPI_Dir.h>
#include <GeomDataAPI_Point.h>
#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
//--------------------------------------------------------------------------------------
#include <ModelAPI_AttributeBoolean.h>
#include <ModelAPI_AttributeDocRef.h>
#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeDoubleArray.h>
#include <ModelAPI_AttributeIntArray.h>
#include <ModelAPI_AttributeInteger.h>
#include <ModelAPI_AttributeRefAttr.h>
theAttribute->setValue(anIndex, it->intValue()); // use only values, no text support in array
}
+//--------------------------------------------------------------------------------------
+void fillAttribute(const std::list<ModelHighAPI_Double> & theValue,
+ const std::shared_ptr<ModelAPI_AttributeDoubleArray> & 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<std::shared_ptr<GeomAPI_Pnt2d> > & theValue,
+ const std::shared_ptr<GeomDataAPI_Point2DArray> & 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,
theX.fillAttribute(theAttribute, theX, theY, theZ);
}
-
//==================================================================================================
GeomAPI_Shape::ShapeType shapeTypeByStr(std::string theShapeTypeStr)
{
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;
void fillAttribute(const std::list<ModelHighAPI_Integer> & theValue,
const std::shared_ptr<ModelAPI_AttributeIntArray> & theAttribute);
+MODELHIGHAPI_EXPORT
+void fillAttribute(const std::list<ModelHighAPI_Double> & theValue,
+ const std::shared_ptr<ModelAPI_AttributeDoubleArray> & theAttribute);
+
+MODELHIGHAPI_EXPORT
+void fillAttribute(const std::list<std::shared_ptr<GeomAPI_Pnt2d> > & theValue,
+ const std::shared_ptr<GeomDataAPI_Point2DArray> & theAttribute);
+
MODELHIGHAPI_EXPORT
void fillAttribute(const ModelHighAPI_Double & theX,
const ModelHighAPI_Double & theY,
QWidget* ModuleBase_IWidgetCreator::createPanelByType(const std::string& theType,
QWidget* theParent,
- const FeaturePtr& theFeature)
+ const FeaturePtr& theFeature,
+ Config_WidgetAPI* theWidgetApi)
{
return 0;
}
/// \param theType a panel type
/// \param theParent a parent widget
/// \param theFeature a feature modified in the panel
+ /// \param theWidgetApi a low-level API for reading xml definitions of widget
/// \return created widget or null
virtual QWidget* createPanelByType(const std::string& theType,
QWidget* theParent,
- const FeaturePtr& theFeature);
+ const FeaturePtr& theFeature,
+ Config_WidgetAPI* theWidgetApi = 0);
/// Create page by its type
/// The default implementation is empty
/// \param theFeature a feature object
/// \param theToStoreValue a value about necessity to store the widget value to the feature
/// \param isUpdateFlushed a flag if update should be flushed on store value
- void setFeature(const FeaturePtr& theFeature, const bool theToStoreValue = false,
- const bool isUpdateFlushed = true);
+ virtual void setFeature(const FeaturePtr& theFeature, const bool theToStoreValue = false,
+ const bool isUpdateFlushed = true);
/// Editing mode depends on mode of current operation. This value is defined by it.
virtual void setEditingMode(bool isEditing) { myIsEditing = isEditing; }
QWidget* ModuleBase_WidgetCreatorFactory::createPanelByType(const std::string& theType,
QWidget* theParent,
- const FeaturePtr& theFeature)
+ const FeaturePtr& theFeature,
+ Config_WidgetAPI* myWidgetApi)
{
QWidget* aPanel = 0;
if (myPanelToCreator.contains(theType)) {
WidgetCreatorPtr aCreator = myPanelToCreator[theType];
- aPanel = aCreator->createPanelByType(theType, theParent, theFeature);
+ aPanel = aCreator->createPanelByType(theType, theParent, theFeature, myWidgetApi);
}
return aPanel;
}
/// \param theType a type
/// \param theParent a parent widget
/// \param theFeature a feature to fill the panel
+ /// \param theWidgetApi the widget configuration.
+ /// The attribute of the model widget is obtained from XML
/// \return a created panel or null
QWidget* createPanelByType(const std::string& theType, QWidget* theParent,
- const FeaturePtr& theFeature);
+ const FeaturePtr& theFeature,
+ Config_WidgetAPI* theWidgetApi = 0);
/// Returns true if there is a creator, which can make a page by the type
/// \param theType a type
std::string aPanelName = myWidgetApi->getProperty(PROPERTY_PANEL_ID);
if (!aPanelName.empty() && ModuleBase_WidgetCreatorFactory::get()->hasPanelWidget(aPanelName)) {
QWidget* aPanel = ModuleBase_WidgetCreatorFactory::get()->createPanelByType(aPanelName,
- thePage->pageWidget(), theFeature);
- thePage->addWidget(aPanel);
+ thePage->pageWidget(), theFeature, myWidgetApi);
+ ModuleBase_ModelWidget* aModelWdg = dynamic_cast<ModuleBase_ModelWidget*>(aPanel);
+ if (aModelWdg)
+ thePage->addModelWidget(aModelWdg);
+ else
+ thePage->addWidget(aPanel);
thePage->alignToTop();
}
}
aWidget->setVisible(false);
}
}
+ thePage->alignToTop();
}
- thePage->alignToTop();
}
void ModuleBase_WidgetFactory::getAttributeTitle(const std::string& theAttributeId,
theTitle =
QString::fromStdString(myWidgetApi->getProperty(CONTAINER_PAGE_NAME)).toStdString().c_str();
}
+ else
+ theTitle = theAttributeId;
}
void ModuleBase_WidgetFactory::getGreedAttribute(std::string& theAttributeId)
PartSet_WidgetSketchLabel.h
PartSet_CenterPrs.h
PartSet_ExternalPointsMgr.h
- PartSet_TreeNodes.h
- PartSet_FieldStepPrs.h
+ PartSet_TreeNodes.h
+ PartSet_FieldStepPrs.h
+ PartSet_WidgetBSplinePoints.h
+ PartSet_BSplineWidget.h
)
SET(PROJECT_MOC_HEADERS
PartSet_WidgetShapeSelector.h
PartSet_WidgetSketchCreator.h
PartSet_WidgetSketchLabel.h
+ PartSet_WidgetBSplinePoints.h
PartSet_ExternalPointsMgr.h
+ PartSet_BSplineWidget.h
)
SET(PROJECT_SOURCES
PartSet_WidgetSketchLabel.cpp
PartSet_CenterPrs.cpp
PartSet_ExternalPointsMgr.cpp
- PartSet_TreeNodes.cpp
- PartSet_FieldStepPrs.cpp
+ PartSet_TreeNodes.cpp
+ PartSet_FieldStepPrs.cpp
+ PartSet_WidgetBSplinePoints.cpp
+ PartSet_BSplineWidget.cpp
)
SET(PROJECT_RESOURCES
--- /dev/null
+// 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 <PartSet_BSplineWidget.h>
+
+#include <SketchPlugin_BSpline.h>
+
+#include <ModuleBase_Tools.h>
+
+#include <ModelAPI_AttributeDoubleArray.h>
+
+#include <GeomDataAPI_Point2DArray.h>
+
+#include <GeomAPI_Pnt2d.h>
+
+#include <QFormLayout>
+#include <QGroupBox>
+#include <QLabel>
+#include <QVBoxLayout>
+#include <QScrollArea>
+#include <QToolButton>
+
+
+PartSet_BSplineWidget::PartSet_BSplineWidget(
+ QWidget* theParent,
+ const Config_WidgetAPI* theData)
+ : ModuleBase_ModelWidget(theParent, theData)
+{
+ QVBoxLayout* aMainLayout = new QVBoxLayout(this);
+ aMainLayout->setContentsMargins(0, 0, 0, 0);
+
+ // GroupBox to keep widgets for B-spline poles and weights
+ myPolesGroupBox = new QGroupBox(tr("Poles and weights"), this);
+ aMainLayout->addWidget(myPolesGroupBox);
+
+ QVBoxLayout* aLayout = new QVBoxLayout(myPolesGroupBox);
+ ModuleBase_Tools::adjustMargins(aLayout);
+
+ myScrollArea = new QScrollArea(myPolesGroupBox);
+ myScrollArea->setWidgetResizable(true);
+ myScrollArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ myScrollArea->setFrameStyle(QFrame::NoFrame);
+ aLayout->addWidget(myScrollArea);
+
+ QWidget* aContainer = new QWidget(myScrollArea);
+ QVBoxLayout* aBoxLay = new QVBoxLayout(aContainer);
+ aBoxLay->setContentsMargins(0, 0, 0, 0);
+
+ // layout of GroupBox
+ myPolesWgt = new QWidget(aContainer);
+ QGridLayout* aGroupLayout = new QGridLayout(myPolesWgt);
+ aGroupLayout->setColumnStretch(1, 1);
+ ModuleBase_Tools::adjustMargins(aGroupLayout);
+
+ restoreValueCustom();
+ aBoxLay->addWidget(myPolesWgt);
+ aBoxLay->addStretch(1);
+ myScrollArea->setWidget(aContainer);
+}
+
+void PartSet_BSplineWidget::setFeature(const FeaturePtr& theFeature,
+ const bool theToStoreValue,
+ const bool isUpdateFlushed)
+{
+ ModuleBase_ModelWidget::setFeature(theFeature, theToStoreValue, isUpdateFlushed);
+ restoreValueCustom();
+}
+
+void PartSet_BSplineWidget::deactivate()
+{
+ ModuleBase_ModelWidget::deactivate();
+ storeValueCustom();
+}
+
+
+QList<QWidget*> PartSet_BSplineWidget::getControls() const
+{
+ QList<QWidget*> aControls;
+ aControls.append(myScrollArea);
+ return aControls;
+}
+
+void PartSet_BSplineWidget::storePolesAndWeights() const
+{
+ std::shared_ptr<ModelAPI_Data> aData = myFeature->data();
+ AttributeDoubleArrayPtr aWeightsArray = aData->realArray(SketchPlugin_BSpline::WEIGHTS_ID());
+
+ std::list<BSplinePoleWidgets>::const_iterator anIt = myPoles.begin();
+ for (int anIndex = 0; anIt != myPoles.end(); ++anIndex, ++anIt) {
+ aWeightsArray->setValue(anIndex, anIt->myWeight->value());
+ }
+}
+
+bool PartSet_BSplineWidget::storeValueCustom()
+{
+ std::shared_ptr<ModelAPI_Data> aData = myFeature->data();
+ if (!aData || !aData->isValid()) // can be on abort of sketcher element
+ return false;
+
+ AttributeDoubleArrayPtr aWeights = aData->realArray(SketchPlugin_BSpline::WEIGHTS_ID());
+
+ bool isBlocked = blockSignals(true);
+ storePolesAndWeights();
+ ModuleBase_Tools::flushUpdated(myFeature);
+ blockSignals(isBlocked);
+
+ updateObject(myFeature);
+ return true;
+}
+
+bool PartSet_BSplineWidget::restoreValueCustom()
+{
+ if (!myFeature)
+ return false;
+
+ DataPtr aData = myFeature->data();
+
+ AttributePoint2DArrayPtr aPoles = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
+ aData->attribute(SketchPlugin_BSpline::POLES_ID()));
+ AttributeDoubleArrayPtr aWeights = aData->realArray(SketchPlugin_BSpline::WEIGHTS_ID());
+
+ while (myPoles.size() < aPoles->size())
+ addPoleWidget();
+
+ std::list<BSplinePoleWidgets>::iterator anIt = myPoles.begin();
+ for (int anIndex = 0; anIt != myPoles.end(); ++anIt, ++anIndex) {
+ GeomPnt2dPtr aPoint = aPoles->pnt(anIndex);
+ anIt->myX->setValue(aPoint->x());
+ anIt->myY->setValue(aPoint->y());
+ bool isBlocked = anIt->myWeight->blockSignals(true);
+ anIt->myWeight->setValue(aWeights->value(anIndex));
+ anIt->myWeight->blockSignals(isBlocked);
+ }
+
+ return true;
+}
+
+void PartSet_BSplineWidget::addPoleWidget()
+{
+ QGridLayout* aGroupLay = dynamic_cast<QGridLayout*>(myPolesWgt->layout());
+ int aNbPoles = (int)myPoles.size();
+ QString aPoleStr = tr("Pole %1").arg(aNbPoles + 1);
+
+ myPoles.push_back(BSplinePoleWidgets());
+ BSplinePoleWidgets& aPole = myPoles.back();
+ aGroupLay->addWidget(createPoleWidget(aPole, aPoleStr, myPolesWgt), aNbPoles, 1);
+}
+
+QGroupBox* PartSet_BSplineWidget::createPoleWidget(BSplinePoleWidgets& thePole,
+ const QString& theName, QWidget* theParent)
+{
+ QGroupBox* aPoleGroupBox = new QGroupBox(theName, theParent);
+ QGridLayout* aPoleLay = new QGridLayout(aPoleGroupBox);
+ aPoleLay->setSpacing(0);
+ ModuleBase_Tools::zeroMargins(aPoleLay);
+
+ thePole.myX = new ModuleBase_LabelValue(aPoleGroupBox, tr("X"));
+ aPoleLay->addWidget(thePole.myX, 0, 0, 1, 3);
+ thePole.myY = new ModuleBase_LabelValue(aPoleGroupBox, tr("Y"));
+ aPoleLay->addWidget(thePole.myY, 1, 0, 1, 3);
+ thePole.myWeight = new ModuleBase_ParamSpinBox(aPoleGroupBox);
+ thePole.myWeight->setMinimum(0.0);
+
+ aPoleLay->addWidget(new QLabel(tr("Weight :"), aPoleGroupBox), 2, 0);
+ aPoleLay->addWidget(thePole.myWeight, 2, 1);
+ // we should listen textChanged signal as valueChanged do not send when text is modified
+ connect(thePole.myWeight, SIGNAL(textChanged(const QString&)),
+ this, SIGNAL(valuesChanged()));
+
+ thePole.myAddBtn = new QToolButton(aPoleGroupBox);
+ thePole.myAddBtn->setIcon(QIcon(":pictures/add.png"));
+ thePole.myAddBtn->setToolTip(tr("Add a new pole after the current"));
+ aPoleLay->addWidget(thePole.myAddBtn, 2, 2);
+ connect(thePole.myAddBtn, SIGNAL(clicked(bool)), SLOT(onAddPole()));
+
+ return aPoleGroupBox;
+}
+
+
+void PartSet_BSplineWidget::onAddPole()
+{
+ QObject* aObj = sender();
+ std::list<BSplinePoleWidgets>::const_iterator aIt;
+ int aId = 0;
+ bool aFound = false;
+ for (aIt = myPoles.cbegin(); aIt != myPoles.cend(); aIt++, aId++) {
+ if ((*aIt).myAddBtn == aObj) {
+ aFound = true;
+ break;
+ }
+ }
+ if (aFound) {
+ // add a new pole after found Id
+ std::ostringstream anActionName;
+ anActionName << SketchPlugin_BSplineBase::ADD_POLE_ACTION_ID() << "#" << aId;
+ if (feature()->customAction(anActionName.str()))
+ updateObject(feature());
+
+ restoreValueCustom();
+ }
+}
--- /dev/null
+// 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 PartSet_BSplineWidget_H
+#define PartSet_BSplineWidget_H
+
+
+#include <PartSet.h>
+
+#include <ModelAPI_Feature.h>
+
+#include <ModuleBase_LabelValue.h>
+#include <ModuleBase_ModelWidget.h>
+#include <ModuleBase_ParamSpinBox.h>
+
+class QGroupBox;
+class QScrollArea;
+class QToolButton;
+
+/** \brief Represent a content of the property panel to show/modify parameters of B-spline curve.
+ * \ingroup GUI
+ */
+class PartSet_BSplineWidget : public ModuleBase_ModelWidget
+{
+Q_OBJECT
+public:
+ /// Constructor
+ /// \param theParent the parent object
+ /// \param theData the widget configuation. The attribute of the model widget is obtained from
+ PartSet_BSplineWidget(QWidget* theParent,
+ const Config_WidgetAPI* theData);
+
+ virtual ~PartSet_BSplineWidget() {}
+
+ /// The methiod called when widget is deactivated
+ virtual void deactivate();
+
+ /// Returns list of widget controls
+ /// \return a control list
+ virtual QList<QWidget*> getControls() const;
+
+ /// Set feature which is processing by active operation
+ /// \param theFeature a feature object
+ /// \param theToStoreValue a value about necessity to store the widget value to the feature
+ /// \param isUpdateFlushed a flag if update should be flushed on store value
+ virtual void setFeature(const FeaturePtr& theFeature, const bool theToStoreValue = false,
+ const bool isUpdateFlushed = true);
+
+protected:
+ /// Saves the internal parameters to the given feature
+ /// \return True in success
+ virtual bool storeValueCustom();
+
+ /// Restore value from attribute data to the widget's control
+ virtual bool restoreValueCustom();
+
+ /// Create group of widgets related to coordinates of pole and its weight
+ void addPoleWidget();
+
+ /// Update attributes of B-spline feature
+ void storePolesAndWeights() const;
+
+private slots:
+ void onAddPole();
+
+private:
+ struct BSplinePoleWidgets {
+ ModuleBase_LabelValue* myX;
+ ModuleBase_LabelValue* myY;
+ ModuleBase_ParamSpinBox* myWeight;
+ QToolButton* myAddBtn;
+ };
+
+ QGroupBox* createPoleWidget(BSplinePoleWidgets& thePole,
+ const QString& theName,
+ QWidget* theParent);
+
+ QWidget* myPolesWgt; ///< widget to show poles and weights of B-spline curve
+ QGroupBox* myPolesGroupBox;
+ QScrollArea* myScrollArea;
+ std::list<BSplinePoleWidgets> myPoles; ///< list of B-spline poles and their weights
+};
+
+#endif
\ No newline at end of file
#include "PartSet_Validators.h"
#include "PartSet_Tools.h"
#include "PartSet_PreviewPlanes.h"
+#include "PartSet_WidgetBSplinePoints.h"
#include "PartSet_WidgetPoint2d.h"
#include "PartSet_WidgetPoint2DFlyout.h"
#include "PartSet_WidgetShapeSelector.h"
#include "PartSet_OverconstraintListener.h"
#include "PartSet_TreeNodes.h"
#include "PartSet_FieldStepPrs.h"
+#include "PartSet_BSplineWidget.h"
#include "PartSet_Filters.h"
#include "PartSet_FilterInfinite.h"
return aProcessed;
}
const TopoDS_Shape& aTDShape = aShape->impl<TopoDS_Shape>();
- AttributePtr anAttribute = PartSet_Tools::findAttributeBy2dPoint(anObject, aTDShape,
- mySketchMgr->activeSketch());
- if (anAttribute.get()) {
+ std::pair<AttributePtr, int> anAttribute =
+ PartSet_Tools::findAttributeBy2dPoint(anObject, aTDShape, mySketchMgr->activeSketch());
+ if (anAttribute.first.get()) {
ModuleBase_WidgetFactory aFactory(theXmlRepr.toStdString(), workshop());
- const std::string anAttributeId = anAttribute->id();
+ const std::string anAttributeId = anAttribute.first->id();
aFactory.createWidget(aPropertyPanel->contentWidget(), anAttributeId);
theWidgets = aFactory.getModelWidgets();
aPointSelectorWgt->setSketcher(mySketchMgr->activeSketch());
aWgt = aPointSelectorWgt;
}
+ else if (theType == "sketch-bspline_selector") {
+ PartSet_WidgetBSplinePoints* aBSplineWgt =
+ new PartSet_WidgetBSplinePoints(theParent, aWorkshop, theWidgetApi);
+ aBSplineWgt->setSketch(mySketchMgr->activeSketch());
+ aWgt = aBSplineWgt;
+ }
else if (theType == WDG_DOUBLEVALUE_EDITOR) {
aWgt = new PartSet_WidgetEditor(theParent, aWorkshop, theWidgetApi);
} else if (theType == "export_file_selector") {
aWgt = new PartSet_WidgetFileSelector(theParent, aWorkshop, theWidgetApi);
} else if (theType == "sketch_launcher") {
aWgt = new PartSet_WidgetSketchCreator(theParent, this, theWidgetApi);
- } else if (theType == "module_choice") {
+ }
+ else if (theType == "module_choice") {
aWgt = new ModuleBase_WidgetChoice(theParent, theWidgetApi);
connect(aWgt, SIGNAL(itemSelected(ModuleBase_ModelWidget*, int)),
- this, SLOT(onChoiceChanged(ModuleBase_ModelWidget*, int)));
+ this, SLOT(onChoiceChanged(ModuleBase_ModelWidget*, int)));
+ } else if (theType == "bspline-panel") {
+ PartSet_BSplineWidget* aPanel = new PartSet_BSplineWidget(theParent, theWidgetApi);
+ //aPanel->setFeature(theFeature);
+ aWgt = aPanel;
}
return aWgt;
}
if (aGeomShape.get()) {
TopoDS_Shape aTDSShape = aGeomShape->impl<TopoDS_Shape>();
- return PartSet_Tools::findAttributeBy2dPoint(theObject, aTDSShape,
- mySketchMgr->activeSketch());
+ std::pair<AttributePtr, int> anAttrAndIndex =
+ PartSet_Tools::findAttributeBy2dPoint(theObject, aTDSShape, mySketchMgr->activeSketch());
+ return anAttrAndIndex.first;
}
return anAttribute;
}
#include <ModuleBase_ViewerFilters.h>
#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
#include <GeomAPI_Shape.h>
void getAttributesOrResults(const Handle(SelectMgr_EntityOwner)& theOwner,
const FeaturePtr& theFeature, const FeaturePtr& theSketch,
const ResultPtr& theResult,
- std::set<AttributePtr>& theSelectedAttributes,
+ std::map<AttributePtr, int>& theSelectedAttributes,
std::set<ResultPtr>& theSelectedResults,
TopTools_MapOfShape& theShapes)
{
theShapes.Add(aShape);
TopAbs_ShapeEnum aShapeType = aShape.ShapeType();
if (aShapeType == TopAbs_VERTEX) {
- AttributePtr aPntAttr = PartSet_Tools::findAttributeBy2dPoint(theFeature,
- aShape, theSketch);
- if (aPntAttr.get() != NULL)
- theSelectedAttributes.insert(aPntAttr);
+ std::pair<AttributePtr, int> aPntAttrIndex =
+ PartSet_Tools::findAttributeBy2dPoint(theFeature, aShape, theSketch);
+ if (aPntAttrIndex.first.get() != NULL)
+ theSelectedAttributes[aPntAttrIndex.first] = aPntAttrIndex.second;
}
else if (aShapeType == TopAbs_EDGE &&
theSelectedResults.find(theResult) == theSelectedResults.end()) {
for (; anIt != aLast; anIt++) {
FeaturePtr aFeature = anIt.key();
- std::set<AttributePtr> anAttributes = anIt.value().myAttributes;
+ std::map<AttributePtr, int> anAttributes = anIt.value().myAttributes;
// Process selection by attribute: the priority to the attribute
if (!anAttributes.empty()) {
- std::set<AttributePtr>::const_iterator anAttIt = anAttributes.begin(),
+ std::map<AttributePtr, int>::const_iterator anAttIt = anAttributes.begin(),
anAttLast = anAttributes.end();
for (; anAttIt != anAttLast; anAttIt++) {
- AttributePtr anAttr = *anAttIt;
+ AttributePtr anAttr = anAttIt->first;
if (anAttr.get() == NULL)
continue;
std::string aAttrId = anAttr->id();
DataPtr aData = aFeature->data();
if (aData->isValid()) {
- std::shared_ptr<GeomDataAPI_Point2D> aPoint =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aData->attribute(aAttrId));
- if (aPoint.get() != NULL) {
+ AttributePtr aPoint = aData->attribute(aAttrId);
+ if (aPoint->attributeType() == GeomDataAPI_Point2D::typeId() ||
+ aPoint->attributeType() == GeomDataAPI_Point2DArray::typeId()) {
bool isImmutable = aPoint->setImmutable(true);
std::shared_ptr<ModelAPI_ObjectMovedMessage> aMessage = std::shared_ptr
<ModelAPI_ObjectMovedMessage>(new ModelAPI_ObjectMovedMessage(this));
- aMessage->setMovedAttribute(aPoint);
+ aMessage->setMovedAttribute(aPoint, anAttIt->second);
aMessage->setOriginalPosition(anOriginalPosition);
aMessage->setCurrentPosition(aCurrentPosition);
Events_Loop::loop()->send(aMessage);
FeatureToSelectionMap::const_iterator anIt = theSelection.find(theFeature);
SelectionInfo anInfo = anIt.value();
- std::set<AttributePtr> aSelectedAttributes = anInfo.myAttributes;
+ std::map<AttributePtr, int> aSelectedAttributes = anInfo.myAttributes;
std::set<ResultPtr> aSelectedResults = anInfo.myResults;
ModuleBase_IViewer* aViewer = theWorkshop->viewer();
const TopoDS_Shape& aShape = anOwner->Shape();
TopAbs_ShapeEnum aShapeType = aShape.ShapeType();
if (aShapeType == TopAbs_VERTEX) {
- AttributePtr aPntAttr =
+ std::pair<AttributePtr, int> aPntAttrIndex =
PartSet_Tools::findAttributeBy2dPoint(theFeature, aShape, theSketch);
- if (aPntAttr.get() != NULL &&
- aSelectedAttributes.find(aPntAttr) != aSelectedAttributes.end())
+ if (aPntAttrIndex.first.get() != NULL &&
+ aSelectedAttributes.find(aPntAttrIndex.first) != aSelectedAttributes.end())
theOwnersToSelect.Add(anOwner);
else if (isSameShape && anInfo.myLocalSelectedShapes.Contains(aShape)) {
theOwnersToSelect.Add(anOwner);
/// Struct to define selection model information to store/restore selection
struct SelectionInfo
{
- std::set<AttributePtr> myAttributes; /// the selected attributes
+ /// the selected attributes and indices of points if array
+ std::map<AttributePtr, int> myAttributes;
std::set<ResultPtr> myResults; /// the selected results
TopoDS_Shape myFirstResultShape; /// the first shape of feature result
TopTools_MapOfShape myLocalSelectedShapes; /// shapes of local selection
#include <GeomDataAPI_Point.h>
#include <GeomDataAPI_Dir.h>
#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
#include <GeomAPI_Pln.h>
#include <GeomAPI_Pnt2d.h>
#include <GeomAPI_Pnt.h>
// attribute, returns the shape
PartSet_Module* aModule = dynamic_cast<PartSet_Module*>(theWorkshop->module());
PartSet_SketcherMgr* aSketchMgr = aModule->sketchMgr();
- AttributePtr aPntAttr = PartSet_Tools::findAttributeBy2dPoint(anAttributeFeature,
- aBRepShape, aSketchMgr->activeSketch());
- if (aPntAttr.get() != NULL && aPntAttr == theAttribute) {
+ std::pair<AttributePtr, int> aPntAttrIndex = PartSet_Tools::findAttributeBy2dPoint(
+ anAttributeFeature, aBRepShape, aSketchMgr->activeSketch());
+ if (aPntAttrIndex.first.get() != NULL && aPntAttrIndex.first == theAttribute) {
aShape = std::shared_ptr<GeomAPI_Shape>(new GeomAPI_Shape);
aShape->setImpl(new TopoDS_Shape(aBRepShape));
break;
return std::shared_ptr<GeomAPI_Pnt2d>(new GeomAPI_Pnt2d(aX, anY));
}
+std::shared_ptr<GeomAPI_Pnt2d> PartSet_Tools::getPnt2d(const Handle(V3d_View)& theView,
+ const TopoDS_Shape& theShape,
+ const FeaturePtr& theSketch)
+{
+ GeomPnt2dPtr aPoint2D;
+ if (!theShape.IsNull() && theShape.ShapeType() == TopAbs_VERTEX) {
+ const TopoDS_Vertex& aVertex = TopoDS::Vertex(theShape);
+ if (!aVertex.IsNull()) {
+ // the case when the point is taken from the existing vertex
+ gp_Pnt aPoint = BRep_Tool::Pnt(aVertex);
+ double aX, aY;
+ PartSet_Tools::convertTo2D(aPoint, theSketch, theView, aX, aY);
+ aPoint2D.reset(new GeomAPI_Pnt2d(aX, aY));
+ }
+ }
+ return aPoint2D;
+}
+
FeaturePtr findFirstCoincidenceByData(const DataPtr& theData,
std::shared_ptr<GeomAPI_Pnt2d> thePoint)
{
return aPnt;
}
-AttributePtr PartSet_Tools::findAttributeBy2dPoint(ObjectPtr theObj,
- const TopoDS_Shape theShape,
- FeaturePtr theSketch)
+class PointWrapper
+{
+public:
+ PointWrapper(AttributePtr theAttribute)
+ : myPoint(std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute)),
+ myArray(std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(theAttribute))
+ {}
+
+ int size() const { return myPoint.get() ? 1 : (myArray.get() ? myArray->size() : 0); }
+
+ GeomPointPtr point(int theIndex, FeaturePtr theSketch)
+ {
+ GeomPnt2dPtr aP2d;
+ if (myPoint.get())
+ aP2d = myPoint->pnt();
+ else if (myArray.get())
+ aP2d = myArray->pnt(theIndex);
+
+ GeomPointPtr aP3d;
+ if (aP2d.get())
+ aP3d = PartSet_Tools::convertTo3D(aP2d->x(), aP2d->y(), theSketch);
+ return aP3d;
+ }
+
+ bool isArray() const { return myArray.get(); }
+
+private:
+ AttributePoint2DPtr myPoint;
+ AttributePoint2DArrayPtr myArray;
+};
+
+std::pair<AttributePtr, int> PartSet_Tools::findAttributeBy2dPoint(ObjectPtr theObj,
+ const TopoDS_Shape theShape,
+ FeaturePtr theSketch)
{
AttributePtr anAttribute;
+ int aPointIndex = -1;
FeaturePtr aFeature = ModelAPI_Feature::feature(theObj);
if (aFeature) {
if (theShape.ShapeType() == TopAbs_VERTEX) {
// find the given point in the feature attributes
std::list<AttributePtr> anAttiributes =
aFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
+ std::list<AttributePtr> anArrays =
+ aFeature->data()->attributes(GeomDataAPI_Point2DArray::typeId());
+ anAttiributes.insert(anAttiributes.end(), anArrays.begin(), anArrays.end());
+
std::list<AttributePtr>::const_iterator anIt = anAttiributes.begin(),
aLast = anAttiributes.end();
double aMinDistance = 1.e-6; // searching for point with minimal distance and < 1.e-6
for (; anIt != aLast && !anAttribute; anIt++) {
- std::shared_ptr<GeomDataAPI_Point2D> aCurPoint =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(*anIt);
- if (!aCurPoint->isInitialized())
- continue;
-
- std::shared_ptr<GeomAPI_Pnt> aPnt =
- convertTo3D(aCurPoint->x(), aCurPoint->y(), theSketch);
- if (aPnt) {
- double aDistance = aPnt->distance(aValue);
- if (aDistance < aMinDistance) {
- anAttribute = aCurPoint;
- aMinDistance = aPnt->distance(aValue);
+ PointWrapper aWrapper(*anIt);
+ for (int anIndex = 0, aSize = aWrapper.size(); anIndex < aSize; ++anIndex) {
+ std::shared_ptr<GeomAPI_Pnt> aPnt = aWrapper.point(anIndex, theSketch);
+ if (aPnt) {
+ double aDistance = aPnt->distance(aValue);
+ if (aDistance < aMinDistance) {
+ anAttribute = *anIt;
+ if (aWrapper.isArray())
+ aPointIndex = anIndex;
+ aMinDistance = aPnt->distance(aValue);
+ }
}
}
}
}
}
}
- return anAttribute;
+ return std::pair<AttributePtr, int>(anAttribute, aPointIndex);
}
void PartSet_Tools::sendSubFeaturesEvent(const CompositeFeaturePtr& theComposite,
* \param theObj - an object
* \param theShape - a Shape
* \param theSketch - a Sketch to get a plane of converting to 2d
+ * \return Found attribute and index of point if the attribute is an array
*/
- static AttributePtr findAttributeBy2dPoint(ObjectPtr theObj, const TopoDS_Shape theShape,
- FeaturePtr theSketch);
+ static std::pair<AttributePtr, int> findAttributeBy2dPoint(ObjectPtr theObj,
+ const TopoDS_Shape theShape,
+ FeaturePtr theSketch);
/**
* Finds an attribute value in attribute reference attribute value
/**
* Convertes parameters into a geom point
- * \theEvent a Qt event to find mouse position
+ * \param theEvent a Qt event to find mouse position
* \param theWindow view window to define eye of view
* \param theSketch to convert 3D point coordinates into coorditates of the sketch plane
*/
ModuleBase_IViewWindow* theWindow,
const FeaturePtr& theSketch);
+ /** Returns point 2d from selected shape
+ * \param theView a view window
+ * \param theShape a vertex shape
+ * \param theX an output value of X coordinate
+ * \param theY an output value of Y coordinate
+ */
+ static std::shared_ptr<GeomAPI_Pnt2d> getPnt2d(const Handle(V3d_View)& theView,
+ const TopoDS_Shape& theShape,
+ const FeaturePtr& theSketch);
+
/**
* Gets all references to the feature, take coincidence constraint features, get point 2d attributes
* and compare the point value to be equal with the given. Returns the first feature, which has
--- /dev/null
+// 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 <PartSet_WidgetBSplinePoints.h>
+
+#include <PartSet_CenterPrs.h>
+#include <PartSet_ExternalObjectsMgr.h>
+#include <PartSet_Module.h>
+#include <PartSet_SketcherReentrantMgr.h>
+#include <PartSet_WidgetPoint2d.h>
+
+#include <XGUI_Tools.h>
+#include <XGUI_Workshop.h>
+#include <XGUI_Displayer.h>
+
+#include <ModuleBase_ISelection.h>
+#include <ModuleBase_IViewer.h>
+#include <ModuleBase_IViewWindow.h>
+#include <ModuleBase_LabelValue.h>
+#include <ModuleBase_Tools.h>
+#include <ModuleBase_ViewerPrs.h>
+#include <ModuleBase_WidgetValidator.h>
+#include <ModuleBase_WidgetValidated.h>
+
+#include <Config_Keywords.h>
+#include <Config_WidgetAPI.h>
+
+#include <Events_Loop.h>
+
+#include <ModelAPI_Events.h>
+#include <ModelAPI_AttributeDoubleArray.h>
+#include <ModelAPI_AttributeRefAttrList.h>
+#include <ModelAPI_CompositeFeature.h>
+
+#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
+
+#include <GeomAPI_Pnt2d.h>
+#include <GeomAPI_IPresentable.h>
+
+#include <SketchPlugin_Feature.h>
+
+#include <QGridLayout>
+#include <QGroupBox>
+#include <QMouseEvent>
+#include <QGraphicsEffect>
+#include <QScrollArea>
+
+static const double MaxCoordinate = 1e12;
+
+static bool IsPointCreated = false;
+
+
+PartSet_WidgetBSplinePoints::PartSet_WidgetBSplinePoints(QWidget* theParent,
+ ModuleBase_IWorkshop* theWorkshop,
+ const Config_WidgetAPI* theData)
+: ModuleBase_ModelWidget(theParent, theData), myWorkshop(theWorkshop),
+ myValueIsCashed(false), myIsFeatureVisibleInCash(true),
+ myXValueInCash(0), myYValueInCash(0),
+ myPointIndex(0), myFinished(false)
+{
+ myRefAttribute = theData->getProperty("reference_attribute");
+ QVBoxLayout* aMainLayout = new QVBoxLayout(this);
+ ModuleBase_Tools::zeroMargins(aMainLayout);
+
+ // the control should accept the focus, so the boolean flag is corrected to be true
+ myIsObligatory = true;
+ QString aPageName = translate(theData->getProperty(CONTAINER_PAGE_NAME));
+ myBox = new QGroupBox(aPageName, theParent);
+ myBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ myBox->setFlat(false);
+ aMainLayout->addWidget(myBox);
+
+ bool aAcceptVariables = theData->getBooleanAttribute(DOUBLE_WDG_ACCEPT_EXPRESSIONS, true);
+
+ // B-spline weights attribute
+ myWeightsAttr = theData->getProperty("weights");
+
+ QVBoxLayout* aLayout = new QVBoxLayout(myBox);
+ ModuleBase_Tools::adjustMargins(aLayout);
+
+ myScrollArea = new QScrollArea(myBox);
+ myScrollArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ myScrollArea->setWidgetResizable(true);
+ myScrollArea->setFrameStyle(QFrame::NoFrame);
+ aLayout->addWidget(myScrollArea);
+
+ QWidget* aContainer = new QWidget(myScrollArea);
+ QVBoxLayout* aBoxLay = new QVBoxLayout(aContainer);
+ aBoxLay->setContentsMargins(0, 0, 0, 0);
+
+ myGroupBox = new QWidget(aContainer);
+ QGridLayout* aGroupLay = new QGridLayout(myGroupBox);
+ ModuleBase_Tools::adjustMargins(aGroupLay);
+ aGroupLay->setSpacing(4);
+ aGroupLay->setColumnStretch(1, 1);
+ createNextPoint();
+ aBoxLay->addWidget(myGroupBox);
+ aBoxLay->addStretch(1);
+
+ myScrollArea->setWidget(aContainer);
+
+ myWidgetValidator = new ModuleBase_WidgetValidator(this, myWorkshop);
+ myExternalObjectMgr = new PartSet_ExternalObjectsMgr(theData->getProperty("use_external"),
+ theData->getProperty("can_create_external"), true);
+}
+
+void PartSet_WidgetBSplinePoints::createNextPoint()
+{
+ storeCurentValue();
+
+ QGridLayout* aGroupLay = dynamic_cast<QGridLayout*>(myGroupBox->layout());
+ int row = (int)myXSpin.size();
+
+ QString aPoleStr = tr("Pole %1");
+ aPoleStr = aPoleStr.arg(myXSpin.size() + 1);
+
+ QGroupBox* aPoleGroupBox = new QGroupBox(aPoleStr, myGroupBox);
+ QGridLayout* aPoleLay = new QGridLayout(aPoleGroupBox);
+ ModuleBase_Tools::adjustMargins(aPoleLay);
+ aPoleLay->setSpacing(2);
+ aPoleLay->setColumnStretch(1, 1);
+
+ myXSpin.push_back(new ModuleBase_LabelValue(aPoleGroupBox, tr("X")));
+ aPoleLay->addWidget(myXSpin.back(), 0, 1);
+ myYSpin.push_back(new ModuleBase_LabelValue(aPoleGroupBox, tr("Y")));
+ aPoleLay->addWidget(myYSpin.back(), 1, 1);
+
+ aGroupLay->addWidget(aPoleGroupBox, row, 1);
+ IsPointCreated = true;
+}
+
+void PartSet_WidgetBSplinePoints::removeLastPoint()
+{
+ QGridLayout* aGroupLay = dynamic_cast<QGridLayout*>(myGroupBox->layout());
+ QWidget* aXSpin = myXSpin.back();
+ QWidget* aYSpin = myYSpin.back();
+ QWidget* aBox = myXSpin.back()->parentWidget();
+ myYSpin.pop_back();
+ myXSpin.pop_back();
+
+ aGroupLay->removeWidget(aXSpin);
+ aGroupLay->removeWidget(aYSpin);
+ aGroupLay->removeWidget(aBox);
+
+ aBox->deleteLater();
+
+ // update B-spline feature attributes
+ storeValueCustom();
+}
+
+bool PartSet_WidgetBSplinePoints::isValidSelectionCustom(const ModuleBase_ViewerPrsPtr& theValue)
+{
+ bool aValid = true;
+
+ PartSet_Module* aModule = dynamic_cast<PartSet_Module*>(myWorkshop->module());
+ if (aModule->sketchReentranceMgr()->isInternalEditActive())
+ return true; // when internal edit is started a new feature is created. I has not results, AIS
+
+ // the selection is not possible if the current feature has no presentation for the current
+ // attribute not in AIS not in results. If so, no object in current feature where make
+ // coincidence, so selection is not necessary
+ GeomShapePtr anAISShape;
+ GeomPresentablePtr aPrs = std::dynamic_pointer_cast<GeomAPI_IPresentable>(myFeature);
+ if (aPrs.get()) {
+ AISObjectPtr anAIS;
+ anAIS = aPrs->getAISObject(anAIS);
+ if (anAIS.get()) {
+ anAISShape = anAIS->getShape();
+ }
+ }
+ const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = myFeature->results();
+ if (!anAISShape.get() && aResults.empty())
+ return true;
+
+ AttributeRefAttrListPtr aRefAttrList = attributeRefAttrList();
+ if (aRefAttrList)
+ return isValidSelectionForAttribute_(theValue, myFeature->attribute(attributeID()));
+ return true;
+}
+
+bool PartSet_WidgetBSplinePoints::isValidSelectionForAttribute_(
+ const ModuleBase_ViewerPrsPtr& theValue,
+ const AttributePtr& theAttribute)
+{
+ bool aValid = false;
+
+ // stores the current values of the widget attribute
+ bool isFlushesActived, isAttributeSetInitializedBlocked, isAttributeSendUpdatedBlocked;
+
+ AttributeRefAttrListPtr aRefAttrList = attributeRefAttrList();
+ ModuleBase_WidgetValidated::blockFeatureAttribute(aRefAttrList, myFeature, true,
+ isFlushesActived, isAttributeSetInitializedBlocked, isAttributeSendUpdatedBlocked);
+ myWidgetValidator->storeAttributeValue(aRefAttrList);
+
+ // saves the owner value to the widget attribute
+ aValid = setSelectionCustom(theValue);
+ if (aValid)
+ // checks the attribute validity
+ aValid = myWidgetValidator->isValidAttribute(theAttribute);
+
+ // restores the current values of the widget attribute
+ myWidgetValidator->restoreAttributeValue(aRefAttrList, aValid);
+ myExternalObjectMgr->removeExternal(sketch(), myFeature, myWorkshop, true);
+
+ ModuleBase_WidgetValidated::blockFeatureAttribute(aRefAttrList, myFeature, false,
+ isFlushesActived, isAttributeSetInitializedBlocked, isAttributeSendUpdatedBlocked);
+ return aValid;
+}
+
+bool PartSet_WidgetBSplinePoints::setSelectionCustom(const ModuleBase_ViewerPrsPtr& theValue)
+{
+ bool isDone = false;
+ GeomShapePtr aShape = theValue->shape();
+ if (aShape.get() && !aShape->isNull()) {
+ Handle(V3d_View) aView = myWorkshop->viewer()->activeView();
+ const TopoDS_Shape& aTDShape = aShape->impl<TopoDS_Shape>();
+ GeomPnt2dPtr aPnt = PartSet_Tools::getPnt2d(aView, aTDShape, mySketch);
+ if (aPnt) {
+ fillRefAttribute(aPnt, theValue);
+ isDone = true;
+ }
+ else if (aTDShape.ShapeType() == TopAbs_EDGE) {
+ fillRefAttribute(theValue);
+ isDone = true;
+ }
+ }
+ return isDone;
+}
+
+static void fillLabels(std::vector<ModuleBase_LabelValue*>& theLabels, const double theValue)
+{
+ for (std::vector<ModuleBase_LabelValue*>::iterator anIt = theLabels.begin();
+ anIt != theLabels.end(); ++anIt)
+ (*anIt)->setValue(theValue);
+}
+
+bool PartSet_WidgetBSplinePoints::resetCustom()
+{
+ bool aDone = false;
+ if (!isUseReset() || isComputedDefault())
+ aDone = false;
+ else {
+ if (myValueIsCashed) {
+ // if the restored value should be hidden, aDone = true to set
+ // reset state for the widget in the parent
+ aDone = restoreCurentValue();
+ emit objectUpdated();
+ }
+ else {
+ // it is important to block the spin box control in order to do not through out the
+ // locking of the validating state.
+ fillLabels(myXSpin, 0.0);
+ fillLabels(myYSpin, 0.0);
+
+ storeValueCustom();
+ aDone = true;
+ }
+ }
+ return aDone;
+}
+
+PartSet_WidgetBSplinePoints::~PartSet_WidgetBSplinePoints()
+{
+ delete myExternalObjectMgr;
+}
+
+bool PartSet_WidgetBSplinePoints::setPoint(double theX, double theY)
+{
+ if (fabs(theX) >= MaxCoordinate || fabs(theY) >= MaxCoordinate)
+ return false;
+
+ myXSpin.back()->setValue(theX);
+ myYSpin.back()->setValue(theY);
+
+ storeValue();
+ return true;
+}
+
+void PartSet_WidgetBSplinePoints::storePolesAndWeights() const
+{
+ std::shared_ptr<ModelAPI_Data> aData = myFeature->data();
+ AttributePoint2DArrayPtr aPointArray = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
+ aData->attribute(attributeID()));
+ AttributeDoubleArrayPtr aWeightsArray = aData->realArray(myWeightsAttr);
+
+ int aSize = (int)myXSpin.size();
+ aPointArray->setSize(aSize);
+ aWeightsArray->setSize(aSize);
+
+ std::vector<ModuleBase_LabelValue*>::const_iterator aXIt = myXSpin.begin();
+ std::vector<ModuleBase_LabelValue*>::const_iterator aYIt = myYSpin.begin();
+ for (int anIndex = 0; aXIt != myXSpin.end() && aYIt != myYSpin.end(); ++anIndex, ++aXIt, ++aYIt)
+ aPointArray->setPnt(anIndex, (*aXIt)->value(), (*aYIt)->value());
+
+ double aWeight = Config_PropManager::real(SKETCH_TAB_NAME, "spline_weight");
+ for (int anIndex = 0; anIndex < aSize; ++anIndex)
+ aWeightsArray->setValue(anIndex, aWeight);
+}
+
+bool PartSet_WidgetBSplinePoints::storeValueCustom()
+{
+ std::shared_ptr<ModelAPI_Data> aData = myFeature->data();
+ if (!aData || !aData->isValid()) // can be on abort of sketcher element
+ return false;
+ AttributePoint2DArrayPtr aPointArray = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
+ aData->attribute(attributeID()));
+ AttributeDoubleArrayPtr aWeightsArray = aData->realArray(myWeightsAttr);
+
+ PartSet_WidgetBSplinePoints* that = (PartSet_WidgetBSplinePoints*) this;
+ bool isBlocked = that->blockSignals(true);
+ bool isImmutable = aPointArray->setImmutable(true);
+
+ if (myFeature->isMacro()) {
+ // Moving points of macro-features has been processed directly (without solver)
+ storePolesAndWeights();
+ updateObject(myFeature);
+
+ } else {
+ if (!aPointArray->isInitialized()) {
+ storePolesAndWeights();
+ }
+
+ std::shared_ptr<ModelAPI_ObjectMovedMessage> aMessage(
+ new ModelAPI_ObjectMovedMessage(this));
+ aMessage->setMovedAttribute(aPointArray, aPointArray->size() - 1);
+ aMessage->setOriginalPosition(aPointArray->pnt(aPointArray->size() - 1));
+ aMessage->setCurrentPosition(myXSpin.back()->value(), myYSpin.back()->value());
+ Events_Loop::loop()->send(aMessage);
+ }
+
+ aPointArray->setImmutable(isImmutable);
+ that->blockSignals(isBlocked);
+
+ return true;
+}
+
+bool PartSet_WidgetBSplinePoints::restoreValueCustom()
+{
+ std::shared_ptr<ModelAPI_Data> aData = myFeature->data();
+ AttributePoint2DArrayPtr aPointArray = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
+ aData->attribute(attributeID()));
+ AttributeDoubleArrayPtr aWeightsArray = aData->realArray(myWeightsAttr);
+
+ if (aPointArray->isInitialized()) {
+ while (myXSpin.size() < aPointArray->size())
+ createNextPoint();
+
+ std::vector<ModuleBase_LabelValue*>::iterator aXIt = myXSpin.begin();
+ std::vector<ModuleBase_LabelValue*>::iterator aYIt = myYSpin.begin();
+ for (int anIndex = 0; aXIt != myXSpin.end() && aYIt != myYSpin.end();
+ ++anIndex, ++aXIt, ++aYIt) {
+ GeomPnt2dPtr aPoint = aPointArray->pnt(anIndex);
+ (*aXIt)->setValue(aPoint->x());
+ (*aYIt)->setValue(aPoint->y());
+ }
+ }
+ else {
+ if (myXSpin.empty())
+ createNextPoint();
+
+ myXSpin.back()->setValue(0.0);
+ myYSpin.back()->setValue(0.0);
+ }
+
+ return true;
+}
+
+static void storeArray(const std::vector<ModuleBase_LabelValue*>& theLabels,
+ std::vector<double>& theValues)
+{
+ theValues.clear();
+ theValues.reserve(theLabels.size());
+ for (std::vector<ModuleBase_LabelValue*>::const_iterator anIt = theLabels.begin();
+ anIt != theLabels.end(); ++anIt)
+ theValues.push_back((*anIt)->value());
+}
+
+void PartSet_WidgetBSplinePoints::storeCurentValue()
+{
+ myValueIsCashed = true;
+ myIsFeatureVisibleInCash = XGUI_Displayer::isVisible(
+ XGUI_Tools::workshop(myWorkshop)->displayer(), myFeature);
+
+ storeArray(myXSpin, myXValueInCash);
+ storeArray(myYSpin, myYValueInCash);
+}
+
+static void restoreArray(std::vector<double>& theCacheValues,
+ std::vector<ModuleBase_LabelValue*>& theLabels)
+{
+ std::vector<double>::iterator aCIt = theCacheValues.begin();
+ std::vector<ModuleBase_LabelValue*>::iterator anIt = theLabels.begin();
+ for (; anIt != theLabels.end(); ++anIt) {
+ if (aCIt != theCacheValues.end())
+ (*anIt)->setValue(*aCIt++);
+ else
+ (*anIt)->setValue(0.0);
+ }
+ theCacheValues.clear();
+}
+
+bool PartSet_WidgetBSplinePoints::restoreCurentValue()
+{
+ bool aRestoredAndHidden = true;
+
+ bool isVisible = myIsFeatureVisibleInCash;
+
+ myValueIsCashed = false;
+ myIsFeatureVisibleInCash = true;
+ // fill the control widgets by the cashed value
+ restoreArray(myXValueInCash, myXSpin);
+ restoreArray(myYValueInCash, myYSpin);
+
+ // store value to the model
+ storeValueCustom();
+ if (isVisible) {
+ setValueState(Stored);
+ aRestoredAndHidden = false;
+ }
+ else
+ aRestoredAndHidden = true;
+
+ return aRestoredAndHidden;
+}
+
+QList<QWidget*> PartSet_WidgetBSplinePoints::getControls() const
+{
+ QList<QWidget*> aControls;
+ aControls.append(myScrollArea);
+ return aControls;
+}
+
+void PartSet_WidgetBSplinePoints::selectionModes(int& theModuleSelectionModes, QIntList& theModes)
+{
+ theModuleSelectionModes = -1;
+ theModes << TopAbs_VERTEX;
+ theModes << TopAbs_EDGE;
+}
+
+void PartSet_WidgetBSplinePoints::deactivate()
+{
+ // the value of the control should be stored to model if it was not
+ // initialized yet. It is important when we leave this control by Tab key.
+ // It should not be performed by the widget activation as the preview
+ // is visualized with default value. Line point is moved to origin.
+ AttributePtr anAttribute = myFeature->data()->attribute(attributeID());
+ if (anAttribute && !anAttribute->isInitialized())
+ storeValue();
+
+ ModuleBase_ModelWidget::deactivate();
+}
+
+void PartSet_WidgetBSplinePoints::mouseReleased(ModuleBase_IViewWindow* theWindow,
+ QMouseEvent* theEvent)
+{
+ // the contex menu release by the right button should not be processed by this widget
+ if (theEvent->button() != Qt::LeftButton)
+ return;
+
+ ModuleBase_ISelection* aSelection = myWorkshop->selection();
+ Handle(V3d_View) aView = theWindow->v3dView();
+
+ QList<ModuleBase_ViewerPrsPtr> aList = aSelection->getSelected(ModuleBase_ISelection::Viewer);
+ ModuleBase_ViewerPrsPtr aFirstValue =
+ aList.size() > 0 ? aList.first() : ModuleBase_ViewerPrsPtr();
+ if (!aFirstValue.get() && myPreSelected.get()) {
+ aFirstValue = myPreSelected;
+ }
+
+ TopoDS_Shape aSelectedShape;
+ ObjectPtr aSelectedObject;
+
+ // if we have selection and use it
+ if (aFirstValue.get() && isValidSelectionCustom(aFirstValue) &&
+ aFirstValue->shape().get()) { // Trihedron Axis may be selected, but shape is empty
+ GeomShapePtr aGeomShape = aFirstValue->shape();
+ aSelectedShape = aGeomShape->impl<TopoDS_Shape>();
+ aSelectedObject = aFirstValue->object();
+
+ FeaturePtr aSelectedFeature = ModelAPI_Feature::feature(aSelectedObject);
+ std::shared_ptr<SketchPlugin_Feature> aSPFeature;
+ if (aSelectedFeature.get())
+ aSPFeature = std::dynamic_pointer_cast<SketchPlugin_Feature>(aSelectedFeature);
+
+ bool isSketchExternalFeature = aSPFeature.get() && aSPFeature->isExternal();
+ if ((!aSPFeature && !aSelectedShape.IsNull()) || isSketchExternalFeature) {
+ ObjectPtr aFixedObject =
+ PartSet_Tools::findFixedObjectByExternal(aSelectedShape, aSelectedObject, mySketch);
+ if (aFixedObject)
+ aSelectedObject = aFixedObject;
+ else if (!isSketchExternalFeature) {
+ FeaturePtr aCreatedFeature;
+ aSelectedObject = PartSet_Tools::createFixedObjectByExternal(
+ aGeomShape, aSelectedObject, mySketch, false, aCreatedFeature);
+ }
+ }
+ }
+ // The selection could be a center of an external circular object
+ else if (aFirstValue.get() && (!aFirstValue->interactive().IsNull())) {
+ Handle(PartSet_CenterPrs) aAIS =
+ Handle(PartSet_CenterPrs)::DownCast(aFirstValue->interactive());
+ if (!aAIS.IsNull()) {
+ gp_Pnt aPntComp = aAIS->Component()->Pnt();
+ GeomVertexPtr aVertPtr(new GeomAPI_Vertex(aPntComp.X(), aPntComp.Y(), aPntComp.Z()));
+ aSelectedShape = aVertPtr->impl<TopoDS_Shape>();
+
+ aSelectedObject =
+ PartSet_Tools::findFixedObjectByExternal(aSelectedShape, aAIS->object(), mySketch);
+ if (!aSelectedObject.get())
+ {
+ FeaturePtr aCreatedFeature;
+ aSelectedObject = PartSet_Tools::createFixedByExternalCenter(aAIS->object(), aAIS->edge(),
+ aAIS->centerType(), mySketch, false, aCreatedFeature);
+ }
+ }
+ }
+
+ GeomPnt2dPtr aSelectedPoint = PartSet_Tools::getPnt2d(aView, aSelectedShape, mySketch);
+ if (!aSelectedPoint) {
+ aSelectedPoint = PartSet_Tools::getPnt2d(theEvent, theWindow, mySketch);
+ setValueState(Stored); // in case of edge selection, Apply state should also be updated
+ }
+ if (aSelectedObject)
+ fillRefAttribute(aSelectedObject);
+ else
+ fillRefAttribute(aSelectedPoint, aFirstValue);
+
+ // next pole of B-spline
+ createNextPoint();
+}
+
+void PartSet_WidgetBSplinePoints::mouseMoved(ModuleBase_IViewWindow* theWindow,
+ QMouseEvent* theEvent)
+{
+ PartSet_Module* aModule = dynamic_cast<PartSet_Module*>(myWorkshop->module());
+
+ if (myFinished || isEditingMode() || aModule->sketchReentranceMgr()->isInternalEditActive())
+ return;
+
+ gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), theWindow->v3dView());
+
+ double aX = 0, aY = 0;
+ PartSet_Tools::convertTo2D(aPoint, mySketch, theWindow->v3dView(), aX, aY);
+ if (myState != ModifiedInViewer)
+ storeCurentValue();
+ // we need to block the value state change
+ bool isBlocked = blockValueState(true);
+ setPoint(aX, aY);
+ blockValueState(isBlocked);
+ setValueState(ModifiedInViewer);
+
+ if (IsPointCreated) {
+ QPoint aPnt = myGroupBox->geometry().bottomLeft();
+ myScrollArea->ensureVisible(aPnt.x(), aPnt.y());
+ IsPointCreated = false;
+ }
+}
+
+bool PartSet_WidgetBSplinePoints::processEscape()
+{
+ bool isProcessed = !isEditingMode();
+ if (isProcessed) {
+ // remove widgets corrsponding to the last pole/weight of B-spline
+ removeLastPoint();
+ myFinished = true;
+
+ emit focusOutWidget(this);
+ }
+ return isProcessed;
+}
+
+bool PartSet_WidgetBSplinePoints::useSelectedShapes() const
+{
+ return true;
+}
+
+AttributeRefAttrListPtr PartSet_WidgetBSplinePoints::attributeRefAttrList() const
+{
+ if (myRefAttribute.empty())
+ return AttributeRefAttrListPtr();
+
+ AttributePtr anAttributeRef = feature()->attribute(myRefAttribute);
+ if (!anAttributeRef.get())
+ return AttributeRefAttrListPtr();
+
+ return std::dynamic_pointer_cast<ModelAPI_AttributeRefAttrList>(anAttributeRef);
+}
+
+void PartSet_WidgetBSplinePoints::fillRefAttribute(GeomPnt2dPtr theClickedPoint,
+ const std::shared_ptr<ModuleBase_ViewerPrs>& theValue)
+{
+ AttributeRefAttrListPtr aRefAttrList = attributeRefAttrList();
+ if (!aRefAttrList.get())
+ return;
+
+ FeaturePtr aFeature = feature();
+ std::string anAttribute = attributeID();
+
+ if (aFeature.get()) {
+ AttributePoint2DPtr aClickedFeaturePoint =
+ PartSet_WidgetPoint2D::findFirstEqualPointInSketch(mySketch, aFeature, theClickedPoint);
+ if (aClickedFeaturePoint.get())
+ aRefAttrList->append(aClickedFeaturePoint);
+ else
+ fillRefAttribute(theValue);
+ }
+}
+
+void PartSet_WidgetBSplinePoints::fillRefAttribute(const ModuleBase_ViewerPrsPtr& theValue)
+{
+ ObjectPtr anObject;
+ if (theValue)
+ anObject = getGeomSelection(theValue);
+ fillRefAttribute(anObject);
+}
+
+void PartSet_WidgetBSplinePoints::fillRefAttribute(const ObjectPtr& theObject)
+{
+ AttributeRefAttrListPtr aRefAttrList = attributeRefAttrList();
+ if (aRefAttrList.get())
+ aRefAttrList->append(theObject);
+}
+
+ObjectPtr PartSet_WidgetBSplinePoints::getGeomSelection(const ModuleBase_ViewerPrsPtr& theValue)
+{
+ ObjectPtr anObject;
+ GeomShapePtr aShape;
+ ModuleBase_ISelection* aSelection = myWorkshop->selection();
+ anObject = aSelection->getResult(theValue);
+ aShape = aSelection->getShape(theValue);
+ myExternalObjectMgr->getGeomSelection(theValue, anObject, aShape, myWorkshop, sketch(), true);
+
+ return anObject;
+}
--- /dev/null
+// 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 PartSet_WidgetBSplinePoints_H
+#define PartSet_WidgetBSplinePoints_H
+
+#include "PartSet.h"
+#include "PartSet_MouseProcessor.h"
+
+#include <ModuleBase_ModelWidget.h>
+
+#include <QObject>
+
+class GeomAPI_Pnt2d;
+class ModelAPI_CompositeFeature;
+class ModuleBase_LabelValue;
+class PartSet_ExternalObjectsMgr;
+class QGroupBox;
+class QScrollArea;
+
+/**\class PartSet_WidgetBSplinePoints
+ * \ingroup Modules
+ * \brief Implementation of model widget to provide widget to input a list of 2D poles
+ * of B-spline curve in association with weights
+ * In XML can be defined as following:
+ * \code
+ * <sketch-bspline_selector id="poles" weights="weights"/>
+ * \endcode
+ */
+class PARTSET_EXPORT PartSet_WidgetBSplinePoints : public ModuleBase_ModelWidget,
+ public PartSet_MouseProcessor
+{
+Q_OBJECT
+public:
+ /// Constructor
+ /// \param theParent the parent object
+ /// \param theWorkshop a current workshop
+ /// \param theData the widget configuation. The attribute of the model widget is obtained from
+ PartSet_WidgetBSplinePoints(QWidget* theParent, ModuleBase_IWorkshop* theWorkshop,
+ const Config_WidgetAPI* theData);
+ /// Destructor
+ virtual ~PartSet_WidgetBSplinePoints();
+
+ /// Fills given container with selection modes if the widget has it
+ /// \param [out] theModuleSelectionModes module additional modes, -1 means all default modes
+ /// \param theModes [out] a container of modes
+ virtual void selectionModes(int& theModuleSelectionModes, QIntList& theModes);
+
+ /// Checks if the selection presentation is valid in widget
+ /// \param theValue a selected presentation in the view
+ /// \return a boolean value
+ virtual bool isValidSelectionCustom(const std::shared_ptr<ModuleBase_ViewerPrs>& theValue);
+
+ /// Checks all attribute validators returns valid. It tries on the given selection
+ /// to current attribute by setting the value inside and calling validators. After this,
+ /// the previous attribute value is restored.The valid/invalid value is cashed.
+ /// \param theValue a selected presentation in the view
+ /// \param theAttribute the attribute
+ /// \return a boolean value
+ bool isValidSelectionForAttribute_(const std::shared_ptr<ModuleBase_ViewerPrs>& theValue,
+ const std::shared_ptr<ModelAPI_Attribute>& theAttribute);
+
+ /// Fills the attribute with the value of the selected owner
+ /// \param thePrs a selected owner
+ bool setSelectionCustom(const std::shared_ptr<ModuleBase_ViewerPrs>& theValue);
+
+ /// Returns list of widget controls
+ /// \return a control list
+ virtual QList<QWidget*> getControls() const;
+
+ /// The methiod called when widget is deactivated
+ virtual void deactivate();
+
+ /// \returns the sketch instance
+ std::shared_ptr<ModelAPI_CompositeFeature> sketch() const { return mySketch; }
+
+ /// Set sketch instance
+ void setSketch(std::shared_ptr<ModelAPI_CompositeFeature> theSketch) { mySketch = theSketch; }
+
+ /// Fill the widget values by given point
+ /// \param theX the X coordinate
+ /// \param theY the Y coordinate
+ /// \returns True in case of success
+ bool setPoint(double theX, double theY);
+
+ /// Returns true if the event is processed.
+ virtual bool processEscape();
+
+ /// Returns true if the attribute can be changed using the selected shapes in the viewer
+ /// and creating a coincidence constraint to them. This control use them.
+ virtual bool useSelectedShapes() const;
+
+ /// Processing the mouse move event in the viewer
+ /// \param theWindow a view window
+ /// \param theEvent a mouse event
+ virtual void mouseMoved(ModuleBase_IViewWindow* theWindow, QMouseEvent* theEvent);
+
+ /// Processing the mouse release event in the viewer
+ /// \param theWindow a view window
+ /// \param theEvent a mouse event
+ virtual void mouseReleased(ModuleBase_IViewWindow* theWindow, QMouseEvent* theEvent);
+
+protected:
+ /// Saves the internal parameters to the given feature
+ /// \return True in success
+ virtual bool storeValueCustom();
+
+ /// Restore value from attribute data to the widget's control
+ virtual bool restoreValueCustom();
+
+ /// Store current value in cashed value
+ void storeCurentValue();
+
+ /// Restore cashed value in the model attribute
+ /// \return boolean state if the restored feature shoud be hidden
+ bool restoreCurentValue();
+
+ /// Fills the widget with default values
+ /// \return true if the widget current value is reset
+ virtual bool resetCustom();
+
+private:
+ /// Create labels for the next B-spline point
+ void createNextPoint();
+ /// Remove labels for the last B-spline point
+ void removeLastPoint();
+
+ /// Save B-spline poles and weights to corresponding attributes
+ void storePolesAndWeights() const;
+
+ /// Returns attribute reference if the key is defined in XML definition of this control
+ /// \return found attribute or null
+ std::shared_ptr<ModelAPI_AttributeRefAttrList> attributeRefAttrList() const;
+
+ void fillRefAttribute(const std::shared_ptr<ModuleBase_ViewerPrs>& theValue);
+ void fillRefAttribute(std::shared_ptr<GeomAPI_Pnt2d> theClickedPoint,
+ const std::shared_ptr<ModuleBase_ViewerPrs>& theValue);
+ void fillRefAttribute(const ObjectPtr& theObject);
+
+ ObjectPtr getGeomSelection(const std::shared_ptr<ModuleBase_ViewerPrs>& theValue);
+
+protected:
+ ModuleBase_IWorkshop* myWorkshop; ///< workshop
+
+private:
+ QGroupBox* myBox;
+ QWidget* myGroupBox; ///< the parent group box for all intenal widgets
+ QScrollArea* myScrollArea;
+ std::vector<ModuleBase_LabelValue*> myXSpin; ///< the label for the X coordinate
+ std::vector<ModuleBase_LabelValue*> myYSpin; ///< the label for the Y coordinate
+ PartSet_ExternalObjectsMgr* myExternalObjectMgr; ///< reference to external objects manager
+
+ /// value used as selection in mouse release method
+ std::shared_ptr<ModuleBase_ViewerPrs> myPreSelected;
+
+ /// it is important during restart operation
+ CompositeFeaturePtr mySketch;
+
+ std::string myRefAttribute; /// if not empty, coincidences are not set but attribute is filled
+
+ bool myValueIsCashed; /// boolean state if the value is cashed during value state change
+ bool myIsFeatureVisibleInCash; /// boolean value if the feature was visible when cash if filled
+ std::vector<double> myXValueInCash; /// the cashed X value during value state change
+ std::vector<double> myYValueInCash; /// the cashed Y value during value state change
+ std::vector<double> myWeightInCash; /// the cached Weight value during valude state change
+
+ std::string myWeightsAttr;
+
+ int myPointIndex; /// index of the changing point
+
+ bool myFinished; /// \c true if building the B-spline is finished (escape pressed)
+};
+
+#endif
GeomShapePtr aShape = theValue->shape();
if (aShape.get() && !aShape->isNull()) {
Handle(V3d_View) aView = myWorkshop->viewer()->activeView();
- double aX = 0, aY = 0;
const TopoDS_Shape& aTDShape = aShape->impl<TopoDS_Shape>();
- if (getPoint2d(aView, aTDShape, aX, aY)) {
- fillRefAttribute(aX, aY, theValue);
+ GeomPnt2dPtr aPnt = PartSet_Tools::getPnt2d(aView, aTDShape, mySketch);
+ if (aPnt) {
+ fillRefAttribute(aPnt->x(), aPnt->y(), theValue);
isDone = true;
}
else if (aTDShape.ShapeType() == TopAbs_EDGE) {
GeomShapePtr aShape = aValue->shape();
if (aShape.get() && !aShape->isNull()) {
Handle(V3d_View) aView = myWorkshop->viewer()->activeView();
- double aX = 0, aY = 0;
const TopoDS_Shape& aTDShape = aShape->impl<TopoDS_Shape>();
- if (getPoint2d(aView, aTDShape, aX, aY)) {
- isDone = setPoint(aX, aY);
- setConstraintToPoint(aX, aY, aValue);
+ GeomPnt2dPtr aPnt = PartSet_Tools::getPnt2d(aView, aTDShape, mySketch);
+ if (aPnt) {
+ isDone = setPoint(aPnt->x(), aPnt->y());
+ setConstraintToPoint(aPnt->x(), aPnt->y(), aValue);
}
}
}
ModuleBase_ModelWidget::deactivate();
}
-bool PartSet_WidgetPoint2D::getPoint2d(const Handle(V3d_View)& theView,
- const TopoDS_Shape& theShape,
- double& theX, double& theY) const
-{
- if (!theShape.IsNull()) {
- if (theShape.ShapeType() == TopAbs_VERTEX) {
- const TopoDS_Vertex& aVertex = TopoDS::Vertex(theShape);
- if (!aVertex.IsNull()) {
- // A case when point is taken from existing vertex
- gp_Pnt aPoint = BRep_Tool::Pnt(aVertex);
- PartSet_Tools::convertTo2D(aPoint, mySketch, theView, theX, theY);
- return true;
- }
- }
- }
- return false;
-}
-
bool PartSet_WidgetPoint2D::setConstraintToPoint(double theClickedX, double theClickedY,
const std::shared_ptr<ModuleBase_ViewerPrs>& theValue)
{
}
}
if (anExternal) {
+ GeomPnt2dPtr aPnt = PartSet_Tools::getPnt2d(aView, aShape, mySketch);
double aX = 0, aY = 0;
- if (getPoint2d(aView, aShape, aX, aY) && isFeatureContainsPoint(myFeature, aX, aY)) {
+ if (aPnt) {
+ aX = aPnt->x();
+ aY = aPnt->y();
+ }
+ if (aPnt && isFeatureContainsPoint(myFeature, aX, aY)) {
// do not create a constraint to the point, which already used by the feature
// if the feature contains the point, focus is not switched
setPoint(aX, aY);
}
else {
- if (getPoint2d(aView, aShape, aX, aY))
+ if (aPnt)
setPoint(aX, aY);
else {
if (aShape.ShapeType() == TopAbs_EDGE) {
}
}
if (!anExternal) {
- double aX = 0, aY = 0;
bool isProcessed = false;
- if (getPoint2d(aView, aShape, aX, aY) && isFeatureContainsPoint(myFeature, aX, aY)) {
+ GeomPnt2dPtr aPnt = PartSet_Tools::getPnt2d(aView, aShape, mySketch);
+ if (aPnt && isFeatureContainsPoint(myFeature, aPnt->x(), aPnt->y())) {
// when the point is selected, the coordinates of the point should be set into the attribute
// if the feature contains the point, focus is not switched
- setPoint(aX, aY);
+ setPoint(aPnt->x(), aPnt->y());
}
else {
+ double aX = 0, aY = 0;
bool anOrphanPoint = isOrphanPoint(aSelectedFeature, mySketch, aX, aY);
// do not set a coincidence constraint in the attribute if the feature contains a point
// with the same coordinates. It is important for line creation in order to do not set
// the same constraints for the same points, oterwise the result line has zero length.
bool isAuxiliaryFeature = false;
- if (getPoint2d(aView, aShape, aX, aY)) {
+ if (aPnt) {
+ aX = aPnt->x();
+ aY = aPnt->y();
setPoint(aX, aY);
setConstraintToPoint(aX, aY, aFirstValue);
}
// external objects e.g. selection of trihedron axis when input end arc point
updateObject(feature());
- double aX = 0, aY = 0;
- if (getPoint2d(aView, aShape, aX, aY)) {
+ GeomPnt2dPtr aPnt = PartSet_Tools::getPnt2d(aView, aShape, mySketch);
+ if (aPnt) {
// do not create a constraint to the point, which already used by the feature
// if the feature contains the point, focus is not switched
- setPoint(aX, aY);
+ setPoint(aPnt->x(), aPnt->y());
}
emit vertexSelected(); // it stops the reentrant operation
emit focusOutWidget(this);
virtual void initializeValueByActivate();
private:
- /// Returns point 2d from selected vertex
- /// \param theView a view window
- /// \param theShape a vertex shape
- /// \param theX an output value of X coordinate
- /// \param theY an output value of Y coordinate
- bool getPoint2d(const Handle(V3d_View)& theView, const TopoDS_Shape& theShape,
- double& theX, double& theY) const;
-
/// Creates constrains of the clicked point
/// \param theClickedX the horizontal coordnate of the point
/// \param theClickedY the vertical coordnate of the point
/// \return true if succed
bool setConstraintToObject(const ObjectPtr& theObject);
+public:
/// Returns if the feature is an orphan point, circle or an arc. Returns true if it
/// has no a coincident to other lines. It processes point, circle and arc features
/// In circle an arc features, only centers are processed, for other points, it returns
const FeaturePtr& theSkipFeature,
const std::shared_ptr<GeomAPI_Pnt2d>& thePoint);
+private:
/// Returns attribute reference if the key is defined in XML definition of this control
/// \return found attribute or null
std::shared_ptr<ModelAPI_AttributeRefAttr> attributeRefAttr() const;
<translation>Groupes</translation>
</message>
</context>
+<context>
+ <name>PartSet_BSplineWidget</name>
+ <message>
+ <source>Poles and weights</source>
+ <translation>Poteaux et poids</translation>
+ </message>
+ <message>
+ <source>B-spline poles and weights</source>
+ <translation>Poteaux et poids B-spline</translation>
+ </message>
+ <message>
+ <source>Pole %1</source>
+ <translation>Pôle %1</translation>
+ </message>
+ <message>
+ <source>Weight :</source>
+ <translation>Poids :</translation>
+ </message>
+ <message>
+ <source>Add a new pole after the current</source>
+ <translation>Ajouter un nouveau pôle après le courant</translation>
+ </message>
+</context>
+<context>
+ <name>PartSet_WidgetBSplinePoints</name>
+ <message>
+ <source>Pole %1</source>
+ <translation>Pôle %1</translation>
+ </message>
+ <message>
+ <source>Create control polygon</source>
+ <translation> Créer un polygone de contrôle</translation>
+ </message>
+ <message>
+ <source>Specify if the control polygon should be created</source>
+ <translation>Spécifiez si le polygone de contrôle doit être créé</translation>
+ </message>
+</context>
</TS>
SET(PROJECT_HEADERS
SketchAPI.h
SketchAPI_Arc.h
+ SketchAPI_BSpline.h
SketchAPI_Circle.h
SketchAPI_Constraint.h
SketchAPI_ConstraintAngle.h
SET(PROJECT_SOURCES
SketchAPI_Arc.cpp
+ SketchAPI_BSpline.cpp
SketchAPI_Circle.cpp
SketchAPI_Constraint.cpp
SketchAPI_ConstraintAngle.cpp
%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::addSpline;
%feature("kwargs") SketchAPI_Sketch::setAngle;
// shared pointers
%shared_ptr(SketchAPI_MacroEllipse)
%shared_ptr(SketchAPI_EllipticArc)
%shared_ptr(SketchAPI_MacroEllipticArc)
+%shared_ptr(SketchAPI_BSpline)
+%shared_ptr(SketchAPI_BSplinePeriodic)
%shared_ptr(SketchAPI_Constraint)
%shared_ptr(SketchAPI_ConstraintAngle)
%shared_ptr(SketchAPI_IntersectionPoint)
%template(InterfaceList) std::list<std::shared_ptr<ModelHighAPI_Interface> >;
%template(EntityList) std::list<std::shared_ptr<SketchAPI_SketchEntity> >;
%template(SketchPointList) std::list<std::shared_ptr<SketchAPI_Point> >;
+%template(GeomPnt2dList) std::list<std::shared_ptr<GeomAPI_Pnt2d> >;
// std::pair -> []
%template(PointRefAttrPair) std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr>;
// fix compilarion error: 'res*' was not declared in this scope
%typemap(freearg) const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr> & {}
+
+%typemap(in) const std::list<std::shared_ptr<GeomAPI_Pnt2d> > & (std::list<std::shared_ptr<GeomAPI_Pnt2d> > temp) {
+ std::shared_ptr<GeomAPI_Pnt2d> * 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<GeomAPI_Pnt2d>(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<GeomAPI_Pnt2d> *), 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<std::shared_ptr<GeomAPI_Pnt2d> >, const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& {
+ std::shared_ptr<GeomAPI_Pnt2d> * 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<GeomAPI_Pnt2d> *), 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<std::shared_ptr<GeomAPI_Pnt2d> > & {}
+
+
// all supported interfaces (the order is very important according dependencies: base class first)
%include "SketchAPI_SketchEntity.h"
%include "SketchAPI_Point.h"
%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"
--- /dev/null
+// 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 <GeomAPI_BSpline2d.h>
+#include <GeomAPI_Pnt2d.h>
+
+#include <GeomAlgoAPI_EdgeBuilder.h>
+
+#include <ModelHighAPI_Double.h>
+#include <ModelHighAPI_Dumper.h>
+#include <ModelHighAPI_Integer.h>
+#include <ModelHighAPI_Selection.h>
+#include <ModelHighAPI_Tools.h>
+
+#include <SketchPlugin_ConstraintCoincidenceInternal.h>
+#include <SketchPlugin_Line.h>
+#include <SketchPlugin_Point.h>
+
+#include <cmath>
+
+
+SketchAPI_BSpline::SketchAPI_BSpline(const std::shared_ptr<ModelAPI_Feature> & theFeature)
+ : SketchAPI_SketchEntity(theFeature)
+{
+ initialize();
+}
+
+SketchAPI_BSpline::SketchAPI_BSpline(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+ bool theInitialize)
+ : SketchAPI_SketchEntity(theFeature)
+{
+ if (theInitialize)
+ initialize();
+}
+
+SketchAPI_BSpline::~SketchAPI_BSpline()
+{
+}
+
+void SketchAPI_BSpline::setByDegreePolesAndWeights(const ModelHighAPI_Integer& theDegree,
+ const std::list<GeomPnt2dPtr>& thePoles,
+ const std::list<ModelHighAPI_Double>& theWeights)
+{
+ std::list<ModelHighAPI_Double> 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<ModelHighAPI_Double> aKnots;
+ std::list<ModelHighAPI_Integer> aMults;
+ getDefaultParameters(thePoles, aWeights, aDegree, aKnots, aMults);
+
+ setByParameters(aDegree, thePoles, aWeights, aKnots, aMults);
+}
+
+void SketchAPI_BSpline::setByParameters(const ModelHighAPI_Integer& theDegree,
+ const std::list<GeomPnt2dPtr>& thePoles,
+ const std::list<ModelHighAPI_Double>& theWeights,
+ const std::list<ModelHighAPI_Double>& theKnots,
+ const std::list<ModelHighAPI_Integer>& theMults)
+{
+ fillAttribute(theDegree, degree());
+
+ fillAttribute(thePoles, poles());
+ if (theWeights.size() <= 1) {
+ // prepare array of equal weights
+ std::list<ModelHighAPI_Double> aWeights(thePoles.size(),
+ theWeights.empty() ? ModelHighAPI_Double(1.0) : theWeights.front());
+ fillAttribute(aWeights, weights());
+ }
+ else
+ fillAttribute(theWeights, weights());
+
+ fillAttribute(theKnots, knots());
+ fillAttribute(theMults, multiplicities());
+
+ if (feature()->getKind() != SketchPlugin_BSplinePeriodic::ID())
+ 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();
+}
+
+static CompositeFeaturePtr sketchForFeature(FeaturePtr theFeature)
+{
+ const std::set<AttributePtr>& aRefs = theFeature->data()->refsToMe();
+ for (std::set<AttributePtr>::const_iterator anIt = aRefs.begin(); anIt != aRefs.end(); ++anIt)
+ if ((*anIt)->id() == SketchPlugin_Sketch::FEATURES_ID())
+ return std::dynamic_pointer_cast<ModelAPI_CompositeFeature>((*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<FeaturePtr>& theEntities)
+{
+ GeomPnt2dPtr aPole = thePoles->pnt(thePoleIndex);
+
+ FeaturePtr aPointFeature = theSketch->addFeature(SketchPlugin_Point::ID());
+ AttributePoint2DPtr aCoord = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ 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<FeaturePtr>& theEntities)
+{
+ int aEndPoleIndex = (theStartPoleIndex + 1) % thePoles->size();
+ GeomPnt2dPtr aStartPoint = thePoles->pnt(theStartPoleIndex);
+ GeomPnt2dPtr aEndPoint = thePoles->pnt(aEndPoleIndex);
+
+ FeaturePtr aLineFeature = theSketch->addFeature(SketchPlugin_Line::ID());
+ AttributePoint2DPtr aLineStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aLineFeature->attribute(SketchPlugin_Line::START_ID()));
+ aLineStart->setValue(aStartPoint);
+ AttributePoint2DPtr aLineEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ 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 << "_" << aEndPoleIndex;
+ 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, aEndPoleIndex);
+
+ theEntities.push_back(aLineFeature);
+}
+
+static void toMapOfAuxIndices(const std::list<int>& theRegular,
+ const std::list<int>& theAuxiliary,
+ std::map<int, bool>& 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<std::shared_ptr<SketchAPI_SketchEntity> > SketchAPI_BSpline::controlPoles(
+ const std::list<int>& regular,
+ const std::list<int>& auxiliary) const
+{
+ std::map<int, bool> anAux;
+ toMapOfAuxIndices(regular, auxiliary, anAux);
+
+ std::list<FeaturePtr> 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<std::shared_ptr<SketchAPI_SketchEntity> > SketchAPI_BSpline::controlPolygon(
+ const std::list<int>& regular,
+ const std::list<int>& auxiliary) const
+{
+ std::map<int, bool> anAux;
+ toMapOfAuxIndices(regular, auxiliary, anAux);
+
+ std::list<FeaturePtr> 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<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+ const std::list<ModelHighAPI_Double>& theWeights,
+ ModelHighAPI_Integer& theDegree,
+ std::list<ModelHighAPI_Double>& theKnots,
+ std::list<ModelHighAPI_Integer>& theMults) const
+{
+ std::shared_ptr<GeomAPI_BSpline2d> aBSplineCurve;
+ try {
+ std::list<double> aWeights;
+ for (std::list<ModelHighAPI_Double>::const_iterator it = theWeights.begin();
+ it != theWeights.end(); ++it)
+ aWeights.push_back(it->value());
+
+ bool isPeriodic = feature()->getKind() == SketchPlugin_BSplinePeriodic::ID();
+ if (theDegree.intValue() < 0)
+ aBSplineCurve.reset(new GeomAPI_BSpline2d(thePoles, aWeights, isPeriodic));
+ else {
+ aBSplineCurve.reset(new GeomAPI_BSpline2d(theDegree.intValue(), thePoles, aWeights,
+ std::list<double>(), std::list<int>(), isPeriodic));
+ }
+ }
+ catch (...) {
+ // cannot build a B-spline curve
+ return;
+ }
+
+ theDegree = aBSplineCurve->degree();
+ std::list<double> aKnots = aBSplineCurve->knots();
+ std::list<int> 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<GeomPnt2dPtr> aPoles;
+ std::list<ModelHighAPI_Double> 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<ModelHighAPI_Double> aKnots;
+ std::list<ModelHighAPI_Integer> 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<ModelHighAPI_Double>::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<ModelHighAPI_Integer>::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<int, FeaturePtr>& thePoints,
+ std::map<int, FeaturePtr>& theSegments)
+{
+ const std::set<AttributePtr>& aRefs = theBSpline->data()->refsToMe();
+ for (std::set<AttributePtr>::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 = " << degree() << ", ";
+ theDumper << "poles = " << poles();
+ if (!isDefaultWeights)
+ theDumper << ", weights = " << weights();
+ if (!isDefaultKnotsMults)
+ theDumper << ", knots = " << knots() << ", multiplicities = " << multiplicities();
+ if (aBase->getKind() == SketchPlugin_BSplinePeriodic::ID())
+ theDumper << ", periodic = True";
+ theDumper << ")" << std::endl;
+ }
+ // dump "auxiliary" flag if necessary
+ SketchAPI_SketchEntity::dump(theDumper);
+
+ // dump control polygon
+ std::map<int, FeaturePtr> 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<int>& theIndices)
+{
+ theDumper << theAttrName << " = [";
+ std::set<int>::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<int, FeaturePtr>& theAuxFeatures) const
+{
+ theDumper << "[";
+ bool isFirst = true;
+ // dump features and split them to auxiliary and regular
+ std::set<int> aRegular, anAuxiliary;
+ for (std::map<int, FeaturePtr>::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;
+}
+
+
+
+// =================================================================================================
+SketchAPI_BSplinePeriodic::SketchAPI_BSplinePeriodic(const FeaturePtr& theFeature)
+ : SketchAPI_BSpline(theFeature, false)
+{
+ initialize();
+}
--- /dev/null
+// 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 <GeomDataAPI_Point2DArray.h>
+
+#include <ModelAPI_AttributeDoubleArray.h>
+
+#include <SketchPlugin_BSpline.h>
+#include <SketchPlugin_BSplinePeriodic.h>
+
+#include <ModelHighAPI_Double.h>
+#include <ModelHighAPI_Integer.h>
+
+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<ModelAPI_Feature>& theFeature);
+
+ /// Destructor.
+ SKETCHAPI_EXPORT
+ virtual ~SketchAPI_BSpline();
+
+ INTERFACE_8(SketchPlugin_BSpline::ID(),
+ poles, SketchPlugin_BSplineBase::POLES_ID(),
+ GeomDataAPI_Point2DArray, /** B-spline poles */,
+ weights, SketchPlugin_BSplineBase::WEIGHTS_ID(),
+ ModelAPI_AttributeDoubleArray, /** B-spline weights */,
+ knots, SketchPlugin_BSplineBase::KNOTS_ID(),
+ ModelAPI_AttributeDoubleArray, /** B-spline knots */,
+ multiplicities, SketchPlugin_BSplineBase::MULTS_ID(),
+ ModelAPI_AttributeIntArray, /** Knots multiplicities */,
+ degree, SketchPlugin_BSplineBase::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_BSplineBase::EXTERNAL_ID(),
+ ModelAPI_AttributeSelection, /** External */)
+
+ /// Set by poles and weights.
+ SKETCHAPI_EXPORT
+ void setByDegreePolesAndWeights(const ModelHighAPI_Integer& theDegree,
+ const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+ const std::list<ModelHighAPI_Double>& theWeights);
+
+ /// Initialize by full set of B-spline parameters.
+ SKETCHAPI_EXPORT
+ void setByParameters(const ModelHighAPI_Integer& theDegree,
+ const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+ const std::list<ModelHighAPI_Double>& theWeights,
+ const std::list<ModelHighAPI_Double>& theKnots,
+ const std::list<ModelHighAPI_Integer>& theMults);
+
+ /// Set by external.
+ SKETCHAPI_EXPORT
+ void setByExternal(const ModelHighAPI_Selection& theExternal);
+
+ /// Generate list of construction points coincident with B-spline poles
+ SKETCHAPI_EXPORT
+ std::list<std::shared_ptr<SketchAPI_SketchEntity> > controlPoles(
+ const std::list<int>& regular = std::list<int>(),
+ const std::list<int>& auxiliary = std::list<int>()) const;
+
+ /// Generate control polygon for B-spline curve
+ SKETCHAPI_EXPORT
+ std::list<std::shared_ptr<SketchAPI_SketchEntity> > controlPolygon(
+ const std::list<int>& regular = std::list<int>(),
+ const std::list<int>& auxiliary = std::list<int>()) const;
+
+ /// Dump wrapped feature
+ SKETCHAPI_EXPORT
+ virtual void dump(ModelHighAPI_Dumper& theDumper) const;
+
+protected:
+ SketchAPI_BSpline(const std::shared_ptr<ModelAPI_Feature>& theFeature, bool theInitialize);
+
+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<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+ const std::list<ModelHighAPI_Double>& theWeights,
+ ModelHighAPI_Integer& theDegree,
+ std::list<ModelHighAPI_Double>& theKnots,
+ std::list<ModelHighAPI_Integer>& 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<int, FeaturePtr>& theAuxFeatures) const;
+};
+
+/// Pointer on B-spline object.
+typedef std::shared_ptr<SketchAPI_BSpline> BSplinePtr;
+
+
+
+/// \class SketchAPI_BSplinePeriodic
+/// \ingroup CPPHighAPI
+/// \brief Interface for BSplinePeriodic feature.
+class SketchAPI_BSplinePeriodic : public SketchAPI_BSpline
+{
+public:
+ /// Constructor without values.
+ SKETCHAPI_EXPORT
+ explicit SketchAPI_BSplinePeriodic(const std::shared_ptr<ModelAPI_Feature>& theFeature);
+
+ /// Destructor.
+ SKETCHAPI_EXPORT
+ virtual ~SketchAPI_BSplinePeriodic() {}
+
+ static std::string ID() { return SketchPlugin_BSplinePeriodic::ID(); }
+ virtual std::string getID() { return SketchPlugin_BSplinePeriodic::ID(); }
+};
+
+#endif // SketchAPI_BSpline_H_
#include "SketchAPI_Projection.h"
#include <SketchPlugin_Line.h>
+#include <SketchPlugin_BSpline.h>
+#include <SketchPlugin_BSplinePeriodic.h>
#include <SketchPlugin_Circle.h>
#include <SketchPlugin_Ellipse.h>
#include <SketchPlugin_EllipticArc.h>
#include <SketchPlugin_Point.h>
#include <SketchAPI_Arc.h>
+#include <SketchAPI_BSpline.h>
#include <SketchAPI_Circle.h>
#include <SketchAPI_Ellipse.h>
#include <SketchAPI_EllipticArc.h>
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_BSplinePeriodic::ID())
+ anEntity.reset(new SketchAPI_BSplinePeriodic(aProjectedFeature));
else if (aProjectedFeature->getKind() == SketchPlugin_Point::ID())
anEntity.reset(new SketchAPI_Point(aProjectedFeature));
#include <ModelHighAPI_Tools.h>
//--------------------------------------------------------------------------------------
#include "SketchAPI_Arc.h"
+#include "SketchAPI_BSpline.h"
#include "SketchAPI_Circle.h"
#include "SketchAPI_Ellipse.h"
#include "SketchAPI_EllipticArc.h"
return EllipticArcPtr(new SketchAPI_EllipticArc(aFeature, theExternalName));
}
+//--------------------------------------------------------------------------------------
+
+std::shared_ptr<SketchAPI_BSpline> SketchAPI_Sketch::addSpline(
+ const ModelHighAPI_Selection & external,
+ const int degree,
+ const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& poles,
+ const std::list<ModelHighAPI_Double>& weights,
+ const std::list<ModelHighAPI_Double>& knots,
+ const std::list<ModelHighAPI_Integer>& multiplicities,
+ const bool periodic)
+{
+ FeaturePtr aFeature = compositeFeature()->addFeature(
+ periodic ? SketchPlugin_BSplinePeriodic::ID() : SketchPlugin_BSpline::ID());
+
+ BSplinePtr aBSpline(periodic ? new SketchAPI_BSplinePeriodic(aFeature)
+ : new SketchAPI_BSpline(aFeature));
+ if (external.variantType() != ModelHighAPI_Selection::VT_Empty)
+ aBSpline->setByExternal(external);
+ else if (knots.empty() || multiplicities.empty())
+ aBSpline->setByDegreePolesAndWeights(degree, poles, weights);
+ else
+ aBSpline->setByParameters(degree, poles, weights, knots, multiplicities);
+
+ return aBSpline;
+}
+
//--------------------------------------------------------------------------------------
std::shared_ptr<SketchAPI_Projection> SketchAPI_Sketch::addProjection(
const ModelHighAPI_Selection & theExternalFeature,
return aMajorAxisEnd ? aMajorAxisEnd->pnt() : std::shared_ptr<GeomAPI_Pnt2d>();
}
-static std::shared_ptr<GeomAPI_Pnt2d> middlePoint(const ObjectPtr& theObject)
+static std::shared_ptr<GeomAPI_Pnt2d> middlePointOnBSpline(const FeaturePtr& theFeature,
+ const CompositeFeaturePtr& theSketch)
+{
+ GeomAPI_Edge anEdge(theFeature->lastResult()->shape());
+ GeomPointPtr aMiddle = anEdge.middlePoint();
+
+ std::shared_ptr<SketchPlugin_Sketch> aSketch =
+ std::dynamic_pointer_cast<SketchPlugin_Sketch>(theSketch);
+ return aSketch->to2D(aMiddle);
+}
+
+static std::shared_ptr<GeomAPI_Pnt2d> middlePoint(const ObjectPtr& theObject,
+ const CompositeFeaturePtr& theSketch)
{
std::shared_ptr<GeomAPI_Pnt2d> aMiddlePoint;
FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
aMiddlePoint = pointOnEllipse(aFeature);
else if (aFeatureKind == SketchPlugin_EllipticArc::ID())
aMiddlePoint = pointOnEllipse(aFeature, false);
+ else if (aFeatureKind == SketchPlugin_BSpline::ID() ||
+ aFeatureKind == SketchPlugin_BSplinePeriodic::ID())
+ aMiddlePoint = middlePointOnBSpline(aFeature, theSketch);
}
return aMiddlePoint;
}
if (aMessage->movedAttribute())
anOriginalPosition = pointCoordinates(aMessage->movedAttribute());
else
- anOriginalPosition = middlePoint(aMessage->movedObject());
+ anOriginalPosition = middlePoint(aMessage->movedObject(), compositeFeature());
if (!anOriginalPosition)
return; // something has gone wrong, do not process movement
#include <ModelHighAPI_Interface.h>
#include <ModelHighAPI_Macro.h>
+#include <ModelHighAPI_Selection.h>
//--------------------------------------------------------------------------------------
class ModelAPI_CompositeFeature;
class ModelAPI_Object;
class ModelHighAPI_Integer;
class ModelHighAPI_RefAttr;
class ModelHighAPI_Reference;
-class ModelHighAPI_Selection;
class SketchAPI_Arc;
class SketchAPI_MacroArc;
class SketchAPI_Circle;
class SketchAPI_MacroEllipse;
class SketchAPI_EllipticArc;
class SketchAPI_MacroEllipticArc;
+class SketchAPI_BSpline;
class SketchAPI_IntersectionPoint;
class SketchAPI_Line;
class SketchAPI_Mirror;
SKETCHAPI_EXPORT
std::shared_ptr<SketchAPI_EllipticArc> addEllipticArc(const std::string & theExternalName);
+ /// Add B-spline
+ SKETCHAPI_EXPORT
+ std::shared_ptr<SketchAPI_BSpline> addSpline(
+ const ModelHighAPI_Selection & external = ModelHighAPI_Selection(),
+ const int degree = -1,
+ const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& poles =
+ std::list<std::shared_ptr<GeomAPI_Pnt2d> >(),
+ const std::list<ModelHighAPI_Double>& weights = std::list<ModelHighAPI_Double>(),
+ const std::list<ModelHighAPI_Double>& knots = std::list<ModelHighAPI_Double>(),
+ const std::list<ModelHighAPI_Integer>& multiplicities = std::list<ModelHighAPI_Integer>(),
+ const bool periodic = false);
+
/// Add projection
SKETCHAPI_EXPORT
std::shared_ptr<SketchAPI_Projection> addProjection(
#include "SketchAPI_SketchEntity.h"
#include <SketchAPI_Arc.h>
+#include <SketchAPI_BSpline.h>
#include <SketchAPI_Circle.h>
#include <SketchAPI_Ellipse.h>
#include <SketchAPI_EllipticArc.h>
#include <ModelHighAPI_Tools.h>
#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_BSpline.h>
#include <SketchPlugin_Circle.h>
#include <SketchPlugin_Ellipse.h>
#include <SketchPlugin_IntersectionPoint.h>
aResult.push_back(std::shared_ptr<SketchAPI_SketchEntity>(new SketchAPI_Ellipse(*anIt)));
else if ((*anIt)->getKind() == SketchPlugin_EllipticArc::ID())
aResult.push_back(std::shared_ptr<SketchAPI_SketchEntity>(new SketchAPI_EllipticArc(*anIt)));
+ else if ((*anIt)->getKind() == SketchPlugin_BSpline::ID())
+ aResult.push_back(std::shared_ptr<SketchAPI_SketchEntity>(new SketchAPI_BSpline(*anIt)));
+ else if ((*anIt)->getKind() == SketchPlugin_BSplinePeriodic::ID()) {
+ aResult.push_back(
+ std::shared_ptr<SketchAPI_SketchEntity>(new SketchAPI_BSplinePeriodic(*anIt)));
+ }
else if ((*anIt)->getKind() == SketchPlugin_Point::ID())
aResult.push_back(std::shared_ptr<SketchAPI_SketchEntity>(new SketchAPI_Point(*anIt)));
else if ((*anIt)->getKind() == SketchPlugin_IntersectionPoint::ID())
#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"
SET(PROJECT_HEADERS
SketchPlugin.h
SketchPlugin_Arc.h
+ SketchPlugin_BSpline.h
+ SketchPlugin_BSplineBase.h
+ SketchPlugin_BSplinePeriodic.h
SketchPlugin_Circle.h
SketchPlugin_Constraint.h
SketchPlugin_ConstraintAngle.h
SketchPlugin_Line.h
SketchPlugin_MacroArc.h
SketchPlugin_MacroArcReentrantMessage.h
+ SketchPlugin_MacroBSpline.h
SketchPlugin_MacroCircle.h
SketchPlugin_MacroEllipse.h
SketchPlugin_MacroEllipticArc.h
SketchPlugin_Point.h
SketchPlugin_Projection.h
SketchPlugin_Sketch.h
+ SketchPlugin_SketchDrawer.h
SketchPlugin_SketchEntity.h
SketchPlugin_Split.h
SketchPlugin_Tools.h
SketchPlugin_Trim.h
SketchPlugin_Validators.h
- SketchPlugin_SketchDrawer.h
)
SET(PROJECT_SOURCES
SketchPlugin_Arc.cpp
+ SketchPlugin_BSpline.cpp
+ SketchPlugin_BSplineBase.cpp
+ SketchPlugin_BSplinePeriodic.cpp
SketchPlugin_Circle.cpp
SketchPlugin_Constraint.cpp
SketchPlugin_ConstraintAngle.cpp
SketchPlugin_IntersectionPoint.cpp
SketchPlugin_Line.cpp
SketchPlugin_MacroArc.cpp
+ SketchPlugin_MacroBSpline.cpp
SketchPlugin_MacroCircle.cpp
SketchPlugin_MacroEllipse.cpp
SketchPlugin_MacroEllipticArc.cpp
SketchPlugin_Point.cpp
SketchPlugin_Projection.cpp
SketchPlugin_Sketch.cpp
+ SketchPlugin_SketchDrawer.cpp
SketchPlugin_SketchEntity.cpp
SketchPlugin_Split.cpp
SketchPlugin_Tools.cpp
SketchPlugin_Trim.cpp
SketchPlugin_Validators.cpp
- SketchPlugin_SketchDrawer.cpp
)
SET(PROJECT_LIBRARIES
GeomAlgoAPI
ModelAPI
ModelGeomAlgo
+ ModuleBase
SketcherPrs
GeomDataAPI
)
)
SET(TEXT_RESOURCES
- SketchPlugin_msg_en.ts
- SketchPlugin_msg_fr.ts
+ SketchPlugin_msg_en.ts
+ SketchPlugin_msg_fr.ts
)
+# sources / moc wrappings
+QT_WRAP_MOC(PROJECT_AUTOMOC ${PROJECT_MOC_HEADERS})
+
+SOURCE_GROUP ("Generated Files" FILES ${PROJECT_AUTOMOC})
SOURCE_GROUP ("Resource Files" FILES ${TEXT_RESOURCES})
ADD_DEFINITIONS(-DSKETCHPLUGIN_EXPORTS)
-ADD_LIBRARY(SketchPlugin MODULE ${PROJECT_SOURCES} ${PROJECT_HEADERS} ${XML_RESOURCES} ${TEXT_RESOURCES})
+ADD_LIBRARY(SketchPlugin MODULE ${PROJECT_SOURCES} ${PROJECT_HEADERS} ${XML_RESOURCES} ${TEXT_RESOURCES} ${PROJECT_AUTOMOC})
TARGET_LINK_LIBRARIES(SketchPlugin ${PROJECT_LIBRARIES})
INCLUDE_DIRECTORIES(
../Events
../ModelAPI
../ModelGeomAlgo
+ ../ModuleBase
../GeomAPI
../GeomAlgoAPI
../GeomDataAPI
../SketcherPrs
+ ${OpenCASCADE_INCLUDE_DIR}
)
INSTALL(TARGETS SketchPlugin DESTINATION ${SHAPER_INSTALL_PLUGIN_FILES})
TestConstraintAngleBehaviorBackward_2.py
TestConstraintAngleEllipse.py
TestConstraintCoincidence.py
+ TestConstraintCoincidenceBSpline.py
TestConstraintCoincidenceEllipse.py
TestConstraintCoincidenceEllipticArc.py
TestConstraintCollinear.py
TestConstraintRadius.py
TestConstraintRadiusFailure.py
TestConstraintTangent.py
+ TestConstraintTangentBSpline.py
TestConstraintTangentEllipse.py
TestConstraintTangentEllipticArc.py
TestConstraintVertical.py
TestCreateArcByThreePoints.py
TestCreateArcByTransversalLine.py
TestCreateArcChangeType.py
+ TestCreateBSpline.py
+ TestCreateBSplinePeriodic.py
TestCreateCircleByCenterAndPassed.py
TestCreateCircleByThreePoints.py
TestCreateCircleChangeType.py
TestMultiTranslation.py
TestPresentation.py
TestProjection.py
+ TestProjectionBSpline.py
+ TestProjectionBSplinePeriodic.py
TestProjectionEllipse.py
TestProjectionEllipticArc.py
TestProjectionIntoResult.py
TestProjectionUpdate.py
TestRectangle.py
TestRemainingDoF.py
+ TestRemoveBSpline.py
+ TestRemoveBSplinePeriodic.py
TestRemoveEllipse.py
TestRemoveEllipticArc.py
TestRemoveSketch.py
if(${SKETCHER_CHANGE_RADIUS_WHEN_MOVE})
ADD_UNIT_TESTS(
TestMoveArc.py
+ TestMoveBSpline.py
+ TestMoveBSplinePeriodic.py
TestMoveCircle.py
TestMoveEllipse.py
TestMoveEllipticArc.py
--- /dev/null
+// 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 <SketchPlugin_BSpline.h>
+
+#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
+
+
+SketchPlugin_BSpline::SketchPlugin_BSpline()
+ : SketchPlugin_BSplineBase()
+{
+}
+
+void SketchPlugin_BSpline::initDerivedClassAttributes()
+{
+ data()->addAttribute(START_ID(), GeomDataAPI_Point2D::typeId());
+ data()->addAttribute(END_ID(), GeomDataAPI_Point2D::typeId());
+
+ SketchPlugin_BSplineBase::initDerivedClassAttributes();
+}
+
+void SketchPlugin_BSpline::attributeChanged(const std::string& theID) {
+ if (theID == POLES_ID()) {
+ AttributePoint2DArrayPtr aPolesArray =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(attribute(POLES_ID()));
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ attribute(START_ID()))->setValue(aPolesArray->pnt(0));
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ attribute(END_ID()))->setValue(aPolesArray->pnt(aPolesArray->size() - 1));
+ }
+ else
+ SketchPlugin_BSplineBase::attributeChanged(theID);
+}
--- /dev/null
+// 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 SketchPlugin_BSpline_H_
+#define SketchPlugin_BSpline_H_
+
+#include <SketchPlugin_BSplineBase.h>
+
+/**\class SketchPlugin_BSpline
+ * \ingroup Plugins
+ * \brief Feature for creation of the B-spline curve in the sketch.
+ */
+class SketchPlugin_BSpline : public SketchPlugin_BSplineBase
+{
+public:
+ /// B-spline feature kind
+ inline static const std::string& ID()
+ {
+ static const std::string ID("SketchBSpline");
+ return ID;
+ }
+
+ /// start point of B-spline curve
+ inline static const std::string& START_ID()
+ {
+ static const std::string ID("start_point");
+ return ID;
+ }
+ /// end point of B-spline curve
+ inline static const std::string& END_ID()
+ {
+ static const std::string ID("end_point");
+ return ID;
+ }
+
+ /// Returns the kind of a feature
+ SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
+ {
+ static std::string MY_KIND = SketchPlugin_BSpline::ID();
+ return MY_KIND;
+ }
+
+ /// Called on change of any argument-attribute of this object
+ SKETCHPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID);
+
+ /// Use plugin manager for features creation
+ SketchPlugin_BSpline();
+
+protected:
+ /// \brief Initializes attributes of derived class.
+ virtual void initDerivedClassAttributes();
+
+ virtual bool isPeriodic() const { return false; }
+};
+
+#endif
--- /dev/null
+// 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 <SketchPlugin_BSplineBase.h>
+
+#include <SketchPlugin_ConstraintCoincidenceInternal.h>
+#include <SketchPlugin_Line.h>
+#include <SketchPlugin_MacroBSpline.h>
+#include <SketchPlugin_Sketch.h>
+
+#include <Events_InfoMessage.h>
+
+#include <GeomAlgoAPI_EdgeBuilder.h>
+
+#include <GeomAPI_BSpline2d.h>
+#include <GeomAPI_Pnt2d.h>
+
+#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
+
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeDoubleArray.h>
+#include <ModelAPI_AttributeIntArray.h>
+#include <ModelAPI_AttributeInteger.h>
+#include <ModelAPI_ResultConstruction.h>
+#include <ModelAPI_Session.h>
+#include <ModelAPI_Validator.h>
+
+
+SketchPlugin_BSplineBase::SketchPlugin_BSplineBase()
+ : SketchPlugin_SketchEntity()
+{
+}
+
+void SketchPlugin_BSplineBase::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());
+ ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EXTERNAL_ID());
+}
+
+void SketchPlugin_BSplineBase::execute()
+{
+ SketchPlugin_Sketch* aSketch = sketch();
+ if(!aSketch) {
+ return;
+ }
+
+ AttributePoint2DArrayPtr aPolesArray =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(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<GeomPnt2dPtr> aPoles2D;
+ for (int anIndex = 0; anIndex < aPolesArray->size(); ++anIndex) {
+ GeomPnt2dPtr aPole = aPolesArray->pnt(anIndex);
+ aPoles2D.push_back(aPole);
+ }
+ // collect weights
+ std::list<double> aWeights;
+ for (int anIndex = 0; anIndex < aWeightsArray->size(); ++anIndex)
+ aWeights.push_back(aWeightsArray->value(anIndex));
+ // collect knots
+ std::list<double> aKnots;
+ for (int anIndex = 0; anIndex < aKnotsArray->size(); ++anIndex)
+ aKnots.push_back(aKnotsArray->value(anIndex));
+ // collect multiplicities
+ std::list<int> aMults;
+ for (int anIndex = 0; anIndex < aMultsArray->size(); ++anIndex)
+ aMults.push_back(aMultsArray->value(anIndex));
+
+ // create result B-spline curve
+ GeomShapePtr anEdge = GeomAlgoAPI_EdgeBuilder::bsplineOnPlane(aSketch->coordinatePlane(),
+ aPoles2D, aWeights, aKnots, aMults, aDegreeAttr->value(), isPeriodic());
+
+ ResultConstructionPtr aResult = document()->createConstruction(data(), 0);
+ aResult->setShape(anEdge);
+ aResult->setIsInHistory(false);
+ setResult(aResult, 0);
+}
+
+bool SketchPlugin_BSplineBase::isFixed() {
+ return data()->selection(EXTERNAL_ID())->context().get() != NULL;
+}
+
+void SketchPlugin_BSplineBase::attributeChanged(const std::string& theID) {
+ // the second condition for unability to move external segments anywhere
+ if (theID == EXTERNAL_ID() || isFixed()) {
+ std::shared_ptr<GeomAPI_Shape> aSelection = data()->selection(EXTERNAL_ID())->value();
+ if (!aSelection) {
+ // empty shape in selection shows that the shape is equal to context
+ ResultPtr anExtRes = selection(EXTERNAL_ID())->context();
+ if (anExtRes)
+ aSelection = anExtRes->shape();
+ }
+//// // update arguments due to the selection value
+//// if (aSelection && !aSelection->isNull() && aSelection->isEdge()) {
+//// std::shared_ptr<GeomAPI_Edge> anEdge(new GeomAPI_Edge(aSelection));
+//// std::shared_ptr<GeomAPI_Ellipse> anEllipse = anEdge->ellipse();
+////
+//// bool aWasBlocked = data()->blockSendAttributeUpdated(true);
+//// std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr =
+//// std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_ID()));
+//// aCenterAttr->setValue(sketch()->to2D(anEllipse->center()));
+////
+//// std::shared_ptr<GeomDataAPI_Point2D> aFocusAttr =
+//// std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(FIRST_FOCUS_ID()));
+//// aFocusAttr->setValue(sketch()->to2D(anEllipse->firstFocus()));
+////
+//// std::shared_ptr<GeomDataAPI_Point2D> aStartAttr =
+//// std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(START_POINT_ID()));
+//// aStartAttr->setValue(sketch()->to2D(anEdge->firstPoint()));
+////
+//// std::shared_ptr<GeomDataAPI_Point2D> aEndAttr =
+//// std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(END_POINT_ID()));
+//// aEndAttr->setValue(sketch()->to2D(anEdge->lastPoint()));
+////
+//// real(MAJOR_RADIUS_ID())->setValue(anEllipse->majorRadius());
+//// real(MINOR_RADIUS_ID())->setValue(anEllipse->minorRadius());
+////
+//// double aStartParam, aMidParam, aEndParam;
+//// anEllipse->parameter(anEdge->firstPoint(), tolerance, aStartParam);
+//// anEllipse->parameter(anEdge->middlePoint(), tolerance, aMidParam);
+//// anEllipse->parameter(anEdge->lastPoint(), tolerance, aEndParam);
+//// if (aEndParam < aStartParam)
+//// aEndParam += 2.0 * PI;
+//// if (aMidParam < aStartParam)
+//// aMidParam += 2.0 * PI;
+//// boolean(REVERSED_ID())->setValue(aMidParam > aEndParam);
+////
+//// data()->blockSendAttributeUpdated(aWasBlocked, false);
+////
+//// fillCharacteristicPoints();
+//// }
+ }
+}
+
+bool SketchPlugin_BSplineBase::customAction(const std::string& theActionId)
+{
+ // parse for the action and an index divided by '#'
+ std::string anAction;
+ int anIndex = -1;
+ size_t pos = theActionId.find('#');
+ if (pos != std::string::npos) {
+ anAction = theActionId.substr(0, pos);
+ anIndex = std::stoi(theActionId.substr(pos + 1));
+ }
+
+ if (anAction == ADD_POLE_ACTION_ID()) {
+ return addPole(anIndex);
+ }
+
+ std::string aMsg = "Error: Feature \"%1\" does not support action \"%2\".";
+ Events_InfoMessage("SketchPlugin_BSplineBase", aMsg).arg(getKind()).arg(anAction).send();
+ return false;
+}
+
+bool SketchPlugin_BSplineBase::addPole(const int theAfter)
+{
+ AttributePoint2DArrayPtr aPolesArray =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(attribute(POLES_ID()));
+ AttributeDoubleArrayPtr aWeightsArray = data()->realArray(WEIGHTS_ID());
+
+ int anAfter = (!isPeriodic() && theAfter == aPolesArray->size() - 1) ? theAfter - 1 : theAfter;
+
+ // find internal coincidences applied to the poles with greater indices
+ std::list<AttributeIntegerPtr> aCoincidentPoleIndex;
+ bool hasAuxSegment = false;
+ const std::set<AttributePtr>& aRefs = data()->refsToMe();
+ for (std::set<AttributePtr>::iterator anIt = aRefs.begin(); anIt != aRefs.end(); ++anIt) {
+ FeaturePtr aFeature = ModelAPI_Feature::feature((*anIt)->owner());
+ if (aFeature->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID()) {
+ AttributeIntegerPtr anIndex;
+ if ((*anIt)->id() == SketchPlugin_ConstraintCoincidenceInternal::ENTITY_A())
+ anIndex = aFeature->integer(SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_A());
+ else if ((*anIt)->id() == SketchPlugin_ConstraintCoincidenceInternal::ENTITY_B())
+ anIndex = aFeature->integer(SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_B());
+
+ if (anIndex && anIndex->isInitialized()) {
+ if (anIndex->value() > anAfter)
+ aCoincidentPoleIndex.push_back(anIndex);
+ else if (anIndex->value() == anAfter && !hasAuxSegment) {
+ // check the constrained object is a segment of the control polygon
+ const std::string& anOtherAttr =
+ (*anIt)->id() == SketchPlugin_ConstraintCoincidenceInternal::ENTITY_A() ?
+ SketchPlugin_ConstraintCoincidenceInternal::ENTITY_B() :
+ SketchPlugin_ConstraintCoincidenceInternal::ENTITY_A();
+ AttributeRefAttrPtr aRefAttr = aFeature->refattr(anOtherAttr);
+ if (aRefAttr && !aRefAttr->isObject() &&
+ aRefAttr->attr()->id() == SketchPlugin_Line::START_ID()) {
+ hasAuxSegment = true;
+ aCoincidentPoleIndex.push_back(anIndex);
+ }
+ }
+ }
+ }
+ }
+
+ bool aWasBlocked = data()->blockSendAttributeUpdated(true);
+
+ // add new pole and default weight
+ std::list<GeomPnt2dPtr> aPoles;
+ aPolesArray->setSize(aPolesArray->size() + 1);
+ aPolesArray->setPnt(aPolesArray->size() - 1, aPolesArray->pnt(0)); // for periodic spline
+ for (int i = aPolesArray->size() - 2; i > anAfter; --i) {
+ aPoles.push_front(aPolesArray->pnt(i));
+ aPolesArray->setPnt(i + 1, aPoles.front());
+ }
+
+ GeomPnt2dPtr aCurPole = aPolesArray->pnt(anAfter);
+ GeomPnt2dPtr aNextPole = aPolesArray->pnt(anAfter + 1);
+ aPolesArray->setPnt(anAfter + 1, (aCurPole->x() + aNextPole->x()) * 0.5,
+ (aCurPole->y() + aNextPole->y()) * 0.5);
+ for (int i = anAfter + 1; i >= 0; --i)
+ aPoles.push_front(aPolesArray->pnt(i));
+
+ std::list<double> aWeights;
+ for (int i = 0; i < aWeightsArray->size(); ++i) {
+ aWeights.push_back(aWeightsArray->value(i));
+ if (i == anAfter)
+ aWeights.push_back(1.0); // default weight
+ }
+ aWeightsArray->setSize(aWeightsArray->size() + 1);
+ std::list<double>::iterator aWIt = aWeights.begin();
+ for (int i = 0; i < aWeightsArray->size(); ++i, ++aWIt)
+ aWeightsArray->setValue(i, *aWIt);
+
+ // recalculate knots and multiplicities
+ std::shared_ptr<GeomAPI_BSpline2d> aBSplineCurve(
+ new GeomAPI_BSpline2d(aPoles, aWeights, isPeriodic()));
+
+ integer(DEGREE_ID())->setValue(aBSplineCurve->degree());
+
+ AttributeDoubleArrayPtr aKnotsAttr = data()->realArray(SketchPlugin_BSplineBase::KNOTS_ID());
+ std::list<double> aKnots = aBSplineCurve->knots();
+ int aSize = (int)aKnots.size();
+ aKnotsAttr->setSize(aSize);
+ std::list<double>::iterator aKIt = aKnots.begin();
+ for (int index = 0; index < aSize; ++index, ++aKIt)
+ aKnotsAttr->setValue(index, *aKIt);
+
+ AttributeIntArrayPtr aMultsAttr = data()->intArray(SketchPlugin_BSplineBase::MULTS_ID());
+ std::list<int> aMults = aBSplineCurve->mults();
+ aSize = (int)aMults.size();
+ aMultsAttr->setSize(aSize);
+ std::list<int>::iterator aMIt = aMults.begin();
+ for (int index = 0; index < aSize; ++index, ++aMIt)
+ aMultsAttr->setValue(index, *aMIt);
+
+ data()->blockSendAttributeUpdated(aWasBlocked, true);
+
+ // update indices of internal coincidences
+ for (std::list<AttributeIntegerPtr>::iterator aCIt = aCoincidentPoleIndex.begin();
+ aCIt != aCoincidentPoleIndex.end(); ++aCIt)
+ (*aCIt)->setValue((*aCIt)->value() + 1);
+
+ // create auxiliary segment and pole updating the control polygon
+ SketchPlugin_MacroBSpline::createAuxiliaryPole(aPolesArray, anAfter + 1);
+ if (hasAuxSegment)
+ SketchPlugin_MacroBSpline::createAuxiliarySegment(aPolesArray, anAfter, anAfter + 1);
+
+ return true;
+}
--- /dev/null
+// 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 SketchPlugin_BSplineBase_H_
+#define SketchPlugin_BSplineBase_H_
+
+#include <SketchPlugin.h>
+#include <SketchPlugin_SketchEntity.h>
+
+/**\class SketchPlugin_BSplineBase
+ * \ingroup Plugins
+ * \brief Base class for B-spline curves in the sketch.
+ */
+class SketchPlugin_BSplineBase : public SketchPlugin_SketchEntity
+{
+public:
+ /// list of B-spline poles
+ inline static const std::string& POLES_ID()
+ {
+ static const std::string ID("poles");
+ return ID;
+ }
+
+ /// list of B-spline weights
+ inline static const std::string& WEIGHTS_ID()
+ {
+ static const std::string ID("weights");
+ 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;
+ }
+
+ /// 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;
+ }
+
+ /// name for add pole action
+ inline static const std::string& ADD_POLE_ACTION_ID()
+ {
+ static const std::string ID("AddPole");
+ return ID;
+ }
+
+ /// Returns true is sketch element is under the rigid constraint
+ SKETCHPLUGIN_EXPORT virtual bool isFixed();
+
+ /// Called on change of any argument-attribute of this object
+ SKETCHPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID);
+
+ /// Creates a new part document if needed
+ SKETCHPLUGIN_EXPORT virtual void execute();
+
+ /// Updates the B-spline curve.
+ /// \param[in] theActionId action key id (in following form: Action#Index)
+ /// \return \c false in case the action not performed.
+ SKETCHPLUGIN_EXPORT virtual bool customAction(const std::string& theActionId);
+
+protected:
+ /// Called from the derived class
+ SketchPlugin_BSplineBase();
+
+ /// \brief Initializes attributes of derived class.
+ virtual void initDerivedClassAttributes();
+
+ /// \brief Return \c true if the B-spline curve is periodic
+ virtual bool isPeriodic() const = 0;
+
+ /// Add new pole after the pole with the given index
+ bool addPole(const int theAfter);
+};
+
+#endif
--- /dev/null
+// 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 <SketchPlugin_BSplinePeriodic.h>
+
+SketchPlugin_BSplinePeriodic::SketchPlugin_BSplinePeriodic()
+ : SketchPlugin_BSplineBase()
+{
+}
--- /dev/null
+// 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 SketchPlugin_BSplinePeriodic_H_
+#define SketchPlugin_BSplinePeriodic_H_
+
+#include <SketchPlugin_BSplineBase.h>
+
+/**\class SketchPlugin_BSplinePeriodic
+ * \ingroup Plugins
+ * \brief Feature for creation of the periodic B-spline curve in the sketch.
+ */
+class SketchPlugin_BSplinePeriodic : public SketchPlugin_BSplineBase
+{
+public:
+ /// B-spline feature kind
+ inline static const std::string& ID()
+ {
+ static const std::string ID("SketchBSplinePeriodic");
+ return ID;
+ }
+
+ /// Returns the kind of a feature
+ SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
+ {
+ static std::string MY_KIND = SketchPlugin_BSplinePeriodic::ID();
+ return MY_KIND;
+ }
+
+ /// Use plugin manager for features creation
+ SketchPlugin_BSplinePeriodic();
+
+protected:
+ virtual bool isPeriodic() const { return true; }
+};
+
+#endif
#include "SketchPlugin_ConstraintCoincidenceInternal.h"
+#include <ModelAPI_AttributeInteger.h>
+#include <ModelAPI_Session.h>
+#include <ModelAPI_Validator.h>
+
SketchPlugin_ConstraintCoincidenceInternal::SketchPlugin_ConstraintCoincidenceInternal()
{
}
void SketchPlugin_ConstraintCoincidenceInternal::initAttributes()
{
SketchPlugin_ConstraintCoincidence::initAttributes();
+
+ data()->addAttribute(INDEX_ENTITY_A(), ModelAPI_AttributeInteger::typeId());
+ ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), INDEX_ENTITY_A());
+
+ data()->addAttribute(INDEX_ENTITY_B(), ModelAPI_AttributeInteger::typeId());
+ ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), INDEX_ENTITY_B());
}
void SketchPlugin_ConstraintCoincidenceInternal::execute()
class SketchPlugin_ConstraintCoincidenceInternal : public SketchPlugin_ConstraintCoincidence
{
public:
- /// Coincidence constraint kind
+ /// \brief Coincidence constraint kind
inline static const std::string& ID()
{
static const std::string MY_CONSTRAINT_COINCIDENCE_ID("SketchConstraintCoincidenceInternal");
return MY_KIND;
}
- /// Returns the AIS preview
+ /// \brief Index of point in the array if the first attribute is an array
+ inline static const std::string& INDEX_ENTITY_A()
+ {
+ static const std::string MY_INDEX("ConstraintEntityA_Index");
+ return MY_INDEX;
+ }
+ /// \brief Index of point in the array if the second attribute is an array
+ inline static const std::string& INDEX_ENTITY_B()
+ {
+ static const std::string MY_INDEX("ConstraintEntityB_Index");
+ return MY_INDEX;
+ }
+
+ /// \brief Returns the AIS preview
SKETCHPLUGIN_EXPORT virtual AISObjectPtr getAISObject(AISObjectPtr thePrevious);
/// \brief Creates a new part document if needed
--- /dev/null
+// 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 <SketchPlugin_MacroBSpline.h>
+
+#include <SketchPlugin_BSpline.h>
+#include <SketchPlugin_BSplinePeriodic.h>
+#include <SketchPlugin_ConstraintCoincidenceInternal.h>
+#include <SketchPlugin_Line.h>
+#include <SketchPlugin_Point.h>
+#include <SketchPlugin_Tools.h>
+#include <SketchPlugin_Sketch.h>
+
+#include <ModelAPI_AttributeDoubleArray.h>
+#include <ModelAPI_AttributeInteger.h>
+#include <ModelAPI_AttributeRefAttrList.h>
+#include <ModelAPI_Events.h>
+#include <ModelAPI_EventReentrantMessage.h>
+#include <ModelAPI_Session.h>
+#include <ModelAPI_Validator.h>
+
+#include <GeomDataAPI_Point2DArray.h>
+
+#include <GeomAlgoAPI_CompoundBuilder.h>
+#include <GeomAlgoAPI_EdgeBuilder.h>
+#include <GeomAlgoAPI_PointBuilder.h>
+
+#include <GeomAPI_BSpline2d.h>
+
+#include <sstream>
+
+/// Create internal coincidence constraint with B-spline pole
+static void createInternalConstraint(SketchPlugin_Sketch* theSketch,
+ AttributePtr thePoint,
+ AttributePtr theBSplinePoles,
+ const int thePoleIndex);
+
+
+SketchPlugin_MacroBSpline::SketchPlugin_MacroBSpline()
+ : SketchPlugin_SketchEntity(),
+ myDegree(3),
+ myIsPeriodic(false)
+{
+}
+
+SketchPlugin_MacroBSpline::SketchPlugin_MacroBSpline(bool isPeriodic)
+ : SketchPlugin_SketchEntity(),
+ myDegree(3),
+ myIsPeriodic(isPeriodic)
+{
+}
+
+void SketchPlugin_MacroBSpline::initAttributes()
+{
+ data()->addAttribute(POLES_ID(), GeomDataAPI_Point2DArray::typeId());
+ data()->addAttribute(WEIGHTS_ID(), ModelAPI_AttributeDoubleArray::typeId());
+
+ data()->addAttribute(REF_POLES_ID(), ModelAPI_AttributeRefAttrList::typeId());
+ ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), REF_POLES_ID());
+
+ data()->addAttribute(CONTROL_POLYGON_ID(), ModelAPI_AttributeBoolean::typeId());
+
+ data()->addAttribute(AUXILIARY_ID(), ModelAPI_AttributeBoolean::typeId());
+}
+
+void SketchPlugin_MacroBSpline::execute()
+{
+ FeaturePtr aBSpline = createBSplineFeature();
+
+ if (boolean(CONTROL_POLYGON_ID())->value()) {
+ std::list<FeaturePtr> aControlPoles;
+ createControlPolygon(aBSpline, aControlPoles);
+ constraintsForPoles(aControlPoles);
+
+ // message to init reentrant operation
+ static Events_ID anId = ModelAPI_EventReentrantMessage::eventId();
+ ReentrantMessagePtr aMessage(new ModelAPI_EventReentrantMessage(anId, this));
+ // set here the last pole to make coincidence with the start point of the next B-spline curve
+ aMessage->setCreatedFeature(aControlPoles.back());
+ Events_Loop::loop()->send(aMessage);
+ }
+}
+
+// LCOV_EXCL_START
+std::string SketchPlugin_MacroBSpline::processEvent(
+ const std::shared_ptr<Events_Message>& theMessage)
+{
+ ReentrantMessagePtr aReentrantMessage =
+ std::dynamic_pointer_cast<ModelAPI_EventReentrantMessage>(theMessage);
+ if (aReentrantMessage) {
+ FeaturePtr aCreatedFeature = aReentrantMessage->createdFeature();
+ ObjectPtr anObject = aReentrantMessage->selectedObject();
+ AttributePtr anAttribute = aReentrantMessage->selectedAttribute();
+ std::shared_ptr<GeomAPI_Pnt2d> aClickedPoint = aReentrantMessage->clickedPoint();
+
+ if (aClickedPoint) {
+ // fill points list (it consists of 2 points to make editable the second one)
+ AttributePoint2DArrayPtr aPointArrayAttr =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(attribute(POLES_ID()));
+ aPointArrayAttr->setSize(2);
+ aPointArrayAttr->setPnt(0, aClickedPoint);
+ aPointArrayAttr->setPnt(1, aClickedPoint);
+
+ // fill weights
+ AttributeDoubleArrayPtr aWeightsArrayAttr = data()->realArray(WEIGHTS_ID());
+ aWeightsArrayAttr->setSize(2);
+ aWeightsArrayAttr->setValue(0, 1.0);
+ aWeightsArrayAttr->setValue(1, 1.0);
+
+ // fill reference attribute
+ AttributeRefAttrListPtr aRefAttrList =
+ std::dynamic_pointer_cast<ModelAPI_AttributeRefAttrList>(attribute(REF_POLES_ID()));
+ if (anAttribute) {
+ if (!anAttribute->owner() || !anAttribute->owner()->data()->isValid()) {
+ if (aCreatedFeature && anAttribute->id() == SketchPlugin_Point::COORD_ID())
+ anAttribute = aCreatedFeature->attribute(SketchPlugin_Point::COORD_ID());
+ }
+ aRefAttrList->append(anAttribute);
+ }
+ }
+ Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
+ }
+ return std::string();
+}
+// LCOV_EXCL_STOP
+
+FeaturePtr SketchPlugin_MacroBSpline::createBSplineFeature()
+{
+ FeaturePtr aBSpline = sketch()->addFeature(
+ myIsPeriodic ? SketchPlugin_BSplinePeriodic::ID() : SketchPlugin_BSpline::ID());
+
+ aBSpline->integer(SketchPlugin_BSplineBase::DEGREE_ID())->setValue(myDegree);
+
+ AttributePoint2DArrayPtr aPoles = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
+ aBSpline->attribute(SketchPlugin_BSplineBase::POLES_ID()));
+ AttributePoint2DArrayPtr aPolesMacro =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(attribute(POLES_ID()));
+ aPoles->assign(aPolesMacro);
+
+ AttributeDoubleArrayPtr aWeights =
+ aBSpline->data()->realArray(SketchPlugin_BSplineBase::WEIGHTS_ID());
+ AttributeDoubleArrayPtr aWeightsMacro = data()->realArray(WEIGHTS_ID());
+ int aSize = aWeightsMacro->size();
+ aWeights->setSize(aSize);
+ for (int index = 0; index < aSize; ++index)
+ aWeights->setValue(index, aWeightsMacro->value(index));
+
+ AttributeDoubleArrayPtr aKnots =
+ aBSpline->data()->realArray(SketchPlugin_BSplineBase::KNOTS_ID());
+ aSize = (int)myKnots.size();
+ aKnots->setSize(aSize);
+ std::list<double>::iterator aKIt = myKnots.begin();
+ for (int index = 0; index < aSize; ++index, ++aKIt)
+ aKnots->setValue(index, *aKIt);
+
+ AttributeIntArrayPtr aMults = aBSpline->data()->intArray(SketchPlugin_BSplineBase::MULTS_ID());
+ aSize = (int)myMultiplicities.size();
+ aMults->setSize(aSize);
+ std::list<int>::iterator aMIt = myMultiplicities.begin();
+ for (int index = 0; index < aSize; ++index, ++aMIt)
+ aMults->setValue(index, *aMIt);
+
+ if (!myIsPeriodic) {
+ AttributePoint2DPtr aStartPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aBSpline->attribute(SketchPlugin_BSpline::START_ID()));
+ aStartPoint->setValue(aPoles->pnt(0));
+
+ AttributePoint2DPtr aEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aBSpline->attribute(SketchPlugin_BSpline::END_ID()));
+ aEndPoint->setValue(aPoles->pnt(aPoles->size() - 1));
+ }
+
+ aBSpline->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(
+ boolean(AUXILIARY_ID())->value());
+
+ aBSpline->execute();
+
+ return aBSpline;
+}
+
+void SketchPlugin_MacroBSpline::createControlPolygon(FeaturePtr theBSpline,
+ std::list<FeaturePtr>& thePoles)
+{
+ AttributePoint2DArrayPtr aPoles = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
+ theBSpline->attribute(SketchPlugin_BSpline::POLES_ID()));
+ int aSize = aPoles->size();
+ // poles
+ for (int index = 0; index < aSize; ++index)
+ thePoles.push_back(createAuxiliaryPole(aPoles, index));
+ // segments
+ for (int index = 1; index < aSize; ++index)
+ createAuxiliarySegment(aPoles, index - 1, index);
+ if (myIsPeriodic) {
+ // additional segment to close the control polygon
+ createAuxiliarySegment(aPoles, aSize - 1, 0);
+ }
+}
+
+void SketchPlugin_MacroBSpline::constraintsForPoles(const std::list<FeaturePtr>& thePoles)
+{
+ AttributeRefAttrListPtr aRefAttrList = data()->refattrlist(REF_POLES_ID());
+ std::list<std::pair<ObjectPtr, AttributePtr> > aList;
+ if (aRefAttrList)
+ aList = aRefAttrList->list();
+
+ SketchPlugin_Sketch* aSketch = sketch();
+
+ std::list<std::pair<ObjectPtr, AttributePtr> >::iterator aLIt = aList.begin();
+ std::list<FeaturePtr>::const_iterator aPIt = thePoles.begin();
+ for (; aLIt != aList.end() && aPIt != thePoles.end(); ++aPIt, ++aLIt) {
+ // firstly, check the attribute (in this case the object will be not empty too)
+ if (aLIt->second) {
+ SketchPlugin_Tools::createConstraintAttrAttr(aSketch,
+ SketchPlugin_ConstraintCoincidence::ID(),
+ (*aPIt)->attribute(SketchPlugin_Point::COORD_ID()), aLIt->second);
+ }
+ // now add coincidence with the result
+ else if (aLIt->first) {
+ SketchPlugin_Tools::createConstraintAttrObject(aSketch,
+ SketchPlugin_ConstraintCoincidence::ID(),
+ (*aPIt)->attribute(SketchPlugin_Point::COORD_ID()), aLIt->first);
+ }
+ }
+}
+
+AISObjectPtr SketchPlugin_MacroBSpline::getAISObject(AISObjectPtr thePrevious)
+{
+ SketchPlugin_Sketch* aSketch = sketch();
+ if (!aSketch)
+ return AISObjectPtr();
+
+ AttributePoint2DArrayPtr aPolesArray =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(attribute(POLES_ID()));
+ AttributeDoubleArrayPtr aWeightsArray = data()->realArray(WEIGHTS_ID());
+
+ if (aPolesArray->size() < 2)
+ return AISObjectPtr();
+
+ std::list<GeomShapePtr> aShapes;
+
+ // convert poles to vertices and collect weights
+ std::list<GeomPnt2dPtr> aPoles2D;
+ std::list<double> aWeights;
+ for (int anIndex = 0; anIndex < aPolesArray->size(); ++anIndex) {
+ double aWeight = aWeightsArray->value(anIndex);
+ if (aWeight < 1.e-10)
+ continue; // skip poles with zero weights
+
+ aWeights.push_back(aWeight);
+
+ GeomPnt2dPtr aPole = aPolesArray->pnt(anIndex);
+ aPoles2D.push_back(aPole);
+ GeomPointPtr aPole3D = aSketch->to3D(aPole->x(), aPole->y());
+ aShapes.push_back(GeomAlgoAPI_PointBuilder::vertex(aPole3D));
+ }
+
+ // create result non-periodic B-spline curve
+ std::shared_ptr<GeomAPI_BSpline2d> aBSplineCurve;
+ try {
+ aBSplineCurve.reset(new GeomAPI_BSpline2d(aPoles2D, aWeights, myIsPeriodic));
+ } catch (...) {
+ // cannot build a B-spline curve
+ return AISObjectPtr();
+ }
+ GeomShapePtr anEdge =
+ 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);
+
+ AISObjectPtr anAIS = thePrevious;
+ if (!anAIS)
+ anAIS.reset(new GeomAPI_AISObject());
+ anAIS->createShape(aCompound);
+
+ // Modify attributes
+ SketchPlugin_Tools::customizeFeaturePrs(anAIS, boolean(AUXILIARY_ID())->value());
+
+ return anAIS;
+}
+
+
+
+// ========================== Auxiliary functions ===========================================
+
+FeaturePtr SketchPlugin_MacroBSpline::createAuxiliaryPole(AttributePoint2DArrayPtr theBSplinePoles,
+ const int thePoleIndex)
+{
+ FeaturePtr aBSpline = ModelAPI_Feature::feature(theBSplinePoles->owner());
+
+ SketchPlugin_Sketch* aSketch =
+ std::dynamic_pointer_cast<SketchPlugin_Feature>(aBSpline)->sketch();
+
+ // create child point equal to the B-spline's pole
+ FeaturePtr aPointFeature = aSketch->addFeature(SketchPlugin_Point::ID());
+ aPointFeature->boolean(SketchPlugin_Point::AUXILIARY_ID())->setValue(true);
+ aPointFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(aBSpline);
+
+ GeomPnt2dPtr aPole = theBSplinePoles->pnt(thePoleIndex);
+
+ AttributePoint2DPtr aCoord = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aPointFeature->attribute(SketchPlugin_Point::COORD_ID()));
+ aCoord->setValue(aPole);
+
+ aPointFeature->execute();
+
+ std::ostringstream aName;
+ aName << aBSpline->name() << "_" << theBSplinePoles->id() << "_" << thePoleIndex;
+ aPointFeature->data()->setName(aName.str());
+ aPointFeature->lastResult()->data()->setName(aName.str());
+
+ // internal constraint to keep position of the point
+ createInternalConstraint(aSketch, aCoord, theBSplinePoles, thePoleIndex);
+
+ return aPointFeature;
+}
+
+void SketchPlugin_MacroBSpline::createAuxiliarySegment(AttributePoint2DArrayPtr theBSplinePoles,
+ const int thePoleIndex1,
+ const int thePoleIndex2)
+{
+ FeaturePtr aBSpline = ModelAPI_Feature::feature(theBSplinePoles->owner());
+
+ SketchPlugin_Sketch* aSketch =
+ std::dynamic_pointer_cast<SketchPlugin_Feature>(aBSpline)->sketch();
+
+ // create child segment between B-spline poles
+ FeaturePtr aLineFeature = aSketch->addFeature(SketchPlugin_Line::ID());
+ aLineFeature->boolean(SketchPlugin_Point::AUXILIARY_ID())->setValue(true);
+ aLineFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(aBSpline);
+
+ AttributePoint2DPtr aLineStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aLineFeature->attribute(SketchPlugin_Line::START_ID()));
+ aLineStart->setValue(theBSplinePoles->pnt(thePoleIndex1));
+
+ AttributePoint2DPtr aLineEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aLineFeature->attribute(SketchPlugin_Line::END_ID()));
+ aLineEnd->setValue(theBSplinePoles->pnt(thePoleIndex2));
+
+ aLineFeature->execute();
+
+ std::ostringstream aName;
+ aName << aBSpline->name() << "_segment_" << thePoleIndex1 << "_" << thePoleIndex2;
+ aLineFeature->data()->setName(aName.str());
+ aLineFeature->lastResult()->data()->setName(aName.str());
+
+ // internal constraints to keep the segment position
+ createInternalConstraint(aSketch, aLineStart, theBSplinePoles, thePoleIndex1);
+ createInternalConstraint(aSketch, aLineEnd, theBSplinePoles, thePoleIndex2);
+}
+
+void createInternalConstraint(SketchPlugin_Sketch* theSketch,
+ AttributePtr thePoint,
+ AttributePtr theBSplinePoles,
+ const int thePoleIndex)
+{
+ std::shared_ptr<SketchPlugin_ConstraintCoincidenceInternal> aConstraint =
+ std::dynamic_pointer_cast<SketchPlugin_ConstraintCoincidenceInternal>(
+ theSketch->addFeature(SketchPlugin_ConstraintCoincidenceInternal::ID()));
+ aConstraint->refattr(SketchPlugin_Constraint::ENTITY_A())->setAttr(thePoint);
+ aConstraint->refattr(SketchPlugin_Constraint::ENTITY_B())->setAttr(theBSplinePoles);
+ aConstraint->integer(SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_B())
+ ->setValue(thePoleIndex);
+}
--- /dev/null
+// 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 SketchPlugin_MacroBSpline_H_
+#define SketchPlugin_MacroBSpline_H_
+
+#include <ModelAPI_IReentrant.h>
+
+#include "SketchPlugin.h"
+
+#include "SketchPlugin_SketchEntity.h"
+
+#include <GeomAPI_IPresentable.h>
+
+class GeomAPI_Circ2d;
+class GeomAPI_Pnt2d;
+
+class GeomDataAPI_Point2DArray;
+
+/**\class SketchPlugin_MacroBSpline
+ * \ingroup Plugins
+ * \brief Feature for creation of the new B-spline in Sketch.
+ */
+class SketchPlugin_MacroBSpline : public SketchPlugin_SketchEntity,
+ public GeomAPI_IPresentable,
+ public ModelAPI_IReentrant
+{
+public:
+ /// B-spline macro feature kind
+ inline static const std::string& ID()
+ {
+ static const std::string ID("SketchMacroBSpline");
+ return ID;
+ }
+
+
+ /// list of B-spline poles
+ inline static const std::string& POLES_ID()
+ {
+ static const std::string ID("poles");
+ return ID;
+ }
+
+ /// list of references of B-spline poles
+ inline static const std::string& REF_POLES_ID()
+ {
+ static const std::string ID("poles_ref");
+ return ID;
+ }
+
+ /// list of B-spline weights
+ inline static const std::string& WEIGHTS_ID()
+ {
+ static const std::string ID("weights");
+ return ID;
+ }
+
+ /// flag attribute whether control polygon is need to be created
+ inline static const std::string& CONTROL_POLYGON_ID()
+ {
+ static const std::string ID("need_control_poly");
+ return ID;
+ }
+
+ /// Returns the kind of a feature
+ SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
+ {
+ static std::string MY_KIND = SketchPlugin_MacroBSpline::ID();
+ return MY_KIND;
+ }
+
+ /// \brief Request for initialization of data model of the feature: adding all attributes.
+ SKETCHPLUGIN_EXPORT virtual void initAttributes();
+
+ /// Returns the AIS preview
+ virtual AISObjectPtr getAISObject(AISObjectPtr thePrevious);
+
+ /// Creates a new part document if needed
+ SKETCHPLUGIN_EXPORT virtual void execute();
+
+ /// Reimplemented from ModelAPI_Feature::isMacro().
+ /// \returns true
+ SKETCHPLUGIN_EXPORT virtual bool isMacro() const {return true;};
+
+ SKETCHPLUGIN_EXPORT virtual bool isPreviewNeeded() const {return false;};
+
+ /// Apply information of the message to current object. It fills reference object,
+ /// tangent type and tangent point refence in case of tangent arc
+ virtual std::string processEvent(const std::shared_ptr<Events_Message>& theMessage);
+
+ /// Use plugin manager for features creation
+ SketchPlugin_MacroBSpline();
+
+protected:
+ SketchPlugin_MacroBSpline(bool isPeriodic);
+
+private:
+ FeaturePtr createBSplineFeature();
+
+ void createControlPolygon(FeaturePtr theBSpline, std::list<FeaturePtr>& thePoles);
+ void constraintsForPoles(const std::list<FeaturePtr>& thePoles);
+
+ /// Create Point feature coincident with the B-spline pole
+ static FeaturePtr createAuxiliaryPole(std::shared_ptr<GeomDataAPI_Point2DArray> theBSplinePoles,
+ const int thePoleIndex);
+ /// Create segment between consequtive B-spline poles
+ static void createAuxiliarySegment(std::shared_ptr<GeomDataAPI_Point2DArray> theBSplinePoles,
+ const int thePoleIndex1,
+ const int thePoleIndex2);
+ friend class SketchPlugin_BSplineBase;
+
+private:
+ std::list<double> myKnots;
+ std::list<int> myMultiplicities;
+ int myDegree;
+ bool myIsPeriodic;
+};
+
+
+/**\class SketchPlugin_MacroBSpline
+* \ingroup Plugins
+* \brief Feature for creation of the new B-spline in Sketch.
+*/
+class SketchPlugin_MacroBSplinePeriodic : public SketchPlugin_MacroBSpline
+{
+public:
+ /// B-spline macro feature kind
+ inline static const std::string& ID()
+ {
+ static const std::string ID("SketchMacroBSplinePeriodic");
+ return ID;
+ }
+
+ /// Returns the kind of a feature
+ SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
+ {
+ return SketchPlugin_MacroBSpline::ID();
+ }
+
+ /// Use plugin manager for features creation
+ SketchPlugin_MacroBSplinePeriodic() : SketchPlugin_MacroBSpline(true) {}
+};
+
+#endif
#include <SketchPlugin_IntersectionPoint.h>
#include <SketchPlugin_Circle.h>
#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_BSpline.h>
+#include <SketchPlugin_BSplinePeriodic.h>
#include <SketchPlugin_Projection.h>
#include <SketchPlugin_ConstraintAngle.h>
#include <SketchPlugin_ConstraintCoincidence.h>
#include <SketchPlugin_ConstraintTangent.h>
#include <SketchPlugin_ConstraintVertical.h>
#include <SketchPlugin_MacroArc.h>
+#include <SketchPlugin_MacroBSpline.h>
#include <SketchPlugin_MacroCircle.h>
#include <SketchPlugin_MultiRotation.h>
#include <SketchPlugin_MultiTranslation.h>
new SketchPlugin_SketchFeatureValidator);
aFactory->registerValidator("SketchPlugin_MultiRotationAngleValidator",
new SketchPlugin_MultiRotationAngleValidator);
+ aFactory->registerValidator("SketchPlugin_BSplineValidator",
+ new SketchPlugin_BSplineValidator);
// register this plugin
ModelAPI_Session::get()->registerPlugin(this);
return FeaturePtr(new SketchPlugin_Circle);
} else if (theFeatureID == SketchPlugin_Arc::ID()) {
return FeaturePtr(new SketchPlugin_Arc);
+ } else if (theFeatureID == SketchPlugin_BSpline::ID()) {
+ return FeaturePtr(new SketchPlugin_BSpline);
+ } else if (theFeatureID == SketchPlugin_BSplinePeriodic::ID()) {
+ return FeaturePtr(new SketchPlugin_BSplinePeriodic);
} else if (theFeatureID == SketchPlugin_Projection::ID()) {
return FeaturePtr(new SketchPlugin_Projection);
} else if (theFeatureID == SketchPlugin_ConstraintCoincidence::ID()) {
return FeaturePtr(new SketchPlugin_Trim);
} else if (theFeatureID == SketchPlugin_MacroArc::ID()) {
return FeaturePtr(new SketchPlugin_MacroArc);
+ } else if (theFeatureID == SketchPlugin_MacroBSpline::ID()) {
+ return FeaturePtr(new SketchPlugin_MacroBSpline);
+ } else if (theFeatureID == SketchPlugin_MacroBSplinePeriodic::ID()) {
+ return FeaturePtr(new SketchPlugin_MacroBSplinePeriodic);
} else if (theFeatureID == SketchPlugin_MacroCircle::ID()) {
return FeaturePtr(new SketchPlugin_MacroCircle);
} else if (theFeatureID == SketchPlugin_Ellipse::ID()) {
aMsg->setState(SketchPlugin_Line::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_Circle::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_Arc::ID(), aHasSketchPlane);
+ aMsg->setState(SketchPlugin_BSpline::ID(), aHasSketchPlane);
+ aMsg->setState(SketchPlugin_BSplinePeriodic::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_Ellipse::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_EllipticArc::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_Projection::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_Split::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_Trim::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_MacroArc::ID(), aHasSketchPlane);
+ aMsg->setState(SketchPlugin_MacroBSpline::ID(), aHasSketchPlane);
+ aMsg->setState(SketchPlugin_MacroBSplinePeriodic::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_MacroCircle::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_MacroEllipse::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_MacroEllipticArc::ID(), aHasSketchPlane);
#include <SketchPlugin_Projection.h>
#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_BSpline.h>
#include <SketchPlugin_Circle.h>
#include <SketchPlugin_Ellipse.h>
#include <SketchPlugin_EllipticArc.h>
#include <ModelAPI_AttributeRefAttr.h>
#include <ModelAPI_AttributeSelection.h>
#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeDoubleArray.h>
+#include <ModelAPI_AttributeInteger.h>
#include <ModelAPI_ResultConstruction.h>
#include <ModelAPI_Session.h>
#include <ModelAPI_Validator.h>
#include <Events_Loop.h>
+#include <GeomAPI_BSpline.h>
#include <GeomAPI_Circ.h>
#include <GeomAPI_Edge.h>
#include <GeomAPI_Ellipse.h>
#include <GeomAlgoAPI_EdgeBuilder.h>
#include <GeomAlgoAPI_Projection.h>
#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
#include <cmath>
return aProj;
}
+static const std::set<std::string>& BSPLINE_PROJECTION()
+{
+ static std::set<std::string> aProj;
+ if (aProj.empty())
+ aProj.insert(SketchPlugin_BSpline::ID());
+ return aProj;
+}
+
static const std::set<std::string>& possibleProjectionTypes(GeomEdgePtr theEdge,
GeomVertexPtr theVertex)
else
return ARC_PROJECTION();
}
+ else
+ return BSPLINE_PROJECTION();
}
static const std::set<std::string> DUMMY;
return DUMMY;
// if the type of feature differs with already selected, remove it and create once again
bool isRebuild = rebuildProjectedFeature(aProjection, aProjType);
- std::shared_ptr<GeomAPI_Pln> aSketchPlane = sketch()->plane();
-
ResultConstructionPtr aResult =
std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(lastResult());
if (!isRebuild && aResult && aResult->shape() && theID == EXTERNAL_FEATURE_ID()) {
keepCurrentFeature();
- if (aVertex) {
- std::shared_ptr<GeomAPI_Pnt> aPrjPnt = aSketchPlane->project(aVertex->point());
- std::shared_ptr<GeomAPI_Pnt2d> 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<GeomDataAPI_Point2D>(
- aProjection->attribute(SketchPlugin_Point::COORD_ID()))->setValue(aPntInSketch);
- }
- else if (anEdge->isLine()) {
- std::shared_ptr<GeomAPI_Pnt> aFirst = aSketchPlane->project(anEdge->firstPoint());
- std::shared_ptr<GeomAPI_Pnt> aLast = aSketchPlane->project(anEdge->lastPoint());
-
- std::shared_ptr<GeomAPI_Pnt2d> aFirstInSketch = sketch()->to2D(aFirst);
- std::shared_ptr<GeomAPI_Pnt2d> 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<GeomDataAPI_Point2D> aStartPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aProjection->attribute(SketchPlugin_Line::START_ID()));
- std::shared_ptr<GeomDataAPI_Point2D> aEndPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- 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<GeomDataAPI_Point2D> aCenterPnt =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aProjection->attribute(SketchPlugin_Arc::CENTER_ID()));
- std::shared_ptr<GeomDataAPI_Point2D> aStartPnt =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aProjection->attribute(SketchPlugin_Arc::START_ID()));
- std::shared_ptr<GeomDataAPI_Point2D> aEndPnt =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- 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<GeomDataAPI_Point2D> aCenterPnt =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- 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<GeomDataAPI_Point2D> aCenterPnt =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aProjection->attribute(SketchPlugin_EllipticArc::CENTER_ID()));
- std::shared_ptr<GeomDataAPI_Point2D> aFocusPnt =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aProjection->attribute(SketchPlugin_EllipticArc::FIRST_FOCUS_ID()));
- std::shared_ptr<GeomDataAPI_Point2D> aStartPnt =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aProjection->attribute(SketchPlugin_EllipticArc::START_POINT_ID()));
- std::shared_ptr<GeomDataAPI_Point2D> aEndPnt =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- 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<GeomDataAPI_Point2D> aCenterPnt =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aProjection->attribute(SketchPlugin_Ellipse::CENTER_ID()));
- aCenterPnt->setValue(aCenterInSketch);
- std::shared_ptr<GeomDataAPI_Point2D> aFocusPnt =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- 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();
theProjection = sketch()->addFeature(theRequestedFeature);
return isRebuild;
}
+
+bool SketchPlugin_Projection::projectPoint(FeaturePtr& theProjection, const GeomPointPtr& thePoint)
+{
+ std::shared_ptr<GeomAPI_Pln> aSketchPlane = sketch()->plane();
+
+ std::shared_ptr<GeomAPI_Pnt> aPrjPnt = aSketchPlane->project(thePoint);
+ std::shared_ptr<GeomAPI_Pnt2d> aPntInSketch = sketch()->to2D(aPrjPnt);
+
+ rebuildProjectedFeature(theProjection, POINT_PROJECTION(), SketchPlugin_Point::ID());
+
+ // update coordinates of projection
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ theProjection->attribute(SketchPlugin_Point::COORD_ID()))->setValue(aPntInSketch);
+ return true;
+}
+
+bool SketchPlugin_Projection::projectSegment(FeaturePtr& theProjection, const GeomEdgePtr& theEdge)
+{
+ std::shared_ptr<GeomAPI_Pln> aSketchPlane = sketch()->plane();
+
+ std::shared_ptr<GeomAPI_Pnt> aFirst = aSketchPlane->project(theEdge->firstPoint());
+ std::shared_ptr<GeomAPI_Pnt> aLast = aSketchPlane->project(theEdge->lastPoint());
+
+ std::shared_ptr<GeomAPI_Pnt2d> aFirstInSketch = sketch()->to2D(aFirst);
+ std::shared_ptr<GeomAPI_Pnt2d> 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<GeomDataAPI_Point2D> aStartPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ theProjection->attribute(SketchPlugin_Line::START_ID()));
+ std::shared_ptr<GeomDataAPI_Point2D> aEndPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ 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<GeomAPI_Pln> 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<GeomDataAPI_Point2D> aCenterPnt =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ theProjection->attribute(SketchPlugin_Arc::CENTER_ID()));
+ std::shared_ptr<GeomDataAPI_Point2D> aStartPnt =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ theProjection->attribute(SketchPlugin_Arc::START_ID()));
+ std::shared_ptr<GeomDataAPI_Point2D> aEndPnt =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ 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<GeomDataAPI_Point2D> aCenterPnt =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ 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<GeomDataAPI_Point2D> aCenterPnt =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ theProjection->attribute(SketchPlugin_Ellipse::CENTER_ID()));
+ aCenterPnt->setValue(aCenterInSketch);
+ std::shared_ptr<GeomDataAPI_Point2D> aFocusPnt =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ 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<GeomDataAPI_Point2D> aCenterPnt =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ theProjection->attribute(SketchPlugin_EllipticArc::CENTER_ID()));
+ std::shared_ptr<GeomDataAPI_Point2D> aFocusPnt =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ theProjection->attribute(SketchPlugin_EllipticArc::FIRST_FOCUS_ID()));
+ std::shared_ptr<GeomDataAPI_Point2D> aStartPnt =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ theProjection->attribute(SketchPlugin_EllipticArc::START_POINT_ID()));
+ std::shared_ptr<GeomDataAPI_Point2D> aEndPnt =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ 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<GeomDataAPI_Point2DArray>(
+ theProjection->attribute(SketchPlugin_BSpline::POLES_ID()));
+ std::list<GeomPointPtr> aPoles = aBSpline.poles();
+ aPolesAttr->setSize((int)aPoles.size());
+ std::list<GeomPointPtr>::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<double> 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<double>::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<double> aKnots = aBSpline.knots();
+ int aSize = (int)aKnots.size();
+ aKnotsAttr->setSize(aSize);
+ std::list<double>::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<int> aMultiplicities = aBSpline.mults();
+ aSize = (int)aMultiplicities.size();
+ aMultsAttr->setSize(aSize);
+ std::list<int>::iterator aMIt = aMultiplicities.begin();
+ for (int index = 0; index < aSize; ++index, ++aMIt)
+ aMultsAttr->setValue(index, *aMIt);
+
+ return true;
+}
#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.
/// \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<GeomAPI_Pnt>& thePoint);
+ /// \brief Project segment to the sketch plane
+ bool projectSegment(FeaturePtr& theProjection, const std::shared_ptr<GeomAPI_Edge>& theEdge);
+ /// \brief Project any edge to sketch plane
+ bool projectEdge(FeaturePtr& theProjection, const std::shared_ptr<GeomAPI_Edge>& theEdge);
+
+ /// \brief Fill attributes of the Arc feature
+ bool fillArc(FeaturePtr& theProjection,
+ const std::shared_ptr<GeomAPI_Curve>& theArc,
+ const std::shared_ptr<GeomAPI_Pln>& thePlane);
+ /// \brief Fill attributes of the Circle feature
+ bool fillCircle(FeaturePtr& theProjection,
+ const std::shared_ptr<GeomAPI_Curve>& theCircle,
+ const std::shared_ptr<GeomAPI_Pln>& thePlane);
+ /// \brief Fill attributes of the Ellipse feature
+ bool fillEllipse(FeaturePtr& theProjection,
+ const std::shared_ptr<GeomAPI_Curve>& theEllipse,
+ const std::shared_ptr<GeomAPI_Pln>& thePlane);
+ /// \brief Fill attributes of the EllipticArc feature
+ bool fillEllipticArc(FeaturePtr& theProjection,
+ const std::shared_ptr<GeomAPI_Curve>& theEllipticArc,
+ const std::shared_ptr<GeomAPI_Pln>& thePlane);
+ /// \brief Fill attributes of the B-spline feature
+ bool fillBSpline(FeaturePtr& theProjection,
+ const std::shared_ptr<GeomAPI_Curve>& theCurve,
+ const std::shared_ptr<GeomAPI_Pln>& thePlane);
+
/// \brief Delete already calculated projected feature
/// if the selection of the projection is changed
/// \param[in/out] theProjection projected feature
#include <GeomAPI_Lin.h>
#include <GeomAPI_Edge.h>
#include <GeomAPI_Vertex.h>
+
#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
#include <algorithm>
#include <cmath>
std::shared_ptr<GeomAPI_Dir> aNormal = aPlane->direction();
std::shared_ptr<GeomAPI_Pnt> anOrigin = aPlane->location();
+ bool aValid = true;
if (anEdge->isLine()) {
std::shared_ptr<GeomAPI_Lin> aLine = anEdge->line();
std::shared_ptr<GeomAPI_Dir> 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<GeomAPI_Circ> aCircle = anEdge->circle();
std::shared_ptr<GeomAPI_Dir> 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<GeomAPI_Ellipse> anEllipse = anEdge->ellipse();
std::shared_ptr<GeomAPI_Dir> 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;
}
return true;
}
+
+bool SketchPlugin_BSplineValidator::isValid(const AttributePtr& theAttribute,
+ const std::list<std::string>& theArguments,
+ Events_InfoMessage& theError) const
+{
+ AttributePoint2DArrayPtr aPolesArray =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(theAttribute);
+ if (!aPolesArray)
+ return false;
+
+ if (aPolesArray->size() < 2) {
+ theError = "Number of B-spline poles should be 2 or more";
+ return false;
+ }
+
+ return true;
+}
Events_InfoMessage& theError) const;
};
+/**\class SketchPlugin_BSplineValidator
+ * \ingroup Validators
+ * \brief Validator for checking poles/weights of B-spline curve.
+ */
+class SketchPlugin_BSplineValidator : public ModelAPI_AttributeValidator
+{
+ //! returns true if attribute is valid
+ //! \param theAttribute the checked attribute
+ //! \param theArguments arguments of the attribute
+ //! \param theError error message
+ virtual bool isValid(const AttributePtr& theAttribute,
+ const std::list<std::string>& theArguments,
+ Events_InfoMessage& theError) const;
+};
+
#endif
</message>
</context>
+ <context>
+ <name>SketchBSpline</name>
+ <message>
+ <source>Number of B-spline poles should be 2 or more</source>
+ <translation>Le nombre de pôles B-spline doit être de 2 ou plus</translation>
+ </message>
+ </context>
+
</TS>
--- /dev/null
+# Copyright (C) 2019-2020 CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+"""
+ Test constraint coincidence applied for B-spline curve and its sub-results
+"""
+
+import unittest
+import math
+
+from salome.shaper import model
+
+from GeomAPI import *
+from SketchAPI import *
+
+__updated__ = "2020-01-21"
+
+class TestCoincidenceBSpline(unittest.TestCase):
+ def setUp(self):
+ model.begin()
+ self.myDocument = model.moduleDocument()
+ self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+
+ self.myPoles = [GeomAPI_Pnt2d(-10, -30), GeomAPI_Pnt2d(20, -15), GeomAPI_Pnt2d(-10, 0), GeomAPI_Pnt2d(20, 15), GeomAPI_Pnt2d(-10, 30)]
+ self.myWeights = [1, 3, 5, 3, 1]
+ self.mySpline = self.mySketch.addSpline(poles = self.myPoles, weights = self.myWeights)
+ self.myControlPoles = self.mySpline.controlPoles(auxiliary = [0, 1, 2, 3, 4])
+ self.myControlLines = self.mySpline.controlPolygon(auxiliary = [0, 1, 2, 3])
+
+ self.myDOF = len(self.myPoles) * 2
+ self.myOrigin = self.mySketch.addPoint("Origin")
+ self.myOX = self.mySketch.addLine("OX")
+ model.do()
+ self.myExpectFailure = False
+ self.myNbPoints = len(self.myPoles) + 1
+ self.myNbLines = len(self.myPoles)
+ self.myNbBSplines = 1
+ self.myNbInternalConstraints = len(self.myPoles) * 3 - 2
+ self.myNbCoincidences = 1
+
+ def tearDown(self):
+ model.end()
+ if self.myExpectFailure:
+ assert(self.mySketch.solverError() != ""), "PlaneGCS limitation: if you see this message, then PlaneGCS has solved the set of constraints correctly"
+ model.undo()
+ else:
+ self.checkDOF()
+ model.testNbSubFeatures(self.mySketch, "SketchPoint", self.myNbPoints)
+ model.testNbSubFeatures(self.mySketch, "SketchLine", self.myNbLines)
+ model.testNbSubFeatures(self.mySketch, "SketchBSpline", self.myNbBSplines)
+ model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidenceInternal", self.myNbInternalConstraints)
+ model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", self.myNbCoincidences)
+
+
+ def checkDOF(self):
+ self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+ def setCoincidentWithOrigin(self, thePoint):
+ self.mySketch.setCoincident(thePoint, self.myOrigin.coordinates())
+ self.myDOF -= 2
+ model.do()
+
+ def setCoincidentWithOX(self, thePoint):
+ self.mySketch.setCoincident(thePoint, self.myOX.result())
+ self.myDOF -= 1
+ model.do()
+
+ def assertPoles(self):
+ poles = self.mySpline.poles()
+ assert(poles.size() == len(self.myPoles))
+ for index in range(0, len(self.myPoles)):
+ self.assertPoints(self.myPoles[index], poles.pnt(index))
+
+ def assertPoints(self, thePoint1, thePoint2):
+ self.assertAlmostEqual(thePoint1.x(), thePoint2.x())
+ self.assertAlmostEqual(thePoint1.y(), thePoint2.y())
+
+ def assertPointOnLine(self, thePoint, theLineStart, theLineEnd):
+ vecP = [thePoint.x() - theLineStart.x(), thePoint.y() - theLineStart.y()]
+ vecL = [theLineEnd.x() - theLineStart.x(), theLineEnd.y() - theLineStart.y()]
+ dist = math.fabs(vecP[0] * vecL[1] - vecP[1] * vecL[0]) / math.hypot(vecL[0], vecL[1])
+ self.assertAlmostEqual(dist, 0.0)
+
+ def assertPointOnSpline(self, thePoint, theSpline):
+ point = GeomAPI_Pnt(thePoint.x(), thePoint.y(), 0.0)
+ bspline = GeomAPI_Curve(theSpline.results()[-1].resultSubShapePair()[0].shape())
+ proj = bspline.project(point)
+ self.assertAlmostEqual(point.distance(proj), 0.0)
+
+
+ def test_origin_equal_start_point(self):
+ """ Test 1. Make start point of B-spline coincident with the Origin
+ """
+ self.setCoincidentWithOrigin(self.mySpline.startPoint())
+ self.myPoles[0].setX(0)
+ self.myPoles[0].setY(0)
+ self.assertPoles()
+
+ def test_origin_equal_end_point(self):
+ """ Test 2. Make end point of B-spline coincident with the Origin
+ """
+ self.setCoincidentWithOrigin(self.mySpline.endPoint())
+ self.myPoles[-1].setX(0)
+ self.myPoles[-1].setY(0)
+ self.assertPoles()
+
+ def test_origin_equal_pole(self):
+ """ Test 3. Make one of B-spline poles coincident with the Origin
+ """
+ self.setCoincidentWithOrigin(SketchAPI_Point(self.myControlPoles[1]).coordinates())
+ self.myPoles[1].setX(0)
+ self.myPoles[1].setY(0)
+ self.assertPoles()
+
+ def test_origin_on_bspline(self):
+ """ Test 4. (expected failure) Make Origin lying on the B-spline curve
+ """
+ self.mySketch.setCoincident(self.mySpline.defaultResult(), self.myOrigin.coordinates())
+ self.myDOF -= 1
+ model.do()
+ self.myExpectFailure = True
+
+ def test_point_on_bspline(self):
+ """ Test 5. Place free point on the B-spline curve
+ """
+ point = self.mySketch.addPoint(1, 0)
+ self.mySketch.setCoincident(self.myOX.defaultResult(), point.coordinates())
+ self.mySketch.setCoincident(self.mySpline.defaultResult(), point.coordinates())
+ model.do()
+ self.myNbPoints += 1
+ self.myNbCoincidences += 1
+ self.assertPointOnSpline(point.coordinates(), self.mySpline)
+
+
+ def test_start_point_on_axis(self):
+ """ Test 6. Make start point of B-spline coincident with the OX
+ """
+ self.setCoincidentWithOX(self.mySpline.startPoint())
+ self.myPoles[0].setY(0)
+ self.assertPoles()
+
+ def test_end_point_on_axis(self):
+ """ Test 7. Make end point of B-spline coincident with the OX
+ """
+ self.setCoincidentWithOX(self.mySpline.endPoint())
+ self.myPoles[-1].setY(0)
+ self.assertPoles()
+
+ def test_pole_on_axis(self):
+ """ Test 8. Make one of B-spline poles coincident with the OX
+ """
+ self.setCoincidentWithOX(SketchAPI_Point(self.myControlPoles[1]).coordinates())
+ self.myPoles[1].setY(0)
+ self.assertPoles()
+
+
+if __name__ == "__main__":
+ test_program = unittest.main(exit=False)
+ assert test_program.result.wasSuccessful(), "Test failed"
+ assert model.checkPythonDump()
--- /dev/null
+# Copyright (C) 2019-2020 CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+"""
+ Test constraint "Tangent" applied to B-spline and another entity
+"""
+
+import unittest
+import math
+
+from salome.shaper import model
+
+from GeomAPI import *
+from GeomAlgoAPI import *
+from SketchAPI import *
+
+__updated__ = "2020-01-22"
+
+class TestTangentBSpline(unittest.TestCase):
+ def setUp(self):
+ model.begin()
+ self.myDocument = model.moduleDocument()
+ self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+ self.myPoles = [GeomAPI_Pnt2d(-10, -30), GeomAPI_Pnt2d(20, -15), GeomAPI_Pnt2d(-10, 0), GeomAPI_Pnt2d(20, 15), GeomAPI_Pnt2d(-10, 30)]
+ self.myWeights = [1, 3, 5, 3, 1]
+ self.mySpline = self.mySketch.addSpline(poles = self.myPoles, weights = self.myWeights)
+ self.myControlPoles = self.mySpline.controlPoles(auxiliary = [0, 1, 2, 3, 4])
+ self.myControlLines = self.mySpline.controlPolygon(auxiliary = [0, 1, 2, 3])
+ model.do()
+
+ self.myExpectedFailure = False
+ self.myDOF = len(self.myPoles) * 2
+ self.myNbPoints = len(self.myPoles)
+ self.myNbLines = len(self.myPoles) - 1
+ self.myNbArcs = 0
+ self.myNbCircles = 0
+ self.myNbEllipses = 0
+ self.myNbEllipticArcs = 0
+ self.myNbBSplines = 1
+ self.myNbInternals = len(self.myPoles) * 3 - 2
+ self.myNbCoincidence = 0
+ self.myNbTangency = 0
+
+ def tearDown(self):
+ model.end()
+ if self.myExpectedFailure:
+ assert(self.mySketch.solverError() != ""), "PlaneGCS limitation: if you see this message, then PlaneGCS has solved the set of constraints correctly"
+ model.undo()
+ else:
+ self.checkDOF()
+ model.testNbSubFeatures(self.mySketch, "SketchPoint", self.myNbPoints)
+ model.testNbSubFeatures(self.mySketch, "SketchLine", self.myNbLines)
+ model.testNbSubFeatures(self.mySketch, "SketchArc", self.myNbArcs)
+ model.testNbSubFeatures(self.mySketch, "SketchCircle", self.myNbCircles)
+ model.testNbSubFeatures(self.mySketch, "SketchEllipse", self.myNbEllipses)
+ model.testNbSubFeatures(self.mySketch, "SketchEllipticArc", self.myNbEllipticArcs)
+ model.testNbSubFeatures(self.mySketch, "SketchBSpline", self.myNbBSplines)
+ model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidenceInternal", self.myNbInternals)
+ model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", self.myNbCoincidence)
+ model.testNbSubFeatures(self.mySketch, "SketchConstraintTangent", self.myNbTangency)
+
+
+ def checkDOF(self):
+ self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+ def assertTangentFeatures(self, theFeature1, theFeature2):
+ shapes = [theFeature1.results()[-1].resultSubShapePair()[0].shape(),
+ theFeature2.results()[-1].resultSubShapePair()[0].shape()]
+ for s in shapes:
+ e = shapeToEdge(s)
+ if e.isLine() or e.isArc() or e.isEllipse():
+ params = e.getRange()
+ e.setRange(params[0] - 100, params[1] + 100)
+ # TODO (azv): complete checking the tangent curves
+
+ def assertPointLineDistance(self, thePoint, theLine, theExpectedDistance = 0):
+ dist = model.distancePointLine(thePoint, theLine)
+ self.assertAlmostEqual(dist, theExpectedDistance)
+
+ def assertTangentLineCircle(self, theLine, theCircle):
+ self.assertPointLineDistance(theCircle.center(), theLine, theCircle.radius().value())
+
+ def assertTangentLineEllipse(self, theLine, theEllipse):
+ aLine = GeomAPI_Lin2d(theLine.startPoint().pnt(), theLine.endPoint().pnt())
+ projF1 = aLine.project(theEllipse.firstFocus().pnt())
+ projF2 = aLine.project(theEllipse.secondFocus().pnt())
+
+ distF1P1 = model.distancePointPoint(theEllipse.firstFocus(), projF1)
+ distF2P2 = model.distancePointPoint(theEllipse.secondFocus(), projF2)
+
+ tgPoint = GeomAPI_Pnt2d((projF1.x() * distF2P2 + projF2.x() * distF1P1) / (distF1P1 + distF2P2), (projF1.y() * distF2P2 + projF2.y() * distF1P1) / (distF1P1 + distF2P2))
+ distF1T = model.distancePointPoint(theEllipse.firstFocus(), tgPoint)
+ distF2T = model.distancePointPoint(theEllipse.secondFocus(), tgPoint)
+ self.assertAlmostEqual(distF1T + distF2T, 2 * theEllipse.majorRadius().value())
+
+
+ def test_line_tangent(self):
+ """ Test 1. Set tangency between B-spline and a line
+ """
+ aLine = self.mySketch.addLine(10, -10, 90, 40)
+ self.myNbLines += 1
+ self.myDOF += 4
+ model.do()
+
+ self.mySketch.setTangent(self.mySpline.result(), aLine.result())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.assertTangentFeatures(aLine, self.mySpline)
+
+ def test_circle_tangent(self):
+ """ Test 2. Set tangency between B-spline and a circle
+ """
+ aCircle = self.mySketch.addCircle(10, 10, 20)
+ self.myNbCircles += 1
+ self.myDOF += 3
+ model.do()
+
+ self.mySketch.setTangent(self.mySpline.result(), aCircle.defaultResult())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.assertTangentFeatures(aCircle, self.mySpline)
+
+ def test_arc_tangent(self):
+ """ Test 3. Set tangency between B-spline and an arc
+ """
+ anArc = self.mySketch.addArc(10, 10, 20, 10, 10, 20, False)
+ self.myNbArcs += 1
+ self.myDOF += 5
+ model.do()
+
+ self.mySketch.setTangent(self.mySpline.result(), anArc.defaultResult())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.assertTangentFeatures(anArc, self.mySpline)
+
+ def test_ellipse_tangent(self):
+ """ Test 4. Set tangency between B-spline and an ellipse
+ """
+ anEllipse = self.mySketch.addEllipse(10, 10, 20, 10, 7)
+ self.myNbEllipses += 1
+ self.myDOF += 5
+ model.do()
+
+ self.mySketch.setTangent(self.mySpline.result(), anEllipse.defaultResult())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.assertTangentFeatures(anEllipse, self.mySpline)
+
+ def test_elliptic_arc_tangent(self):
+ """ Test 5. Set tangency between B-spline and an elliptic arc
+ """
+ anEllipticArc = self.mySketch.addEllipticArc(10, 10, 20, 10, 22.2065556157337, 10, 10, 17, True)
+ self.myNbEllipticArcs += 1
+ self.myDOF += 7
+ model.do()
+
+ self.mySketch.setTangent(self.mySpline.result(), anEllipticArc.defaultResult())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.assertTangentFeatures(anEllipticArc, self.mySpline)
+
+ def test_spline_tangent(self):
+ """ Test 6. Set tangency between two B-spline curves
+ """
+ aSpline = self.mySketch.addSpline(poles = [(50, -20), (40, 0), (50, 20)])
+ self.myNbBSplines += 1
+ self.myDOF += aSpline.poles().size() * 2
+ model.do()
+
+ self.mySketch.setTangent(self.mySpline.result(), aSpline.result())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ #self.assertTangentFeatures(aSpline, self.mySpline)
+ self.myExpectedFailure = True
+
+
+ def test_line_tangent_coincident_by_pole(self):
+ """ Test 7. Set tangency between B-spline and a line coincident with B-spline start point
+ """
+ aLine = self.mySketch.addLine(-15, -25, 50, 40)
+ self.myNbLines += 1
+ self.myDOF += 4
+ model.do()
+
+ self.mySketch.setCoincident(self.mySpline.startPoint(), aLine.result())
+ self.myNbCoincidence += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.mySketch.setTangent(self.mySpline.result(), aLine.result())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.assertPointLineDistance(self.mySpline.startPoint(), aLine)
+ self.assertTangentFeatures(aLine, self.mySpline)
+
+ def test_circle_tangent_coincident_by_pole(self):
+ """ Test 8. Set tangency between B-spline and a circle coincident with B-spline end point
+ """
+ aCircle = self.mySketch.addCircle(10, 10, 20)
+ self.myNbCircles += 1
+ self.myDOF += 3
+ model.do()
+
+ self.mySketch.setCoincident(self.mySpline.startPoint(), aCircle.defaultResult())
+ self.myNbCoincidence += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.mySketch.setTangent(self.mySpline.result(), aCircle.defaultResult())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.assertTangentFeatures(aCircle, self.mySpline)
+ dist = model.distancePointPoint(self.mySpline.startPoint(), aCircle.center())
+ self.assertAlmostEqual(dist, aCircle.radius().value())
+
+ def test_arc_tangent_coincident_by_pole(self):
+ """ Test 9. Set tangency between B-spline and an arc coincident with B-spline end point
+ """
+ anArc = self.mySketch.addArc(10, 10, 20, 10, 10, 20, False)
+ self.myNbArcs += 1
+ self.myDOF += 5
+ model.do()
+
+ self.mySketch.setCoincident(self.mySpline.endPoint(), anArc.defaultResult())
+ self.myNbCoincidence += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.mySketch.setTangent(self.mySpline.result(), anArc.defaultResult())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.assertTangentFeatures(anArc, self.mySpline)
+ dist = model.distancePointPoint(self.mySpline.endPoint(), anArc.center())
+ self.assertAlmostEqual(dist, anArc.radius().value())
+
+ def test_ellipse_tangent_coincident_by_pole(self):
+ """ Test 10. Set tangency between B-spline and an ellipse coincident with B-spline start point
+ """
+ anEllipse = self.mySketch.addEllipse(10, 10, 20, 10, 7)
+ self.myNbEllipses += 1
+ self.myDOF += 5
+ model.do()
+
+ self.mySketch.setCoincident(self.mySpline.startPoint(), anEllipse.defaultResult())
+ self.myNbCoincidence += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.mySketch.setTangent(self.mySpline.result(), anEllipse.defaultResult())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.assertTangentLineEllipse(SketchAPI_Line(self.myControlLines[0]), anEllipse)
+
+ def test_elliptic_arc_tangent_coincident_by_pole(self):
+ """ Test 11. Set tangency between B-spline and an elliptic arc coincident with B-spline start point
+ """
+ anEllipticArc = self.mySketch.addEllipticArc(10, 10, 20, 10, 22.2065556157337, 10, 10, 17, True)
+ self.myNbEllipticArcs += 1
+ self.myDOF += 7
+ model.do()
+
+ self.mySketch.setCoincident(self.mySpline.startPoint(), anEllipticArc.defaultResult())
+ self.myNbCoincidence += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.mySketch.setTangent(self.mySpline.result(), anEllipticArc.defaultResult())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.assertTangentLineEllipse(SketchAPI_Line(self.myControlLines[0]), anEllipticArc)
+
+
+ def test_line_tangent_coincident_by_boundaries(self):
+ """ Test 12. Set tangency between B-spline and a line, coincident by their start points
+ """
+ aLine = self.mySketch.addLine(10, -10, 90, 40)
+ self.myNbLines += 1
+ self.myDOF += 4
+ model.do()
+
+ self.mySketch.setCoincident(self.mySpline.startPoint(), aLine.startPoint())
+ self.myNbCoincidence += 1
+ self.myDOF -= 2
+ model.do()
+
+ self.mySketch.setTangent(self.mySpline.result(), aLine.result())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.assertPointLineDistance(aLine.endPoint(), self.myControlLines[0])
+
+ def test_arc_tangent_coincident_by_boundaries(self):
+ """ Test 13. Set tangency between B-spline and an arc, coincident by their start points
+ """
+ anArc = self.mySketch.addArc(10, 10, 20, 10, 10, 20, False)
+ self.myNbArcs += 1
+ self.myDOF += 5
+ model.do()
+
+ self.mySketch.setCoincident(self.mySpline.startPoint(), anArc.startPoint())
+ self.myNbCoincidence += 1
+ self.myDOF -= 2
+ model.do()
+
+ self.mySketch.setTangent(self.mySpline.result(), anArc.defaultResult())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.assertTangentLineCircle(SketchAPI_Line(self.myControlLines[0]), anArc)
+
+ def test_elliptic_arc_tangent_coincident_by_boundaries(self):
+ """ Test 14. Set tangency between B-spline and an elliptic arc, coincident by their start points
+ """
+ anEllipticArc = self.mySketch.addEllipticArc(10, -10, 20, -10, 22.2065556157337, -10, 10, 3, True)
+ self.myNbEllipticArcs += 1
+ self.myDOF += 7
+ model.do()
+
+ self.mySketch.setCoincident(self.mySpline.startPoint(), anEllipticArc.startPoint())
+ self.myNbCoincidence += 1
+ self.myDOF -= 2
+ model.do()
+
+ self.mySketch.setTangent(self.mySpline.result(), anEllipticArc.defaultResult())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.assertTangentLineEllipse(SketchAPI_Line(self.myControlLines[0]), anEllipticArc)
+
+ def test_spline_tangent_coincident_by_boundaries(self):
+ """ Test 15. Set tangency between two B-spline curves coincident with B-spline start point
+ """
+ aSpline = self.mySketch.addSpline(poles = [(50, -20), (40, 0), (50, 20)])
+ self.myNbBSplines += 1
+ self.myDOF += aSpline.poles().size() * 2
+ model.do()
+
+ self.mySketch.setCoincident(self.mySpline.startPoint(), aSpline.startPoint())
+ self.myNbCoincidence += 1
+ self.myDOF -= 2
+ model.do()
+
+ self.mySketch.setTangent(self.mySpline.result(), aSpline.result())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ #self.assertPointLineDistance(aSpline.poles()[1], self.myControlLines[0])
+ self.myExpectedFailure = True
+
+
+ def test_line_tangent_coincident_by_aux(self):
+ """ Test 16. Set tangency between B-spline and a line, coincident by their start points
+ """
+ aLine = self.mySketch.addLine(10, -10, 90, 40)
+ self.myNbLines += 1
+ self.myDOF += 4
+ model.do()
+
+ self.mySketch.setCoincident(SketchAPI_Point(self.myControlPoles[0]).coordinates(), aLine.startPoint())
+ self.myNbCoincidence += 1
+ self.myDOF -= 2
+ model.do()
+
+ self.mySketch.setTangent(self.mySpline.result(), aLine.result())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.assertPointLineDistance(aLine.endPoint(), self.myControlLines[0])
+
+ def test_arc_tangent_coincident_by_aux(self):
+ """ Test 17. Set tangency between B-spline and an arc, coincident by their start points
+ """
+ anArc = self.mySketch.addArc(10, 10, 20, 10, 10, 20, False)
+ self.myNbArcs += 1
+ self.myDOF += 5
+ model.do()
+
+ self.mySketch.setCoincident(SketchAPI_Point(self.myControlPoles[0]).coordinates(), anArc.startPoint())
+ self.myNbCoincidence += 1
+ self.myDOF -= 2
+ model.do()
+
+ self.mySketch.setTangent(self.mySpline.result(), anArc.defaultResult())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.assertTangentLineCircle(SketchAPI_Line(self.myControlLines[0]), anArc)
+
+ def test_elliptic_arc_tangent_coincident_by_aux(self):
+ """ Test 18. Set tangency between B-spline and an elliptic arc, coincident by their start points
+ """
+ anEllipticArc = self.mySketch.addEllipticArc(10, 10, 20, 10, 22.2065556157337, 10, 10, 17, True)
+ self.myNbEllipticArcs += 1
+ self.myDOF += 7
+ model.do()
+
+ self.mySketch.setCoincident(SketchAPI_Point(self.myControlPoles[0]).coordinates(), anEllipticArc.startPoint())
+ self.myNbCoincidence += 1
+ self.myDOF -= 2
+ model.do()
+
+ self.mySketch.setTangent(self.mySpline.result(), anEllipticArc.defaultResult())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.assertTangentLineEllipse(SketchAPI_Line(self.myControlLines[0]), anEllipticArc)
+
+ def test_spline_tangent_coincident_by_aux(self):
+ """ Test 19. Set tangency between two B-spline curves coincident with B-spline start point
+ """
+ aSpline = self.mySketch.addSpline(poles = [(50, -20), (40, 0), (50, 20)])
+ self.myNbBSplines += 1
+ self.myDOF += aSpline.poles().size() * 2
+ model.do()
+
+ self.mySketch.setCoincident(SketchAPI_Point(self.myControlPoles[0]).coordinates(), aSpline.startPoint())
+ self.myNbCoincidence += 1
+ self.myDOF -= 2
+ model.do()
+
+ self.mySketch.setTangent(self.mySpline.result(), aSpline.result())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ #self.assertPointLineDistance(aSpline.poles().pnt(1), self.myControlLines[0])
+ self.myExpectedFailure = True
+
+
+
+if __name__ == "__main__":
+ test_program = unittest.main(exit=False)
+ assert test_program.result.wasSuccessful(), "Test failed"
+ #assert model.checkPythonDump()
--- /dev/null
+# Copyright (C) 2020 CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+"""
+ Test creation of B-spline curve
+"""
+
+import unittest
+from salome.shaper import model
+
+from GeomAPI import *
+from SketchAPI import *
+
+__updated__ = "2020-01-17"
+
+class TestBSpline(unittest.TestCase):
+ def setUp(self):
+ model.begin()
+ self.myDocument = model.moduleDocument()
+ self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+ self.myPoles = [GeomAPI_Pnt2d(50., 50.), GeomAPI_Pnt2d(70., 70.), GeomAPI_Pnt2d(80., 30.), GeomAPI_Pnt2d(50., 10.), GeomAPI_Pnt2d(10., -30.)]
+ self.myPolesCoordinates = [(50., 50.), (70., 70.), (80., 30.), (50., 10.), (10., -30.)]
+ self.myDegree = 3;
+ self.myDOF = 0
+ self.myNbPoints = 0
+ self.myNbLines = 0
+ self.myNbSplines = 0
+
+ def tearDown(self):
+ self.checkDOF()
+ model.end()
+ model.testNbSubFeatures(self.mySketch, "SketchPoint", self.myNbPoints)
+ model.testNbSubFeatures(self.mySketch, "SketchLine", self.myNbLines)
+ model.testNbSubFeatures(self.mySketch, "SketchBSpline", self.myNbSplines)
+
+
+ def checkDOF(self):
+ self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+
+ def test_bspline_by_coordinates(self):
+ """ Test 1. Create B-spline curve by coordinates of its poles
+ """
+ self.mySpline = self.mySketch.addSpline(poles = self.myPolesCoordinates)
+ self.myDOF += len(self.myPolesCoordinates) * 2
+ self.myNbSplines += 1
+ model.do()
+
+ assert(self.mySpline.feature())
+ assert(self.mySpline.feature().error() == "")
+ assert(self.mySpline.degree().value() == self.myDegree)
+
+ def test_bspline_by_poles(self):
+ """ Test 2. Create B-spline curve by poles
+ """
+ self.mySpline = self.mySketch.addSpline(poles = self.myPoles)
+ self.myDOF += len(self.myPoles) * 2
+ self.myNbSplines += 1
+ model.do()
+
+ assert(self.mySpline.feature())
+ assert(self.mySpline.feature().error() == "")
+ assert(self.mySpline.degree().value() == self.myDegree)
+
+ def test_bspline_by_degree_and_poles(self):
+ """ Test 3. Create B-spline curve by poles and degree
+ """
+ self.myDegree = 4
+ self.mySpline = self.mySketch.addSpline(degree = self.myDegree, poles = self.myPoles)
+ self.myDOF += len(self.myPoles) * 2
+ self.myNbSplines += 1
+ model.do()
+
+ assert(self.mySpline.feature())
+ assert(self.mySpline.feature().error() == "")
+ assert(self.mySpline.degree().value() == self.myDegree)
+
+ def test_bspline_by_poles_and_weights(self):
+ """ Test 4. Create B-spline curve by poles and weights
+ """
+ self.mySpline = self.mySketch.addSpline(poles = self.myPoles, weights = [1, 2, 3, 2, 1])
+ self.myDOF += len(self.myPoles) * 2
+ self.myNbSplines += 1
+ model.do()
+
+ assert(self.mySpline.feature())
+ assert(self.mySpline.feature().error() == "")
+ assert(self.mySpline.degree().value() == self.myDegree)
+
+ def test_bspline_by_parametric(self):
+ """ Test 5. Create B-spline curve by whole set of parameters
+ """
+ self.myDegree = 5
+ self.myPolesCoordinates = [(-79.8578274581199, 75.5284518447357),
+ (-64.6205376770376, 62.7428476092882),
+ (-49.3832478959552, 49.9572433738407),
+ (-34.1459581148729, 37.1716391383932),
+ (-18.9086683337906, 24.3860349029457),
+ (-3.55842111132817, 11.5056481200973),
+ (-3.37993197286247, 11.42995541724),
+ (-3.1778022626919, 11.4565662984205),
+ (-3.02498570721059, 11.575876223351),
+ (8.46852511720001, 27.9903107977019),
+ (19.8774589601206, 44.2839569245217),
+ (31.2863928030413, 60.5776030513415),
+ (42.6953266459619, 76.8712491781612),
+ (54.1042604888826, 93.164895304981)
+ ]
+ self.mySpline = self.mySketch.addSpline(degree = self.myDegree,
+ poles = self.myPolesCoordinates,
+ weights = [1, 1, 1, 1, 1, 1, 0.957903314642061, 0.95790331464206, 1, 1, 1, 1, 1, 1],
+ knots = [-494.543457494654, 500, 507.372773368102, 1501.91623086297],
+ multiplicities = [6, 4, 4, 6])
+ self.myDOF += len(self.myPolesCoordinates) * 2
+ self.myNbSplines += 1
+ model.do()
+
+ assert(self.mySpline.feature())
+ assert(self.mySpline.feature().error() == "")
+ assert(self.mySpline.degree().value() == self.myDegree)
+
+ def test_bspline_linear(self):
+ """ Test 6. Create B-spline curve by 2 poles
+ """
+ self.myDegree = 1
+ self.mySpline = self.mySketch.addSpline(poles = self.myPoles[:2])
+ self.myDOF += 4
+ self.myNbSplines += 1
+ model.do()
+
+ assert(self.mySpline.feature())
+ assert(self.mySpline.feature().error() == "")
+ assert(self.mySpline.degree().value() == self.myDegree)
+
+ def test_bspline_parabola(self):
+ """ Test 7. Create B-spline curve by 3 poles
+ """
+ self.myDegree = 2
+ self.mySpline = self.mySketch.addSpline(poles = self.myPoles[:3])
+ self.myDOF += 6
+ self.myNbSplines += 1
+ model.do()
+
+ assert(self.mySpline.feature())
+ assert(self.mySpline.feature().error() == "")
+ assert(self.mySpline.degree().value() == self.myDegree)
+
+ def test_bspline_with_poles(self):
+ """ Test 8. Create B-spline curve and points coincident with its poles
+ """
+ self.mySpline = self.mySketch.addSpline(poles = self.myPoles)
+ self.mySpline.controlPoles(regular = [0, 2], auxiliary = [1, 3])
+ self.myDOF += len(self.myPoles) * 2
+ self.myNbSplines += 1
+ self.myNbPoints += 4
+ model.do()
+
+ assert(self.mySpline.feature())
+ assert(self.mySpline.feature().error() == "")
+ assert(self.mySpline.degree().value() == self.myDegree)
+
+ def test_bspline_with_polygon(self):
+ """ Test 9. Create B-spline curve and its control polygon
+ """
+ self.mySpline = self.mySketch.addSpline(poles = self.myPoles)
+ self.mySpline.controlPolygon(regular = [0, 2], auxiliary = [1, 3])
+ self.myDOF += len(self.myPoles) * 2
+ self.myNbSplines += 1
+ self.myNbLines += 4
+ model.do()
+
+ assert(self.mySpline.feature())
+ assert(self.mySpline.feature().error() == "")
+ assert(self.mySpline.degree().value() == self.myDegree)
+
+if __name__ == "__main__":
+ test_program = unittest.main(exit=False)
+ assert test_program.result.wasSuccessful(), "Test failed"
+ assert model.checkPythonDump()
--- /dev/null
+# Copyright (C) 2020 CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+"""
+ Test creation of periodic B-spline curve
+"""
+
+import unittest
+from salome.shaper import model
+
+from GeomAPI import *
+from SketchAPI import *
+
+__updated__ = "2020-01-24"
+
+class TestBSplinePeriodic(unittest.TestCase):
+ def setUp(self):
+ model.begin()
+ self.myDocument = model.moduleDocument()
+ self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+ self.myPoles = [GeomAPI_Pnt2d(50., 50.), GeomAPI_Pnt2d(70., 70.), GeomAPI_Pnt2d(80., 30.), GeomAPI_Pnt2d(50., 10.), GeomAPI_Pnt2d(10., -30.)]
+ self.myPolesCoordinates = [(50., 50.), (70., 70.), (80., 30.), (50., 10.), (10., -30.)]
+ self.myDegree = 3;
+ self.myDOF = 0
+ self.myNbPoints = 0
+ self.myNbLines = 0
+ self.myNbSplines = 0
+
+ def tearDown(self):
+ self.checkDOF()
+ model.end()
+ model.testNbSubFeatures(self.mySketch, "SketchPoint", self.myNbPoints)
+ model.testNbSubFeatures(self.mySketch, "SketchLine", self.myNbLines)
+ model.testNbSubFeatures(self.mySketch, "SketchBSplinePeriodic", self.myNbSplines)
+
+
+ def checkDOF(self):
+ self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+
+ def test_bspline_by_coordinates(self):
+ """ Test 1. Create B-spline curve by coordinates of its poles
+ """
+ self.mySpline = self.mySketch.addSpline(poles = self.myPolesCoordinates, periodic = True)
+ self.myDOF += len(self.myPolesCoordinates) * 2
+ self.myNbSplines += 1
+ model.do()
+
+ assert(self.mySpline.feature())
+ assert(self.mySpline.feature().error() == "")
+ assert(self.mySpline.degree().value() == self.myDegree)
+
+ def test_bspline_by_poles(self):
+ """ Test 2. Create B-spline curve by poles
+ """
+ self.mySpline = self.mySketch.addSpline(poles = self.myPoles, periodic = True)
+ self.myDOF += len(self.myPoles) * 2
+ self.myNbSplines += 1
+ model.do()
+
+ assert(self.mySpline.feature())
+ assert(self.mySpline.feature().error() == "")
+ assert(self.mySpline.degree().value() == self.myDegree)
+
+ def test_bspline_by_degree_and_poles(self):
+ """ Test 3. Create B-spline curve by poles and degree
+ """
+ self.myDegree = 4
+ self.mySpline = self.mySketch.addSpline(degree = self.myDegree, poles = self.myPoles, periodic = True)
+ self.myDOF += len(self.myPoles) * 2
+ self.myNbSplines += 1
+ model.do()
+
+ assert(self.mySpline.feature())
+ assert(self.mySpline.feature().error() == "")
+ assert(self.mySpline.degree().value() == self.myDegree)
+
+ def test_bspline_by_poles_and_weights(self):
+ """ Test 4. Create B-spline curve by poles and weights
+ """
+ self.mySpline = self.mySketch.addSpline(poles = self.myPoles, weights = [1, 2, 3, 2, 1], periodic = True)
+ self.myDOF += len(self.myPoles) * 2
+ self.myNbSplines += 1
+ model.do()
+
+ assert(self.mySpline.feature())
+ assert(self.mySpline.feature().error() == "")
+ assert(self.mySpline.degree().value() == self.myDegree)
+
+ def test_bspline_by_parametric(self):
+ """ Test 5. Create B-spline curve by whole set of parameters
+ """
+ self.myDegree = 3
+ self.myPolesCoordinates = [(-10, 0), (-20, 20), (0, 10), (20, 20),
+ (10, 0), (20, -20), (0, -10), (-20, -20)
+ ]
+ self.mySpline = self.mySketch.addSpline(degree = self.myDegree,
+ poles = self.myPolesCoordinates,
+ weights = [1, 1, 1, 1, 1, 1, 1, 1],
+ knots = [0, 1, 2, 3, 4, 5, 6, 7, 8],
+ multiplicities = [1, 1, 1, 1, 1, 1, 1, 1, 1],
+ periodic = True)
+ self.myDOF += len(self.myPolesCoordinates) * 2
+ self.myNbSplines += 1
+ model.do()
+
+ assert(self.mySpline.feature())
+ assert(self.mySpline.feature().error() == "")
+ assert(self.mySpline.degree().value() == self.myDegree)
+
+ def test_bspline_linear(self):
+ """ Test 6. Create B-spline curve by 2 poles
+ """
+ self.myDegree = 1
+ self.mySpline = self.mySketch.addSpline(poles = self.myPoles[:2], periodic = True)
+ self.myDOF += 4
+ self.myNbSplines += 1
+ model.do()
+
+ assert(self.mySpline.feature())
+ assert(self.mySpline.feature().error() == "")
+ assert(self.mySpline.degree().value() == self.myDegree)
+
+ def test_bspline_parabola(self):
+ """ Test 7. Create B-spline curve by 3 poles
+ """
+ self.myDegree = 2
+ self.mySpline = self.mySketch.addSpline(poles = self.myPoles[:3], periodic = True)
+ self.myDOF += 6
+ self.myNbSplines += 1
+ model.do()
+
+ assert(self.mySpline.feature())
+ assert(self.mySpline.feature().error() == "")
+ assert(self.mySpline.degree().value() == self.myDegree)
+
+ def test_bspline_with_poles(self):
+ """ Test 8. Create B-spline curve and points coincident with its poles
+ """
+ self.mySpline = self.mySketch.addSpline(poles = self.myPoles, periodic = True)
+ self.mySpline.controlPoles(regular = [0, 2], auxiliary = [1, 3])
+ self.myDOF += len(self.myPoles) * 2
+ self.myNbSplines += 1
+ self.myNbPoints += 4
+ model.do()
+
+ assert(self.mySpline.feature())
+ assert(self.mySpline.feature().error() == "")
+ assert(self.mySpline.degree().value() == self.myDegree)
+
+ def test_bspline_with_polygon(self):
+ """ Test 9. Create B-spline curve and its control polygon
+ """
+ self.mySpline = self.mySketch.addSpline(poles = self.myPoles, periodic = True)
+ self.mySpline.controlPolygon(regular = [0, 2], auxiliary = [1, 3])
+ self.myDOF += len(self.myPoles) * 2
+ self.myNbSplines += 1
+ self.myNbLines += 4
+ model.do()
+
+ assert(self.mySpline.feature())
+ assert(self.mySpline.feature().error() == "")
+ assert(self.mySpline.degree().value() == self.myDegree)
+
+if __name__ == "__main__":
+ test_program = unittest.main(exit=False)
+ assert test_program.result.wasSuccessful(), "Test failed"
+ assert model.checkPythonDump()
--- /dev/null
+# Copyright (C) 2019-2020 CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+"""
+ Test movement of the B-spline curve
+"""
+
+import unittest
+import math
+from GeomAPI import *
+from GeomDataAPI import geomDataAPI_Point2DArray
+from SketchAPI import *
+from salome.shaper import model
+
+__updated__ = "2020-01-20"
+
+class TestMoveBSpline(unittest.TestCase):
+ def setUp(self):
+ model.begin()
+ self.myDocument = model.moduleDocument()
+ self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+ self.myPoles = [GeomAPI_Pnt2d(20., 50.),
+ GeomAPI_Pnt2d(70., 70.),
+ GeomAPI_Pnt2d(80., 30.),
+ GeomAPI_Pnt2d(50., 10.),
+ GeomAPI_Pnt2d(90., -30.)]
+ self.mySpline = self.mySketch.addSpline(poles = self.myPoles)
+ self.myDOF = len(self.myPoles) * 2
+ model.do()
+ self.checkDOF()
+
+ def tearDown(self):
+ self.checkDOF()
+ model.end()
+
+ def checkDOF(self):
+ self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+ def checkPointCoordinates(self, thePoint, theCoordinates):
+ aCoord = []
+ if issubclass(type(theCoordinates), GeomAPI_Pnt2d):
+ aCoord = [theCoordinates.x(), theCoordinates.y()]
+ else:
+ aCoord = theCoordinates
+ DIGITS = 7 - math.floor(math.log10(math.hypot(aCoord[0], aCoord[1])))
+ self.assertAlmostEqual(thePoint.x(), aCoord[0], DIGITS)
+ self.assertAlmostEqual(thePoint.y(), aCoord[1], DIGITS)
+
+ def checkPoles(self, theBSpline, theCoordinates):
+ poles = theBSpline.poles()
+ for index, point in zip(range(0, len(theCoordinates)), theCoordinates):
+ self.checkPointCoordinates(poles.pnt(index), point)
+
+ def fixPoint(self, thePoint):
+ self.mySketch.setFixed(thePoint)
+ self.myDOF -= 2
+ model.do()
+ self.checkDOF()
+
+
+ def test_move_free_bspline(self):
+ """ Test 1. Movement of a free B-spline dragging the edge
+ """
+ oldPosition = GeomAPI_Edge(self.mySpline.defaultResult().shape()).middlePoint()
+ newPosition = GeomAPI_Pnt2d(120., 90.)
+ self.mySketch.move(self.mySpline.defaultResult(), newPosition)
+ model.do()
+
+ # plane is XOY, no need to project oldPosition point
+ dx = newPosition.x() - oldPosition.x()
+ dy = newPosition.y() - oldPosition.y()
+
+ newPoles = []
+ for pole in self.myPoles:
+ newPoles.append(GeomAPI_Pnt2d(pole.x() + dx, pole.y() + dy))
+ self.checkPoles(self.mySpline, newPoles)
+
+ def test_move_start_point(self):
+ """ Test 2. Movement of start point of a free B-spline curve
+ """
+ newPoles = self.myPoles
+
+ newPoles[0].setX(newPoles[0].x() - 20.)
+ newPoles[0].setY(newPoles[0].y() + 10.)
+ self.mySketch.move(self.mySpline.startPoint(), newPoles[0])
+ model.do()
+
+ self.checkPoles(self.mySpline, newPoles)
+
+ def test_move_end_point(self):
+ """ Test 3. Movement of end point of a free B-spline curve
+ """
+ newPoles = self.myPoles
+
+ newPoles[-1].setX(newPoles[-1].x() + 20.)
+ newPoles[-1].setY(newPoles[-1].y() + 10.)
+ self.mySketch.move(self.mySpline.endPoint(), newPoles[-1])
+ model.do()
+
+ self.checkPoles(self.mySpline, newPoles)
+
+
+ def test_move_bspline_with_start_point_fixed(self):
+ """ Test 4. Movement of a B-spline dragging the edge when start point is fixed
+ """
+ self.fixPoint(self.mySpline.startPoint())
+ model.do()
+
+ oldPosition = GeomAPI_Edge(self.mySpline.defaultResult().shape()).middlePoint()
+ newPosition = GeomAPI_Pnt2d(120., 90.)
+ self.mySketch.move(self.mySpline.defaultResult(), newPosition)
+ model.do()
+
+ # plane is XOY, no need to project oldPosition point
+ dx = newPosition.x() - oldPosition.x()
+ dy = newPosition.y() - oldPosition.y()
+
+ newPoles = [self.myPoles[0]]
+ for pole in self.myPoles[1:]:
+ newPoles.append(GeomAPI_Pnt2d(pole.x() + dx, pole.y() + dy))
+ self.checkPoles(self.mySpline, newPoles)
+
+ def test_move_start_point_with_start_point_fixed(self):
+ """ Test 5. Movement of start point of a free B-spline curve has no result if the first pole is fixed
+ """
+ self.fixPoint(self.mySpline.startPoint())
+ model.do()
+
+ self.mySketch.move(self.mySpline.startPoint(), self.myPoles[0].x() - 10., self.myPoles[0].y() + 10.)
+ model.do()
+
+ self.checkPoles(self.mySpline, self.myPoles)
+
+ def test_move_end_point_with_start_point_fixed(self):
+ """ Test 6. Movement of end point of a free B-spline curve when start point is fixed
+ """
+ self.fixPoint(self.mySpline.startPoint())
+ model.do()
+
+ newPoles = self.myPoles
+
+ newPoles[-1].setX(newPoles[-1].x() + 20.)
+ newPoles[-1].setY(newPoles[-1].y() + 10.)
+ self.mySketch.move(self.mySpline.endPoint(), newPoles[-1])
+ model.do()
+
+ self.checkPoles(self.mySpline, newPoles)
+
+
+ def test_move_bspline_with_end_point_fixed(self):
+ """ Test 7. Movement of a B-spline dragging the edge when end point is fixed
+ """
+ self.fixPoint(self.mySpline.endPoint())
+ model.do()
+
+ oldPosition = GeomAPI_Edge(self.mySpline.defaultResult().shape()).middlePoint()
+ newPosition = GeomAPI_Pnt2d(120., 90.)
+ self.mySketch.move(self.mySpline.defaultResult(), newPosition)
+ model.do()
+
+ # plane is XOY, no need to project oldPosition point
+ dx = newPosition.x() - oldPosition.x()
+ dy = newPosition.y() - oldPosition.y()
+
+ newPoles = []
+ for pole in self.myPoles[:-1]:
+ newPoles.append(GeomAPI_Pnt2d(pole.x() + dx, pole.y() + dy))
+ newPoles.append(self.myPoles[-1])
+ self.checkPoles(self.mySpline, newPoles)
+
+ def test_move_start_point_with_end_point_fixed(self):
+ """ Test 8. Movement of start point of a free B-spline curve when end point is fixed
+ """
+ self.fixPoint(self.mySpline.endPoint())
+ model.do()
+
+ newPoles = self.myPoles
+
+ newPoles[0].setX(newPoles[0].x() + 20.)
+ newPoles[0].setY(newPoles[0].y() + 10.)
+ self.mySketch.move(self.mySpline.startPoint(), self.myPoles[0])
+ model.do()
+
+ self.checkPoles(self.mySpline, self.myPoles)
+
+ def test_move_end_point_with_end_point_fixed(self):
+ """ Test 9. Movement of end point of a free B-spline curve has no result if the last pole is fixed
+ """
+ self.fixPoint(self.mySpline.endPoint())
+ model.do()
+
+ self.mySketch.move(self.mySpline.endPoint(), self.myPoles[-1].x() + 10., self.myPoles[-1].y() + 10.)
+ model.do()
+
+ self.checkPoles(self.mySpline, self.myPoles)
+
+
+ def test_move_fixed_bspline(self):
+ """ Test 10. Movement of a fully fixed B-spline
+ """
+ self.mySketch.setFixed(self.mySpline.defaultResult())
+ self.myDOF = 0
+ model.do()
+
+ newPosition = GeomAPI_Pnt2d(120., 90.)
+ self.mySketch.move(self.mySpline.defaultResult(), newPosition)
+ model.do()
+
+ self.checkPoles(self.mySpline, self.myPoles)
+
+ def test_move_start_point_of_fixed_bspline(self):
+ """ Test 11. Movement of start point of a fully fixed B-spline curve
+ """
+ self.mySketch.setFixed(self.mySpline.defaultResult())
+ self.myDOF = 0
+ model.do()
+
+ self.mySketch.move(self.mySpline.startPoint(), self.myPoles[0].x() + 10., self.myPoles[0].y() + 10.)
+ model.do()
+
+ self.checkPoles(self.mySpline, self.myPoles)
+
+ def test_move_end_point_of_fixed_bspline(self):
+ """ Test 12. Movement of end point of a fully fixed B-spline curve
+ """
+ self.mySketch.setFixed(self.mySpline.defaultResult())
+ self.myDOF = 0
+ model.do()
+
+ self.mySketch.move(self.mySpline.endPoint(), self.myPoles[-1].x() + 10., self.myPoles[-1].y() + 10.)
+ model.do()
+
+ self.checkPoles(self.mySpline, self.myPoles)
+
+
+ def test_move_bspline_with_fixed_pole(self):
+ """ Test 13. Movement of a B-spline curve with fixed pole
+ """
+ [Point_1, Point_2, Point_3, Point_4, Point_5] = self.mySpline.controlPoles(auxiliary = [0, 1, 2, 3, 4])
+ model.do()
+
+ self.fixPoint(Point_2.defaultResult())
+ model.do()
+
+ oldPosition = GeomAPI_Edge(self.mySpline.defaultResult().shape()).middlePoint()
+ newPosition = GeomAPI_Pnt2d(120., 90.)
+ self.mySketch.move(self.mySpline.defaultResult(), newPosition)
+ model.do()
+
+ # plane is XOY, no need to project oldPosition point
+ dx = newPosition.x() - oldPosition.x()
+ dy = newPosition.y() - oldPosition.y()
+
+ newPoles = []
+ for pole in self.myPoles:
+ newPoles.append(GeomAPI_Pnt2d(pole.x() + dx, pole.y() + dy))
+ newPoles[1].setX(newPoles[1].x() - dx)
+ newPoles[1].setY(newPoles[1].y() - dy)
+ self.checkPoles(self.mySpline, newPoles)
+
+ def test_move_start_point_with_fixed_pole(self):
+ """ Test 14. Movement of start point of a B-spline curve with fixed pole
+ """
+ [Point_1, Point_2, Point_3, Point_4, Point_5] = self.mySpline.controlPoles(auxiliary = [0, 1, 2, 3, 4])
+ model.do()
+
+ self.fixPoint(Point_2.defaultResult())
+ model.do()
+
+ newPoles = self.myPoles
+
+ newPoles[0].setX(newPoles[0].x() + 20.)
+ newPoles[0].setY(newPoles[0].y() + 10.)
+ self.mySketch.move(self.mySpline.startPoint(), newPoles[0])
+ model.do()
+
+ self.checkPoles(self.mySpline, newPoles)
+
+ def test_move_end_point_with_fixed_pole(self):
+ """ Test 15. Movement of end point of a B-spline curve with fixed pole
+ """
+ [Point_1, Point_2, Point_3, Point_4, Point_5] = self.mySpline.controlPoles(auxiliary = [0, 1, 2, 3, 4])
+ model.do()
+
+ self.fixPoint(Point_2.defaultResult())
+ model.do()
+
+ newPoles = self.myPoles
+
+ newPoles[-1].setX(newPoles[-1].x() + 20.)
+ newPoles[-1].setY(newPoles[-1].y() + 10.)
+ self.mySketch.move(self.mySpline.endPoint(), newPoles[-1])
+ model.do()
+
+ self.checkPoles(self.mySpline, newPoles)
+
+
+ def test_move_bspline_with_fixed_segment(self):
+ """ Test 16. Movement of a B-spline curve with fixed control segment
+ """
+ [Line_1, Line_2, Line_3, Line_4] = self.mySpline.controlPolygon(auxiliary = [0, 1, 2, 3])
+ model.do()
+
+ self.mySketch.setFixed(Line_1.defaultResult())
+ self.myDOF -= 4
+ model.do()
+
+ oldPosition = GeomAPI_Edge(self.mySpline.defaultResult().shape()).middlePoint()
+ newPosition = GeomAPI_Pnt2d(120., 90.)
+ self.mySketch.move(self.mySpline.defaultResult(), newPosition)
+ model.do()
+
+ # plane is XOY, no need to project oldPosition point
+ dx = newPosition.x() - oldPosition.x()
+ dy = newPosition.y() - oldPosition.y()
+
+ newPoles = [self.myPoles[0], self.myPoles[1]]
+ for pole in self.myPoles[2:]:
+ newPoles.append(GeomAPI_Pnt2d(pole.x() + dx, pole.y() + dy))
+ self.checkPoles(self.mySpline, newPoles)
+
+ def test_move_start_point_with_fixed_segment(self):
+ """ Test 17. Movement of start point of a B-spline curve with fixed control segment
+ """
+ [Line_1, Line_2, Line_3, Line_4] = self.mySpline.controlPolygon(auxiliary = [0, 1, 2, 3])
+ model.do()
+
+ self.mySketch.setFixed(Line_1.defaultResult())
+ self.myDOF -= 4
+ model.do()
+
+ self.mySketch.move(self.mySpline.startPoint(), self.myPoles[0].x() + 10., self.myPoles[0].y() - 20.)
+ model.do()
+
+ self.checkPoles(self.mySpline, self.myPoles)
+
+ def test_move_end_point_with_fixed_segment(self):
+ """ Test 18. Movement of end point of a B-spline curve with fixed control segment
+ """
+ [Line_1, Line_2, Line_3, Line_4] = self.mySpline.controlPolygon(auxiliary = [0, 1, 2, 3])
+ model.do()
+
+ self.mySketch.setFixed(Line_1.defaultResult())
+ self.myDOF -= 4
+ model.do()
+
+ newPoles = self.myPoles
+
+ newPoles[-1].setX(newPoles[-1].x() + 20.)
+ newPoles[-1].setY(newPoles[-1].y() + 10.)
+ self.mySketch.move(self.mySpline.endPoint(), newPoles[-1])
+ model.do()
+
+ self.checkPoles(self.mySpline, newPoles)
+
+
+ def test_move_pole_of_free_bspline(self):
+ """ Test 19. Movement of a pole of a B-spline curve
+ """
+ [Point_1, Point_2, Point_3, Point_4, Point_5] = self.mySpline.controlPoles(auxiliary = [0, 1, 2, 3, 4])
+ [Line_1, Line_2, Line_3, Line_4] = self.mySpline.controlPolygon(auxiliary = [0, 1, 2, 3])
+ model.do()
+
+ newPoles = self.myPoles
+
+ newPoles[2].setX(newPoles[2].x() + 20.)
+ newPoles[2].setY(newPoles[2].y() + 20.)
+ self.mySketch.move(SketchAPI_Point(Point_3).coordinates(), newPoles[2])
+ model.do()
+
+ self.checkPoles(self.mySpline, newPoles)
+
+ def test_move_segment_of_free_bspline(self):
+ """ Test 20. Movement of a control segment of a B-spline curve
+ """
+ [Point_1, Point_2, Point_3, Point_4, Point_5] = self.mySpline.controlPoles(auxiliary = [0, 1, 2, 3, 4])
+ [Line_1, Line_2, Line_3, Line_4] = self.mySpline.controlPolygon(auxiliary = [0, 1, 2, 3])
+ model.do()
+
+ oldPosition = GeomAPI_Pnt2d(0.5 * (self.myPoles[2].x() + self.myPoles[3].x()),
+ 0.5 * (self.myPoles[2].y() + self.myPoles[3].y()))
+ newPosition = GeomAPI_Pnt2d(120., 90.)
+ self.mySketch.move(SketchAPI_Line(Line_3).defaultResult(), newPosition)
+ model.do()
+
+ dx = newPosition.x() - oldPosition.x()
+ dy = newPosition.y() - oldPosition.y()
+
+ newPoles = self.myPoles
+ newPoles[2].setX(newPoles[2].x() + dx)
+ newPoles[2].setY(newPoles[2].y() + dy)
+ newPoles[3].setX(newPoles[3].x() + dx)
+ newPoles[3].setY(newPoles[3].y() + dy)
+
+ self.checkPoles(self.mySpline, newPoles)
+
+
+
+if __name__ == "__main__":
+ test_program = unittest.main(exit=False)
+ assert test_program.result.wasSuccessful(), "Test failed"
+ assert model.checkPythonDump()
--- /dev/null
+# Copyright (C) 2019-2020 CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+"""
+ Test movement of the periodic B-spline curve
+"""
+
+import unittest
+import math
+from GeomAPI import *
+from GeomDataAPI import geomDataAPI_Point2DArray
+from SketchAPI import *
+from salome.shaper import model
+
+__updated__ = "2020-01-20"
+
+class TestMoveBSpline(unittest.TestCase):
+ def setUp(self):
+ model.begin()
+ self.myDocument = model.moduleDocument()
+ self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+ self.myPoles = [GeomAPI_Pnt2d(20., 50.),
+ GeomAPI_Pnt2d(70., 70.),
+ GeomAPI_Pnt2d(80., 30.),
+ GeomAPI_Pnt2d(50., -10.),
+ GeomAPI_Pnt2d(90., -30.)]
+ self.mySpline = self.mySketch.addSpline(poles = self.myPoles, periodic = True)
+ self.myDOF = len(self.myPoles) * 2
+ model.do()
+ self.checkDOF()
+
+ def tearDown(self):
+ self.checkDOF()
+ model.end()
+
+ def checkDOF(self):
+ self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+ def checkPointCoordinates(self, thePoint, theCoordinates):
+ aCoord = []
+ if issubclass(type(theCoordinates), GeomAPI_Pnt2d):
+ aCoord = [theCoordinates.x(), theCoordinates.y()]
+ else:
+ aCoord = theCoordinates
+ DIGITS = 7 - math.floor(math.log10(math.hypot(aCoord[0], aCoord[1])))
+ self.assertAlmostEqual(thePoint.x(), aCoord[0], DIGITS)
+ self.assertAlmostEqual(thePoint.y(), aCoord[1], DIGITS)
+
+ def checkPoles(self, theBSpline, theCoordinates):
+ poles = theBSpline.poles()
+ for index, point in zip(range(0, len(theCoordinates)), theCoordinates):
+ self.checkPointCoordinates(poles.pnt(index), point)
+
+ def fixPoint(self, thePoint):
+ self.mySketch.setFixed(thePoint)
+ self.myDOF -= 2
+ model.do()
+ self.checkDOF()
+
+
+ def test_move_free_bspline(self):
+ """ Test 1. Movement of a free B-spline dragging the edge
+ """
+ oldPosition = GeomAPI_Edge(self.mySpline.defaultResult().shape()).middlePoint()
+ newPosition = GeomAPI_Pnt2d(120., 90.)
+ self.mySketch.move(self.mySpline.defaultResult(), newPosition)
+ model.do()
+
+ # plane is XOY, no need to project oldPosition point
+ dx = newPosition.x() - oldPosition.x()
+ dy = newPosition.y() - oldPosition.y()
+
+ newPoles = []
+ for pole in self.myPoles:
+ newPoles.append(GeomAPI_Pnt2d(pole.x() + dx, pole.y() + dy))
+ self.checkPoles(self.mySpline, newPoles)
+
+
+ def test_move_fixed_bspline(self):
+ """ Test 2. Movement of a fully fixed B-spline
+ """
+ self.mySketch.setFixed(self.mySpline.defaultResult())
+ self.myDOF = 0
+ model.do()
+
+ newPosition = GeomAPI_Pnt2d(120., 90.)
+ self.mySketch.move(self.mySpline.defaultResult(), newPosition)
+ model.do()
+
+ self.checkPoles(self.mySpline, self.myPoles)
+
+
+ def test_move_bspline_with_fixed_pole(self):
+ """ Test 3. Movement of a B-spline curve with fixed pole
+ """
+ [Point_1, Point_2, Point_3, Point_4, Point_5] = self.mySpline.controlPoles(auxiliary = [0, 1, 2, 3, 4])
+ model.do()
+
+ self.fixPoint(Point_2.defaultResult())
+ model.do()
+
+ oldPosition = GeomAPI_Edge(self.mySpline.defaultResult().shape()).middlePoint()
+ newPosition = GeomAPI_Pnt2d(120., 90.)
+ self.mySketch.move(self.mySpline.defaultResult(), newPosition)
+ model.do()
+
+ # plane is XOY, no need to project oldPosition point
+ dx = newPosition.x() - oldPosition.x()
+ dy = newPosition.y() - oldPosition.y()
+
+ newPoles = []
+ for pole in self.myPoles:
+ newPoles.append(GeomAPI_Pnt2d(pole.x() + dx, pole.y() + dy))
+ newPoles[1].setX(newPoles[1].x() - dx)
+ newPoles[1].setY(newPoles[1].y() - dy)
+ self.checkPoles(self.mySpline, newPoles)
+
+
+ def test_move_bspline_with_fixed_segment(self):
+ """ Test 4. Movement of a B-spline curve with fixed control segment
+ """
+ [Line_1, Line_2, Line_3, Line_4, Line_5] = self.mySpline.controlPolygon(auxiliary = [0, 1, 2, 3, 4])
+ model.do()
+
+ self.mySketch.setFixed(Line_1.defaultResult())
+ self.myDOF -= 4
+ model.do()
+
+ oldPosition = GeomAPI_Edge(self.mySpline.defaultResult().shape()).middlePoint()
+ newPosition = GeomAPI_Pnt2d(120., 90.)
+ self.mySketch.move(self.mySpline.defaultResult(), newPosition)
+ model.do()
+
+ # plane is XOY, no need to project oldPosition point
+ dx = newPosition.x() - oldPosition.x()
+ dy = newPosition.y() - oldPosition.y()
+
+ newPoles = [self.myPoles[0], self.myPoles[1]]
+ for pole in self.myPoles[2:]:
+ newPoles.append(GeomAPI_Pnt2d(pole.x() + dx, pole.y() + dy))
+ self.checkPoles(self.mySpline, newPoles)
+
+
+ def test_move_pole_of_free_bspline(self):
+ """ Test 5. Movement of a pole of a B-spline curve
+ """
+ [Point_1, Point_2, Point_3, Point_4, Point_5] = self.mySpline.controlPoles(auxiliary = [0, 1, 2, 3, 4])
+ [Line_1, Line_2, Line_3, Line_4, Line_5] = self.mySpline.controlPolygon(auxiliary = [0, 1, 2, 3, 4])
+ model.do()
+
+ newPoles = self.myPoles
+
+ newPoles[2].setX(newPoles[2].x() + 20.)
+ newPoles[2].setY(newPoles[2].y() + 20.)
+ self.mySketch.move(SketchAPI_Point(Point_3).coordinates(), newPoles[2])
+ model.do()
+
+ self.checkPoles(self.mySpline, newPoles)
+
+ def test_move_segment_of_free_bspline(self):
+ """ Test 6. Movement of a control segment of a B-spline curve
+ """
+ [Point_1, Point_2, Point_3, Point_4, Point_5] = self.mySpline.controlPoles(auxiliary = [0, 1, 2, 3, 4])
+ [Line_1, Line_2, Line_3, Line_4, Line_5] = self.mySpline.controlPolygon(auxiliary = [0, 1, 2, 3, 4])
+ model.do()
+
+ oldPosition = GeomAPI_Pnt2d(0.5 * (self.myPoles[2].x() + self.myPoles[3].x()),
+ 0.5 * (self.myPoles[2].y() + self.myPoles[3].y()))
+ newPosition = GeomAPI_Pnt2d(120., 90.)
+ self.mySketch.move(SketchAPI_Line(Line_3).defaultResult(), newPosition)
+ model.do()
+
+ dx = newPosition.x() - oldPosition.x()
+ dy = newPosition.y() - oldPosition.y()
+
+ newPoles = self.myPoles
+ newPoles[2].setX(newPoles[2].x() + dx)
+ newPoles[2].setY(newPoles[2].y() + dy)
+ newPoles[3].setX(newPoles[3].x() + dx)
+ newPoles[3].setY(newPoles[3].y() + dy)
+
+ self.checkPoles(self.mySpline, newPoles)
+
+
+
+if __name__ == "__main__":
+ test_program = unittest.main(exit=False)
+ assert test_program.result.wasSuccessful(), "Test failed"
+ assert model.checkPythonDump()
anEllipticArcPnt4.setValue(-10, 0)
assert(featureToPresentation(anEllipticArc).getAISObject(None) is not None)
aSession.finishOperation()
+
+# Test presentation for MacroBSpline on low-level
+aSession.startOperation()
+aBSpline = aSketchFeature.addFeature("SketchMacroBSpline")
+aPoles = geomDataAPI_Point2DArray(aBSpline.attribute("poles"))
+aPoles.setSize(4)
+aPoles.setPnt(0, 0, 0)
+aPoles.setPnt(1, 10, 0)
+aPoles.setPnt(2, 10, 10)
+aPoles.setPnt(3, 0, 10)
+aWeights = aBSpline.data().realArray("weights")
+aWeights.setSize(4)
+aWeights.setValue(0, 1)
+aWeights.setValue(1, 2)
+aWeights.setValue(2, 2)
+aWeights.setValue(3, 1)
+aBSpline.boolean("need_control_poly").setValue(True)
+assert(featureToPresentation(aBSpline).getAISObject(None) is not None)
+aSession.finishOperation()
+
+# Test presentation for MacroBSplinePeriodic on low-level
+aSession.startOperation()
+aBSplineP = aSketchFeature.addFeature("SketchMacroBSplinePeriodic")
+aPoles = geomDataAPI_Point2DArray(aBSplineP.attribute("poles"))
+aPoles.setSize(4)
+aPoles.setPnt(0, 0, 0)
+aPoles.setPnt(1, 10, 0)
+aPoles.setPnt(2, 10, 10)
+aPoles.setPnt(3, 0, 10)
+aWeights = aBSplineP.data().realArray("weights")
+aWeights.setSize(4)
+aWeights.setValue(0, 1)
+aWeights.setValue(1, 2)
+aWeights.setValue(2, 2)
+aWeights.setValue(3, 1)
+aBSplineP.boolean("need_control_poly").setValue(True)
+assert(featureToPresentation(aBSplineP).getAISObject(None) is not None)
+aSession.finishOperation()
--- /dev/null
+# Copyright (C) 2019-2020 CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10, 180)
+Sketch_1 = model.addSketch(Part_1_doc, model.selection("FACE", "Cylinder_1_1/Face_5"))
+SketchCircle_1 = Sketch_1.addCircle(-0.87355746875896, 7.873567272779828, 3.095312696967586)
+model.do()
+ExtrusionCut_1 = model.addExtrusionCut(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2r")], model.selection(), [model.selection("SOLID", "Cylinder_1_1")])
+Rotation_1 = model.addRotation(Part_1_doc, [model.selection("SOLID", "ExtrusionCut_1_1")], model.selection("EDGE", "PartSet/OX"), 45)
+Edge_1 = model.addEdge(Part_1_doc, [model.selection("EDGE", "[Rotation_1_1/MF:Rotated&Cylinder_1_1/Face_1][(Rotation_1_1/MF:Rotated&Cylinder_1_1/Face_1)(Rotation_1_1/MF:Rotated&Cylinder_1_1/Face_5)(Rotation_1_1/MF:Rotated&Cylinder_1_1/Face_4)(Rotation_1_1/MF:Rotated&Cylinder_1_1/Face_3)2]")], False)
+
+Sketch_2 = model.addSketch(Part_1_doc, model.standardPlane("XOY"))
+SketchProjection_1 = Sketch_2.addProjection(model.selection("EDGE", "Edge_1_1"), True)
+SketchBSpline_1 = SketchProjection_1.createdFeature()
+model.do()
+
+Sketch_3 = model.addSketch(Part_1_doc, model.standardPlane("XOZ"))
+SketchProjection_2 = Sketch_3.addProjection(model.selection("EDGE", "Edge_1_1"), True)
+SketchBSpline_2 = SketchProjection_2.createdFeature()
+model.do()
+
+Sketch_4 = model.addSketch(Part_1_doc, model.standardPlane("YOZ"))
+SketchProjection_3 = Sketch_4.addProjection(model.selection("EDGE", "Edge_1_1"), True)
+SketchBSpline_3 = SketchProjection_3.createdFeature()
+model.do()
+
+model.end()
+
+from GeomAPI import *
+import math
+
+TOLERANCE = 1.e-7
+
+def checkProjection(theBSpline3D, theBSpline2D, theFlags):
+ assert(theBSpline2D.isEdge() and theBSpline2D.edge().isBSpline())
+ poles2D = GeomAPI_BSpline(GeomAPI_Curve(theBSpline2D)).poles()
+ poles3D = theBSpline3D.poles()
+ assert(poles2D.size() == poles3D.size())
+ for p2d, p3d in zip(poles2D, poles3D):
+ assert(math.fabs((p2d.x() - p3d.x()) * theFlags.x()) < TOLERANCE and
+ math.fabs((p2d.y() - p3d.y()) * theFlags.y()) < TOLERANCE and
+ math.fabs((p2d.z() - p3d.z()) * theFlags.z()) < TOLERANCE)
+
+
+bspline0 = GeomAPI_BSpline(GeomAPI_Curve(Edge_1.results()[-1].resultSubShapePair()[0].shape()))
+
+bsplineShape1 = SketchBSpline_1.results()[-1].resultSubShapePair()[0].shape()
+checkProjection(bspline0, bsplineShape1, GeomAPI_Pnt(1, 1, 0))
+
+bsplineShape2 = SketchBSpline_2.results()[-1].resultSubShapePair()[0].shape()
+checkProjection(bspline0, bsplineShape2, GeomAPI_Pnt(1, 0, 1))
+
+bsplineShape3 = SketchBSpline_3.results()[-1].resultSubShapePair()[0].shape()
+checkProjection(bspline0, bsplineShape3, GeomAPI_Pnt(0, 1, 1))
+
+assert(model.checkPythonDump())
--- /dev/null
+# Copyright (C) 2019-2020 CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10, 180)
+Sketch_1 = model.addSketch(Part_1_doc, model.selection("FACE", "Cylinder_1_1/Face_5"))
+SketchCircle_1 = Sketch_1.addCircle(-0.9379111501048892, 5.54816019935757, 2.957303770750356)
+model.do()
+ExtrusionCut_1 = model.addExtrusionCut(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2r")], model.selection(), [model.selection("SOLID", "Cylinder_1_1")])
+Rotation_1 = model.addRotation(Part_1_doc, [model.selection("SOLID", "ExtrusionCut_1_1")], model.selection("EDGE", "PartSet/OX"), 45)
+Edge_1 = model.addEdge(Part_1_doc, [model.selection("EDGE", "[Rotation_1_1/MF:Rotated&Cylinder_1_1/Face_1][Rotation_1_1/MF:Rotated&Sketch_1/SketchCircle_1_2]")], False)
+
+Sketch_2 = model.addSketch(Part_1_doc, model.standardPlane("XOY"))
+SketchProjection_1 = Sketch_2.addProjection(model.selection("EDGE", "Edge_1_1"), True)
+SketchBSpline_1 = SketchProjection_1.createdFeature()
+model.do()
+
+Sketch_3 = model.addSketch(Part_1_doc, model.standardPlane("XOZ"))
+SketchProjection_2 = Sketch_3.addProjection(model.selection("EDGE", "Edge_1_1"), True)
+SketchBSpline_2 = SketchProjection_2.createdFeature()
+model.do()
+
+Sketch_4 = model.addSketch(Part_1_doc, model.standardPlane("YOZ"))
+SketchProjection_3 = Sketch_4.addProjection(model.selection("EDGE", "Edge_1_1"), True)
+SketchBSpline_3 = SketchProjection_3.createdFeature()
+model.do()
+
+model.end()
+
+from GeomAPI import *
+import math
+
+TOLERANCE = 1.e-7
+
+def checkProjection(theBSpline3D, theBSpline2D, theFlags):
+ assert(theBSpline2D.isEdge() and theBSpline2D.edge().isBSpline())
+ poles2D = GeomAPI_BSpline(GeomAPI_Curve(theBSpline2D)).poles()
+ poles3D = theBSpline3D.poles()
+ assert(poles2D.size() == poles3D.size())
+ for p2d, p3d in zip(poles2D, poles3D):
+ assert(math.fabs((p2d.x() - p3d.x()) * theFlags.x()) < TOLERANCE and
+ math.fabs((p2d.y() - p3d.y()) * theFlags.y()) < TOLERANCE and
+ math.fabs((p2d.z() - p3d.z()) * theFlags.z()) < TOLERANCE)
+
+
+bspline0 = GeomAPI_BSpline(GeomAPI_Curve(Edge_1.results()[-1].resultSubShapePair()[0].shape()))
+
+bsplineShape1 = SketchBSpline_1.results()[-1].resultSubShapePair()[0].shape()
+checkProjection(bspline0, bsplineShape1, GeomAPI_Pnt(1, 1, 0))
+
+bsplineShape2 = SketchBSpline_2.results()[-1].resultSubShapePair()[0].shape()
+checkProjection(bspline0, bsplineShape2, GeomAPI_Pnt(1, 0, 1))
+
+bsplineShape3 = SketchBSpline_3.results()[-1].resultSubShapePair()[0].shape()
+checkProjection(bspline0, bsplineShape3, GeomAPI_Pnt(0, 1, 1))
+
+assert(model.checkPythonDump())
--- /dev/null
+# Copyright (C) 2019-2020 CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+"""
+ Test removing B-spline curve and its construstion elements
+"""
+
+from salome.shaper import model
+from ModelAPI import *
+
+def assertNbSubs(theSketch, theNbPoints, theNbLines, theNbSplines, theNbInternalConstraints):
+ model.testNbSubFeatures(theSketch, "SketchPoint", theNbPoints)
+ model.testNbSubFeatures(theSketch, "SketchLine", theNbLines)
+ model.testNbSubFeatures(theSketch, "SketchBSpline", theNbSplines)
+ model.testNbSubFeatures(theSketch, "SketchConstraintCoincidenceInternal", theNbInternalConstraints)
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchBSpline_1_poles = [(-30, -10), (-15, 20), (0, -10), (15, 20), (30, -10)]
+SketchBSpline_1 = Sketch_1.addSpline(poles = SketchBSpline_1_poles)
+controlPoles = SketchBSpline_1.controlPoles(auxiliary = [0, 1, 2, 3, 4])
+controlLines = SketchBSpline_1.controlPolygon(auxiliary = [0, 1, 2, 3])
+model.do()
+model.end()
+
+DEFAULT_DOF = len(SketchBSpline_1_poles) * 2
+DEFAULT_POINTS = len(SketchBSpline_1_poles)
+DEFAULT_LINES = len(SketchBSpline_1_poles) - 1
+DEFAULT_BSPLINES = 1
+DEAFULT_INTERNALS = len(controlPoles) + len(controlLines) * 2
+
+assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES, DEFAULT_BSPLINES, DEAFULT_INTERNALS)
+assert(model.dof(Sketch_1) == DEFAULT_DOF)
+
+# Test 1. Remove auxiliary points one by one.
+for pnt in controlPoles:
+ model.begin()
+ removeFeaturesAndReferences(FeatureSet([pnt.feature()]))
+ model.end()
+
+ assertNbSubs(Sketch_1, DEFAULT_POINTS - 1, DEFAULT_LINES, DEFAULT_BSPLINES, DEAFULT_INTERNALS - 1)
+ assert(model.dof(Sketch_1) == DEFAULT_DOF)
+ model.undo()
+ assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES, DEFAULT_BSPLINES, DEAFULT_INTERNALS)
+ assert(model.dof(Sketch_1) == DEFAULT_DOF)
+
+# Test 2. Remove auxiliary lines one by one.
+for ln in controlLines:
+ model.begin()
+ removeFeaturesAndReferences(FeatureSet([ln.feature()]))
+ model.end()
+
+ assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES - 1, DEFAULT_BSPLINES, DEAFULT_INTERNALS - 2)
+ assert(model.dof(Sketch_1) == DEFAULT_DOF)
+ model.undo()
+ assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES, DEFAULT_BSPLINES, DEAFULT_INTERNALS)
+ assert(model.dof(Sketch_1) == DEFAULT_DOF)
+
+# Test 3. Remove the B-spline curve.
+model.begin()
+removeFeaturesAndReferences(FeatureSet([SketchBSpline_1.feature()]))
+model.end()
+
+assertNbSubs(Sketch_1, 0, 0, 0, 0)
+assert(model.dof(Sketch_1) == 0)
+model.undo()
+assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES, DEFAULT_BSPLINES, DEAFULT_INTERNALS)
+assert(model.dof(Sketch_1) == DEFAULT_DOF)
+
+# Test 4. Remove some construction elements, make non-auxiliary a couple of the rest and check the dumping.
+model.begin()
+partSet = model.moduleDocument()
+Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchBSpline_2_poles = [(-30, -10), (-15, -40), (0, -10), (15, -40), (30, -10)]
+SketchBSpline_2 = Sketch_2.addSpline(poles = SketchBSpline_2_poles)
+controlPoles2 = SketchBSpline_2.controlPoles(auxiliary = [0, 1, 2, 3, 4])
+controlLines2 = SketchBSpline_2.controlPolygon(auxiliary = [0, 1, 2, 3])
+model.do()
+model.end()
+
+model.begin()
+controlPoles2[1].setAuxiliary(False)
+controlLines2[2].setAuxiliary(False)
+removeFeaturesAndReferences(FeatureSet([controlPoles2[2].feature(), controlLines2[0].feature()]))
+model.end()
+
+assertNbSubs(Sketch_2, DEFAULT_POINTS - 1, DEFAULT_LINES - 1, DEFAULT_BSPLINES, DEAFULT_INTERNALS - 3)
+
+assert(model.checkPythonDump())
--- /dev/null
+# Copyright (C) 2019-2020 CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+"""
+ Test removing peridoc B-spline curve and its construstion elements
+"""
+
+from salome.shaper import model
+from ModelAPI import *
+
+def assertNbSubs(theSketch, theNbPoints, theNbLines, theNbSplines, theNbInternalConstraints):
+ model.testNbSubFeatures(theSketch, "SketchPoint", theNbPoints)
+ model.testNbSubFeatures(theSketch, "SketchLine", theNbLines)
+ model.testNbSubFeatures(theSketch, "SketchBSplinePeriodic", theNbSplines)
+ model.testNbSubFeatures(theSketch, "SketchConstraintCoincidenceInternal", theNbInternalConstraints)
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchBSpline_1_poles = [(-30, -10), (-15, 20), (0, -10), (15, 20), (30, -10)]
+SketchBSpline_1 = Sketch_1.addSpline(poles = SketchBSpline_1_poles, periodic = True)
+controlPoles = SketchBSpline_1.controlPoles(auxiliary = [0, 1, 2, 3, 4])
+controlLines = SketchBSpline_1.controlPolygon(auxiliary = [0, 1, 2, 3, 4])
+model.do()
+model.end()
+
+DEFAULT_DOF = len(SketchBSpline_1_poles) * 2
+DEFAULT_POINTS = len(SketchBSpline_1_poles)
+DEFAULT_LINES = len(SketchBSpline_1_poles)
+DEFAULT_BSPLINES = 1
+DEAFULT_INTERNALS = len(controlPoles) + len(controlLines) * 2
+
+assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES, DEFAULT_BSPLINES, DEAFULT_INTERNALS)
+assert(model.dof(Sketch_1) == DEFAULT_DOF)
+
+# Test 1. Remove auxiliary points one by one.
+for pnt in controlPoles:
+ model.begin()
+ removeFeaturesAndReferences(FeatureSet([pnt.feature()]))
+ model.end()
+
+ assertNbSubs(Sketch_1, DEFAULT_POINTS - 1, DEFAULT_LINES, DEFAULT_BSPLINES, DEAFULT_INTERNALS - 1)
+ assert(model.dof(Sketch_1) == DEFAULT_DOF)
+ model.undo()
+ assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES, DEFAULT_BSPLINES, DEAFULT_INTERNALS)
+ assert(model.dof(Sketch_1) == DEFAULT_DOF)
+
+# Test 2. Remove auxiliary lines one by one.
+for ln in controlLines:
+ model.begin()
+ removeFeaturesAndReferences(FeatureSet([ln.feature()]))
+ model.end()
+
+ assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES - 1, DEFAULT_BSPLINES, DEAFULT_INTERNALS - 2)
+ assert(model.dof(Sketch_1) == DEFAULT_DOF)
+ model.undo()
+ assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES, DEFAULT_BSPLINES, DEAFULT_INTERNALS)
+ assert(model.dof(Sketch_1) == DEFAULT_DOF)
+
+# Test 3. Remove the B-spline curve.
+model.begin()
+removeFeaturesAndReferences(FeatureSet([SketchBSpline_1.feature()]))
+model.end()
+
+assertNbSubs(Sketch_1, 0, 0, 0, 0)
+assert(model.dof(Sketch_1) == 0)
+model.undo()
+assertNbSubs(Sketch_1, DEFAULT_POINTS, DEFAULT_LINES, DEFAULT_BSPLINES, DEAFULT_INTERNALS)
+assert(model.dof(Sketch_1) == DEFAULT_DOF)
+
+# Test 4. Remove some construction elements, make non-auxiliary a couple of the rest and check the dumping.
+model.begin()
+partSet = model.moduleDocument()
+Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchBSpline_2_poles = [(-30, -10), (-15, -40), (0, -10), (15, -40), (30, -10)]
+SketchBSpline_2 = Sketch_2.addSpline(poles = SketchBSpline_2_poles, periodic = True)
+controlPoles2 = SketchBSpline_2.controlPoles(auxiliary = [0, 1, 2, 3, 4])
+controlLines2 = SketchBSpline_2.controlPolygon(auxiliary = [0, 1, 2, 3, 4])
+model.do()
+model.end()
+
+model.begin()
+controlPoles2[1].setAuxiliary(False)
+controlLines2[2].setAuxiliary(False)
+removeFeaturesAndReferences(FeatureSet([controlPoles2[2].feature(), controlLines2[0].feature()]))
+model.end()
+
+assertNbSubs(Sketch_2, DEFAULT_POINTS - 1, DEFAULT_LINES - 1, DEFAULT_BSPLINES, DEAFULT_INTERNALS - 3)
+
+assert(model.checkPythonDump())
arcFeature.rst
ellipseFeature.rst
arcEllipseFeature.rst
+ bsplineFeature.rst
.. _sketch_constraints:
--- /dev/null
+
+ .. _tui_create_bspline:
+
+Create Sketch B-spline
+======================
+
+.. literalinclude:: examples/bspline.py
+ :linenos:
+ :language: python
+
+:download:`Download this script <examples/bspline.py>`
--- /dev/null
+.. |bspline.icon| image:: images/bspline.png
+.. |bspline_p.icon| image:: images/bspline_p.png
+.. |add_pole.icon| image:: images/bspline_add_pole.png
+
+B-spline and periodic B-spline
+==============================
+
+The feature creates a free form spline curve in the current Sketch.
+
+To add a new B-spline to the Sketch:
+
+#. select in the Main Menu *Sketch - > B-spline* item or
+#. click |bspline.icon| **B-spline** button in the Sketch toolbar.
+
+To add a periodic B-spline to the Sketch:
+
+#. select in the Main Menu *Sketch - > Periodic B-spline* item or
+#. click |bspline_p.icon| **Periodic B-spline** button in the Sketch toolbar.
+
+
+Creation of B-spline curve
+""""""""""""""""""""""""""
+
+.. image:: images/bspline_creation_panel.png
+ :align: center
+
+Click in the view to specify the control polygon of B-spline curve. The curve will be shown after the second point is initialized. To stop adding new poles, click **Esc** button or **Apply** the operation.
+
+
+**TUI Command**:
+
+.. py:function:: Sketch_1.addSpline(degree, poles, weights, knots, multiplicities, periodic)
+
+ :param integer: degree of B-spline.
+ :param array: list of poles [(x1, y1), (x2, y2), ...].
+ :param array: list of weights for corresponding poles.
+ :param array: parametric knots of B-spline curve.
+ :param array: multiplicity of each knot.
+ :param boolean: True mentions that the B-spline curve is periodic.
+ :return: Result object.
+
+Each parameter is optional.
+
+Result
+""""""
+
+Created B-spline curve appears in the view.
+
+.. image:: images/bspline_result.png
+ :align: center
+
+.. centered::
+ Non-periodic B-spline created
+
+
+.. image:: images/bspline_periodic_result.png
+ :align: center
+
+.. centered::
+ Periodic B-spline created
+
+**See Also** a sample TUI Script of :ref:`tui_create_bspline` operation.
+
+
+Modification of B-spline curve
+""""""""""""""""""""""""""""""
+
+.. image:: images/bspline_modification_panel.png
+ :align: center
+
+.. centered::
+ Modification panel for B-spline curve
+
+The following options are provided to modify the already created B-spline curve:
+
+#. Change weight of each pole.
+#. Add new pole.
+
+The new pole is added after the current by pressing on the corresponding |add_pole.icon| button. The default weight for the new pole is 1.
+
+**Note:** adding the new pole after the last for non-periodic B-spline will not change the last point of the curve to avoid modification of full sketch.
--- /dev/null
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+
+SketchBSpline_1_poles = [(-70, -5), (-50, 30), (-40, 3), (-20, 20), (-10, -5)]
+SketchBSpline_1 = Sketch_1.addSpline(poles = SketchBSpline_1_poles, weights = [1, 2, 2, 2, 1])
+[SketchPoint_1, SketchPoint_2, SketchPoint_3, SketchPoint_4, SketchPoint_5] = SketchBSpline_1.controlPoles(auxiliary = [0, 1, 2, 3, 4])
+[SketchLine_1, SketchLine_2, SketchLine_3, SketchLine_4] = SketchBSpline_1.controlPolygon(auxiliary = [0, 1, 2, 3])
+
+SketchBSplinePeriodic_1_poles = [(10, -5), (30, 30), (40, 3), (60, 20), (70, -5)]
+SketchBSplinePeriodic_1 = Sketch_1.addSpline(poles = SketchBSplinePeriodic_1_poles, weights = [3, 2, 1, 1, 1], periodic = True)
+[SketchPoint_6, SketchPoint_7, SketchPoint_8, SketchPoint_9, SketchPoint_10] = SketchBSplinePeriodic_1.controlPoles(auxiliary = [0, 1, 2, 3, 4])
+[SketchLine_5, SketchLine_6, SketchLine_7, SketchLine_8, SketchLine_9] = SketchBSplinePeriodic_1.controlPolygon(auxiliary = [0, 1, 2, 3, 4])
+
+model.do()
+model.end()
nested="SketchPoint SketchIntersectionPoint SketchLine
SketchCircle SketchMacroCircle SketchArc SketchMacroArc
SketchEllipse SketchMacroEllipse SketchEllipticArc SketchMacroEllipticArc
+ SketchBSpline SketchMacroBSpline SketchMacroBSplinePeriodic SketchBSplinePeriodic
SketchRectangle
SketchProjection
SketchConstraintLength SketchConstraintRadius SketchConstraintDistance SketchConstraintDistanceHorizontal SketchConstraintDistanceVertical
</feature>
</group>
+ <group id="Parametric curves">
+ <!-- SketchBSpline is a hidden feature. It is created inside SketchMacroBSpline. -->
+ <feature id="SketchBSpline"
+ title="B-spline"
+ tooltip="Create B-spline curve"
+ icon="icons/Sketch/bspline.png"
+ helpfile="bsplineFeature.html"
+ internal="1">
+ <bspline-panel id="poles"
+ weights="weights"
+ title="Poles and weights"
+ tooltip="B-spline poles and weights"
+ enable_value="enable_by_preferences">
+ <validator id="SketchPlugin_BSplineValidator"/>
+ </bspline-panel>
+ <boolvalue id="Auxiliary"
+ label="Auxiliary"
+ default="false"
+ tooltip="Construction element"
+ obligatory="0"
+ change_visual_attributes="true"/>
+ </feature>
+
+ <!-- SketchBSplinePeriodic is a hidden feature. It is created inside SketchMacroBSplinePeriodic. -->
+ <feature id="SketchBSplinePeriodic"
+ title="Periodic B-spline"
+ tooltip="Create periodic B-spline curve"
+ icon="icons/Sketch/bspline_p.png"
+ helpfile="bsplineFeature.html"
+ internal="1">
+ <bspline-panel id="poles"
+ weights="weights"
+ title="Poles and weights"
+ tooltip="B-spline poles and weights"
+ enable_value="enable_by_preferences">
+ <validator id="SketchPlugin_BSplineValidator"/>
+ </bspline-panel>
+ <boolvalue id="Auxiliary"
+ label="Auxiliary"
+ default="false"
+ tooltip="Construction element"
+ obligatory="0"
+ change_visual_attributes="true"/>
+ </feature>
+
+ <!-- SketchMacroBSpline -->
+ <feature id="SketchMacroBSpline"
+ title="B-spline"
+ tooltip="Create B-spline curve"
+ icon="icons/Sketch/bspline.png"
+ helpfile="bsplineFeature.html">
+ <sketch-bspline_selector id="poles"
+ weights="weights"
+ reference_attribute="poles_ref"
+ title="Poles and weights"
+ tooltip="B-spline poles and weights"
+ enable_value="enable_by_preferences">
+ <validator id="SketchPlugin_BSplineValidator"/>
+ </sketch-bspline_selector>
+ <boolvalue id="need_control_poly"
+ label="Create control polygon"
+ default="true"
+ tooltip="Specify if the control polygon should be created"/>
+ <boolvalue id="Auxiliary"
+ label="Auxiliary"
+ default="false"
+ tooltip="Construction element"
+ obligatory="0"
+ change_visual_attributes="true"/>
+ </feature>
+
+ <!-- SketchMacroBSplinePeriodic -->
+ <feature id="SketchMacroBSplinePeriodic"
+ title="Periodic B-spline"
+ tooltip="Create periodic B-spline curve"
+ icon="icons/Sketch/bspline_p.png"
+ helpfile="bsplineFeature.html">
+ <sketch-bspline_selector id="poles"
+ weights="weights"
+ reference_attribute="poles_ref"
+ title="Poles and weights"
+ tooltip="B-spline poles and weights"
+ enable_value="enable_by_preferences">
+ <validator id="SketchPlugin_BSplineValidator"/>
+ </sketch-bspline_selector>
+ <boolvalue id="need_control_poly"
+ label="Create control polygon"
+ default="true"
+ tooltip="Specify if the control polygon should be created"/>
+ <boolvalue id="Auxiliary"
+ label="Auxiliary"
+ default="false"
+ tooltip="Construction element"
+ obligatory="0"
+ change_visual_attributes="true"/>
+ </feature>
+ </group>
+
<group id="Segmentation">
<!-- SketchSplit -->
<feature id="SketchSplit" title="Split"
PlaneGCSSolver_EdgeWrapper.h
PlaneGCSSolver_EntityWrapper.h
PlaneGCSSolver_PointWrapper.h
+ PlaneGCSSolver_PointArrayWrapper.h
PlaneGCSSolver_ScalarWrapper.h
+ PlaneGCSSolver_ScalarArrayWrapper.h
PlaneGCSSolver_AngleWrapper.h
PlaneGCSSolver_BooleanWrapper.h
PlaneGCSSolver_Tools.h
+ PlaneGCSSolver_GeoExtensions.h
)
SET(PLANEGCSSOLVER_SOURCES
PlaneGCSSolver_ConstraintWrapper.cpp
PlaneGCSSolver_EdgeWrapper.cpp
PlaneGCSSolver_PointWrapper.cpp
+ PlaneGCSSolver_PointArrayWrapper.cpp
PlaneGCSSolver_ScalarWrapper.cpp
+ PlaneGCSSolver_ScalarArrayWrapper.cpp
PlaneGCSSolver_AngleWrapper.cpp
PlaneGCSSolver_BooleanWrapper.cpp
PlaneGCSSolver_Tools.cpp
+ PlaneGCSSolver_GeoExtensions.cpp
)
SET(PLANEGCSSOLVER_BUILDER_HEADERS
#include <PlaneGCSSolver_AngleWrapper.h>
#include <PlaneGCSSolver_AttributeBuilder.h>
+#include <PlaneGCSSolver_PointArrayWrapper.h>
#include <PlaneGCSSolver_PointWrapper.h>
#include <PlaneGCSSolver_ScalarWrapper.h>
+#include <PlaneGCSSolver_ScalarArrayWrapper.h>
#include <PlaneGCSSolver_BooleanWrapper.h>
+#include <PlaneGCSSolver_Tools.h>
+#include <GeomAPI_Pnt2d.h>
#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeDoubleArray.h>
+#include <ModelAPI_AttributeInteger.h>
+#include <SketchPlugin_BSpline.h>
+#include <SketchPlugin_BSplinePeriodic.h>
#include <SketchPlugin_ConstraintAngle.h>
#include <SketchPlugin_MultiRotation.h>
static EntityWrapperPtr createScalar(const AttributePtr& theAttribute,
PlaneGCSSolver_Storage* theStorage)
{
- AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
- if (!aScalar)
- return EntityWrapperPtr();
+ double aValue = 0.0;
+ AttributeDoublePtr aDouble = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
+ if (aDouble)
+ aValue = aDouble->isInitialized() ? aDouble->value() : 0.0;
+ else {
+ AttributeIntegerPtr anInt = std::dynamic_pointer_cast<ModelAPI_AttributeInteger>(theAttribute);
+ if (anInt)
+ aValue = anInt->isInitialized() ? anInt->value() : 0.0;
+ else
+ return EntityWrapperPtr();
+ }
ScalarWrapperPtr aWrapper;
// following attributes should be converted from degrees to radians
(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() ||
+ anOwner->getKind() == SketchPlugin_BSplinePeriodic::ID()) &&
+ theAttribute->id() == SketchPlugin_BSplineBase::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;
}
+template <typename TYPE>
+static bool nonSolverAttribute(const FeaturePtr theOwner, const std::string& theAttrId)
+{
+ return theOwner->getKind() == TYPE::ID() && (theAttrId == TYPE::WEIGHTS_ID()
+ || theAttrId == TYPE::KNOTS_ID() || theAttrId == TYPE::MULTS_ID());
+}
+
+static EntityWrapperPtr createScalarArray(const AttributePtr& theAttribute,
+ PlaneGCSSolver_Storage* theStorage)
+{
+ PlaneGCSSolver_Tools::AttributeArray anArray(theAttribute);
+
+ if (!anArray.isInitialized())
+ return EntityWrapperPtr();
+
+ PlaneGCSSolver_Storage* aStorage = theStorage;
+ // Weights, knots and multiplicities of B-spline curve are not processed by the solver
+ FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
+ if (nonSolverAttribute<SketchPlugin_BSpline>(anOwner, theAttribute->id()) ||
+ nonSolverAttribute<SketchPlugin_BSplinePeriodic>(anOwner, theAttribute->id()))
+ aStorage = 0;
+
+ 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);
+ aParameters.push_back(aParam);
+ }
+
+ return EntityWrapperPtr(new PlaneGCSSolver_ScalarArrayWrapper(aParameters));
+}
+
+static PointWrapperPtr createPoint(const GeomPnt2dPtr& thePoint, PlaneGCSSolver_Storage* theStorage)
+{
+ GCSPointPtr aNewPoint(new GCS::Point);
+
+ aNewPoint->x = createParameter(theStorage);
+ aNewPoint->y = createParameter(theStorage);
+ if (thePoint) {
+ *(aNewPoint->x) = thePoint->x();
+ *(aNewPoint->y) = thePoint->y();
+ }
+
+ return PointWrapperPtr(new PlaneGCSSolver_PointWrapper(aNewPoint));
+}
+
static EntityWrapperPtr createPoint(const AttributePtr& theAttribute,
PlaneGCSSolver_Storage* theStorage)
{
if (!aPoint2D)
return EntityWrapperPtr();
- GCSPointPtr aNewPoint(new GCS::Point);
+ GeomPnt2dPtr aPnt;
+ if (aPoint2D->isInitialized())
+ aPnt = aPoint2D->pnt();
- aNewPoint->x = createParameter(theStorage);
- aNewPoint->y = createParameter(theStorage);
- if (aPoint2D->isInitialized()) {
- *(aNewPoint->x) = aPoint2D->x();
- *(aNewPoint->y) = aPoint2D->y();
- }
+ return createPoint(aPnt, theStorage);
+}
+
+static EntityWrapperPtr createPointArray(const AttributePtr& theAttribute,
+ PlaneGCSSolver_Storage* theStorage)
+{
+ std::shared_ptr<GeomDataAPI_Point2DArray> aPointArray =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(theAttribute);
+ if (!aPointArray)
+ return EntityWrapperPtr();
+
+ int aSize = aPointArray->size();
- return EntityWrapperPtr(new PlaneGCSSolver_PointWrapper(aNewPoint));
+ std::vector<PointWrapperPtr> aPointWrappers;
+ aPointWrappers.reserve(aSize);
+ for (int index = 0; index < aSize; ++index)
+ aPointWrappers.push_back(createPoint(aPointArray->pnt(index), theStorage));
+
+ return EntityWrapperPtr(new PlaneGCSSolver_PointArrayWrapper(aPointWrappers));
}
EntityWrapperPtr PlaneGCSSolver_AttributeBuilder::createAttribute(
aResult = createScalar(theAttribute, myStorage);
if (!aResult)
aResult = createBoolean(theAttribute);
+ if (!aResult)
+ aResult = createPointArray(theAttribute, myStorage);
+ if (!aResult)
+ aResult = createScalarArray(theAttribute, myStorage);
if (aResult && !myStorage)
aResult->setExternal(true);
return aResult;
}
+
+bool PlaneGCSSolver_AttributeBuilder::updateAttribute(
+ AttributePtr theAttribute,
+ EntityWrapperPtr theEntity)
+{
+ bool isUpdated = false;
+ GCS::SET_pD aParamsToRemove;
+ // rebuild array if its size is changed
+ if (theEntity->type() == ENTITY_POINT_ARRAY) {
+ std::shared_ptr<PlaneGCSSolver_PointArrayWrapper> aWrapper =
+ std::dynamic_pointer_cast<PlaneGCSSolver_PointArrayWrapper>(theEntity);
+ std::shared_ptr<GeomDataAPI_Point2DArray> anAttribute =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(theAttribute);
+
+ if (aWrapper->size() != anAttribute->size()) {
+ std::vector<PointWrapperPtr> aPointsArray = aWrapper->array();
+ std::vector<PointWrapperPtr>::iterator aPos = aPointsArray.begin();
+ while (anAttribute->size() > (int)aPointsArray.size()) {
+ // add points to the middle of array
+ GeomPnt2dPtr aValue;
+ for (; aPos != aPointsArray.end(); ++aPos) {
+ aValue = anAttribute->pnt(aPos - aPointsArray.begin());
+ if (aValue->distance(PlaneGCSSolver_Tools::point(*aPos)) > tolerance)
+ break;
+ }
+ int aShift = aPos - aPointsArray.begin();
+ aPointsArray.insert(aPos, createPoint(aValue, myStorage));
+ aPos = aPointsArray.begin() + aShift;
+ }
+
+ while (anAttribute->size() < (int)aPointsArray.size()) {
+ // remove middle points
+ std::vector<PointWrapperPtr>::iterator anIt = --aPointsArray.end();
+ GCS::SET_pD aParams = PlaneGCSSolver_Tools::parameters(*anIt);
+ aParamsToRemove.insert(aParams.begin(), aParams.end());
+ aPointsArray.erase(anIt);
+ }
+
+ aWrapper->setArray(aPointsArray);
+ }
+ }
+ else if (theEntity->type() == ENTITY_SCALAR_ARRAY) {
+ std::shared_ptr<PlaneGCSSolver_ScalarArrayWrapper> aWrapper =
+ std::dynamic_pointer_cast<PlaneGCSSolver_ScalarArrayWrapper>(theEntity);
+ if (aWrapper->size() != PlaneGCSSolver_Tools::AttributeArray(theAttribute).size()) {
+ aParamsToRemove = PlaneGCSSolver_Tools::parameters(aWrapper);
+ std::shared_ptr<PlaneGCSSolver_ScalarArrayWrapper> aNewArray =
+ std::dynamic_pointer_cast<PlaneGCSSolver_ScalarArrayWrapper>(
+ createScalarArray(theAttribute, myStorage));
+ aWrapper->setArray(aNewArray->array());
+ isUpdated = true;
+ }
+ }
+
+ if (!aParamsToRemove.empty()) {
+ if (myStorage)
+ myStorage->removeParameters(aParamsToRemove);
+ else {
+ std::for_each(aParamsToRemove.begin(), aParamsToRemove.end(),
+ [](double* theParam) { delete theParam; });
+ }
+ }
+
+ return isUpdated || theEntity->update(theAttribute);
+}
/// \return Created wrapper of the attribute applicable for specific solver
virtual EntityWrapperPtr createAttribute(AttributePtr theAttribute);
+ /// \brief Update entity by the attribute values.
+ /// \return \c true if any value is updated.
+ virtual bool updateAttribute(AttributePtr theAttribute, EntityWrapperPtr theEntity);
+
/// \brief Blank. To be defined in derived class.
virtual EntityWrapperPtr createFeature(FeaturePtr)
{ return EntityWrapperPtr(); }
#include <PlaneGCSSolver_BooleanWrapper.h>
+#include <ModelAPI_AttributeBoolean.h>
+
PlaneGCSSolver_BooleanWrapper::PlaneGCSSolver_BooleanWrapper(bool theParam)
: myValue(theParam)
{
}
+
+bool PlaneGCSSolver_BooleanWrapper::update(AttributePtr theAttribute)
+{
+ bool isUpdated = false;
+ AttributeBooleanPtr aBoolean =
+ std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(theAttribute);
+ if (aBoolean) {
+ isUpdated = value() != aBoolean->value();
+ setValue(aBoolean->value());
+ }
+ return isUpdated;
+}
virtual SketchSolver_EntityType type() const
{ return ENTITY_BOOLEAN; }
+protected:
+ /// \brief Update entity by the values of theAttribute
+ /// \return \c true if any value of attribute is not equal to the stored in the entity
+ virtual bool update(std::shared_ptr<ModelAPI_Attribute> theAttribute);
+
protected:
bool myValue;
};
#include <PlaneGCSSolver_Defs.h>
#include <PlaneGCSSolver_ScalarWrapper.h>
+#include <list>
+
/**
* Wrapper providing operations with PlaneGCS constraints.
*/
ENTITY_UNKNOWN = 0,
ENTITY_BOOLEAN,
ENTITY_SCALAR,
+ ENTITY_SCALAR_ARRAY,
ENTITY_ANGLE,
ENTITY_POINT,
+ ENTITY_POINT_ARRAY,
ENTITY_LINE,
ENTITY_CIRCLE,
ENTITY_ARC,
ENTITY_ELLIPSE,
- ENTITY_ELLIPTIC_ARC
+ ENTITY_ELLIPTIC_ARC,
+ ENTITY_BSPLINE
};
/// Types of constraints
#include <PlaneGCSSolver_EdgeWrapper.h>
#include <cmath>
-static bool isLine(const GCSCurvePtr& theEntity)
+template <typename TYPE>
+static bool isCurve(const GCSCurvePtr& theEntity)
{
- return std::dynamic_pointer_cast<GCS::Line>(theEntity).get();
-}
-
-static bool isCircle(const GCSCurvePtr& theEntity)
-{
- return std::dynamic_pointer_cast<GCS::Circle>(theEntity).get();
-}
-
-static bool isArc(const GCSCurvePtr& theEntity)
-{
- return std::dynamic_pointer_cast<GCS::Arc>(theEntity).get();
-}
-
-static bool isEllipse(const GCSCurvePtr& theEntity)
-{
- return std::dynamic_pointer_cast<GCS::Ellipse>(theEntity).get();
-}
-
-static bool isEllipticArc(const GCSCurvePtr& theEntity)
-{
- return std::dynamic_pointer_cast<GCS::ArcOfEllipse>(theEntity).get();
+ return std::dynamic_pointer_cast<TYPE>(theEntity).get();
}
PlaneGCSSolver_EdgeWrapper::PlaneGCSSolver_EdgeWrapper(const GCSCurvePtr theEntity)
: myEntity(theEntity)
{
- if (isLine(myEntity))
+ if (isCurve<GCS::Line>(myEntity))
myType = ENTITY_LINE;
- else if (isArc(myEntity))
+ else if (isCurve<GCS::Arc>(myEntity))
myType = ENTITY_ARC;
- else if (isCircle(myEntity))
+ else if (isCurve<GCS::Circle>(myEntity))
myType = ENTITY_CIRCLE;
- else if (isEllipticArc(myEntity))
+ else if (isCurve<GCS::ArcOfEllipse>(myEntity))
myType = ENTITY_ELLIPTIC_ARC;
- else if (isEllipse(myEntity))
+ else if (isCurve<GCS::Ellipse>(myEntity))
myType = ENTITY_ELLIPSE;
+ else if (isCurve<GCS::BSpline>(myEntity))
+ myType = ENTITY_BSPLINE;
}
static double squareDistance(const GCS::Point& theP1, const GCS::Point& theP2)
#include <PlaneGCSSolver_Defs.h>
-#include <ModelAPI_Attribute.h>
-#include <ModelAPI_Feature.h>
-
-#include <list>
+#include <map>
#include <memory>
+class ModelAPI_Attribute;
+
class PlaneGCSSolver_EntityWrapper;
typedef std::shared_ptr<PlaneGCSSolver_EntityWrapper> EntityWrapperPtr;
const std::map<std::string, EntityWrapperPtr>& additionalAttributes() const
{ return myAdditionalAttributes; }
+protected:
+ /// \brief Update entity by the values of theAttribute
+ /// \return \c true if any value of attribute is not equal to the stored in the entity
+ virtual bool update(std::shared_ptr<ModelAPI_Attribute> theAttribute)
+ { return false; }
+
+ friend class PlaneGCSSolver_AttributeBuilder;
+
private:
bool myExternal;
std::map<std::string, EntityWrapperPtr> myAdditionalAttributes;
//
#include <PlaneGCSSolver_FeatureBuilder.h>
+#include <PlaneGCSSolver_BooleanWrapper.h>
#include <PlaneGCSSolver_EdgeWrapper.h>
+#include <PlaneGCSSolver_GeoExtensions.h>
#include <PlaneGCSSolver_PointWrapper.h>
+#include <PlaneGCSSolver_PointArrayWrapper.h>
#include <PlaneGCSSolver_ScalarWrapper.h>
-#include <PlaneGCSSolver_BooleanWrapper.h>
+#include <PlaneGCSSolver_ScalarArrayWrapper.h>
#include <PlaneGCSSolver_Tools.h>
#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_BSpline.h>
+#include <SketchPlugin_BSplinePeriodic.h>
#include <SketchPlugin_Circle.h>
#include <SketchPlugin_Ellipse.h>
#include <SketchPlugin_EllipticArc.h>
#include <GeomAPI_Pnt2d.h>
#include <GeomAPI_XY.h>
-static bool isAttributeApplicable(const std::string& theAttrName,
- const std::string& theOwnerName);
static EntityWrapperPtr createLine(const AttributeEntityMap& theAttributes);
static EntityWrapperPtr createCircle(const AttributeEntityMap& theAttributes);
static EntityWrapperPtr createEllipse(const AttributeEntityMap& theAttributes);
static EntityWrapperPtr createEllipticArc(const AttributeEntityMap& theAttributes,
PlaneGCSSolver_Storage* theStorage);
+template <typename TYPE>
+static EntityWrapperPtr createBSpline(const AttributeEntityMap& theAttributes);
PlaneGCSSolver_FeatureBuilder::PlaneGCSSolver_FeatureBuilder(
{
FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
EntityWrapperPtr anAttr;
- if (isAttributeApplicable(theAttribute->id(), anOwner->getKind()))
+ if (PlaneGCSSolver_Tools::isAttributeApplicable(theAttribute->id(), anOwner->getKind()))
anAttr = PlaneGCSSolver_AttributeBuilder::createAttribute(theAttribute);
if (anAttr)
myAttributes[theAttribute] = anAttr;
// Arc of ellipse
else if (aFeatureKind == SketchPlugin_EllipticArc::ID())
aResult = createEllipticArc(myAttributes, myStorage);
+ // B-spline curve
+ else if (aFeatureKind == SketchPlugin_BSpline::ID())
+ aResult = createBSpline<SketchPlugin_BSpline>(myAttributes);
+ else if (aFeatureKind == SketchPlugin_BSplinePeriodic::ID())
+ aResult = createBSpline<SketchPlugin_BSplinePeriodic>(myAttributes);
// Point (it has low probability to be an attribute of constraint, so it is checked at the end)
else if (aFeatureKind == SketchPlugin_Point::ID() ||
aFeatureKind == SketchPlugin_IntersectionPoint::ID()) {
return anEllipseWrapper;
}
-bool isAttributeApplicable(const std::string& theAttrName, const std::string& theOwnerName)
+template <typename TYPE>
+EntityWrapperPtr createBSpline(const AttributeEntityMap& theAttributes)
{
- if (theOwnerName == SketchPlugin_Arc::ID()) {
- return theAttrName == SketchPlugin_Arc::CENTER_ID() ||
- theAttrName == SketchPlugin_Arc::START_ID() ||
- theAttrName == SketchPlugin_Arc::END_ID() ||
- theAttrName == SketchPlugin_Arc::REVERSED_ID();
- }
- else if (theOwnerName == SketchPlugin_Circle::ID()) {
- return theAttrName == SketchPlugin_Circle::CENTER_ID() ||
- theAttrName == SketchPlugin_Circle::RADIUS_ID();
- }
- else if (theOwnerName == SketchPlugin_Line::ID()) {
- return theAttrName == SketchPlugin_Line::START_ID() ||
- theAttrName == SketchPlugin_Line::END_ID();
- }
- else if (theOwnerName == SketchPlugin_Ellipse::ID()) {
- return theAttrName == SketchPlugin_Ellipse::CENTER_ID() ||
- theAttrName == SketchPlugin_Ellipse::FIRST_FOCUS_ID() ||
- theAttrName == SketchPlugin_Ellipse::SECOND_FOCUS_ID() ||
- theAttrName == SketchPlugin_Ellipse::MAJOR_AXIS_START_ID() ||
- theAttrName == SketchPlugin_Ellipse::MAJOR_AXIS_END_ID() ||
- theAttrName == SketchPlugin_Ellipse::MINOR_AXIS_START_ID() ||
- theAttrName == SketchPlugin_Ellipse::MINOR_AXIS_END_ID() ||
- theAttrName == SketchPlugin_Ellipse::MAJOR_RADIUS_ID() ||
- theAttrName == SketchPlugin_Ellipse::MINOR_RADIUS_ID();
- }
- else if (theOwnerName == SketchPlugin_EllipticArc::ID()) {
- return theAttrName == SketchPlugin_EllipticArc::CENTER_ID() ||
- theAttrName == SketchPlugin_EllipticArc::FIRST_FOCUS_ID() ||
- theAttrName == SketchPlugin_EllipticArc::SECOND_FOCUS_ID() ||
- theAttrName == SketchPlugin_EllipticArc::MAJOR_AXIS_START_ID() ||
- theAttrName == SketchPlugin_EllipticArc::MAJOR_AXIS_END_ID() ||
- theAttrName == SketchPlugin_EllipticArc::MINOR_AXIS_START_ID() ||
- theAttrName == SketchPlugin_EllipticArc::MINOR_AXIS_END_ID() ||
- theAttrName == SketchPlugin_EllipticArc::MAJOR_RADIUS_ID() ||
- theAttrName == SketchPlugin_EllipticArc::MINOR_RADIUS_ID() ||
- theAttrName == SketchPlugin_EllipticArc::START_POINT_ID() ||
- theAttrName == SketchPlugin_EllipticArc::END_POINT_ID() ||
- theAttrName == SketchPlugin_EllipticArc::REVERSED_ID();
+ std::shared_ptr<GCS::BSplineImpl> aNewSpline(new GCS::BSplineImpl);
+
+ aNewSpline->degree = 3;
+ aNewSpline->periodic = std::is_same<TYPE, SketchPlugin_BSplinePeriodic>();
+
+ std::map<std::string, EntityWrapperPtr> anAdditionalAttributes;
+
+ AttributeEntityMap::const_iterator anIt = theAttributes.begin();
+ for (; anIt != theAttributes.end(); ++anIt) {
+ const std::string& anAttrID = anIt->first->id();
+ if (anAttrID == TYPE::POLES_ID()) {
+ PointArrayWrapperPtr anArray =
+ std::dynamic_pointer_cast<PlaneGCSSolver_PointArrayWrapper>(anIt->second);
+
+ int aSize = anArray->size();
+ aNewSpline->poles.reserve(aSize);
+ for (int anIndex = 0; anIndex < aSize; ++anIndex)
+ aNewSpline->poles.push_back(*anArray->value(anIndex)->point());
+
+ aNewSpline->start = aNewSpline->poles.front();
+ aNewSpline->end = aNewSpline->poles.back();
+ }
+ else if (anAttrID == TYPE::DEGREE_ID()) {
+ ScalarWrapperPtr aScalar =
+ std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(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<PlaneGCSSolver_ScalarArrayWrapper>(anIt->second);
+ if (anAttrID == TYPE::WEIGHTS_ID())
+ aNewSpline->weights = anArray->array();
+ else if (anAttrID == TYPE::KNOTS_ID())
+ aNewSpline->knots = anArray->array();
+ else if (anAttrID == TYPE::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));
+ }
+ }
}
- // suppose that all remaining features are points
- return theAttrName == SketchPlugin_Point::COORD_ID();
+ EdgeWrapperPtr aWrapper(new PlaneGCSSolver_EdgeWrapper(aNewSpline));
+ aWrapper->setAdditionalAttributes(anAdditionalAttributes);
+ return aWrapper;
}
--- /dev/null
+// 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 <PlaneGCSSolver_GeoExtensions.h>
+#include <PlaneGCSSolver_Tools.h>
+
+#include <GeomAPI_BSpline2d.h>
+#include <GeomAPI_Pnt2d.h>
+#include <GeomAPI_XY.h>
+
+#include <cmath>
+
+namespace GCS
+{
+
+DeriVector2 BSplineImpl::Value(double u, double du, double* derivparam)
+{
+ if (!isCacheValid())
+ rebuildCache();
+
+ std::shared_ptr<GeomAPI_Pnt2d> aValue;
+ std::shared_ptr<GeomAPI_XY> aDeriv;
+ myCurve->D1(u, aValue, aDeriv);
+
+ return DeriVector2(aValue->x(), aValue->y(), aDeriv->x() * du, aDeriv->y() * du);
+}
+
+DeriVector2 BSplineImpl::CalculateNormal(Point &p, double* derivparam)
+{
+ if (!isCacheValid())
+ rebuildCache();
+
+ double u = 0.0;
+ if (!myCurve->parameter(GeomPnt2dPtr(new GeomAPI_Pnt2d(*p.x, *p.y)), 1e100, u)) {
+ // Sometimes OCCT's Extrema algorithm cannot find the parameter on B-spline curve
+ // (usually, if the point is near the curve extremity).
+ // Workaround: compute distance to each boundary point
+ double aDistPS = PlaneGCSSolver_Tools::distance(p, poles.front());
+ double aDistPE = PlaneGCSSolver_Tools::distance(p, poles.back());
+ static const double THE_TOLERANCE = 1.e-6;
+ if (aDistPS < aDistPE && aDistPS < THE_TOLERANCE)
+ u = *knots.front();
+ else if (aDistPE < aDistPS && aDistPE < THE_TOLERANCE)
+ u = *knots.back();
+ else
+ return DeriVector2();
+ }
+
+ std::shared_ptr<GeomAPI_Pnt2d> aValue;
+ std::shared_ptr<GeomAPI_XY> aDeriv;
+ myCurve->D1(u, aValue, aDeriv);
+
+ DeriVector2 norm(aDeriv->x(), aDeriv->y(), 0.0, 0.0);
+ return norm.rotate90ccw();
+}
+
+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<GeomPnt2dPtr>::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<double>::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();
+ 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(degree, myCachedPoles, myCachedWeights,
+ myCachedKnots, myCachedMultiplicities, periodic));
+}
+
+} // namespace GCS
--- /dev/null
+// 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 <PlaneGCSSolver_Defs.h>
+
+#include <list>
+#include <memory>
+
+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 DeriVector2 CalculateNormal(Point &p, 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<GeomAPI_BSpline2d> myCurve; /// cached B-spline curve
+ std::list<std::shared_ptr<GeomAPI_Pnt2d> > myCachedPoles; /// cached B-spline poles
+ std::list<double> myCachedWeights; /// cached B-spline weights
+ std::list<double> myCachedKnots; /// cached B-spline knots
+ std::list<int> myCachedMultiplicities; /// cached B-spline multiplicities
+ };
+}
+
+#endif
--- /dev/null
+// 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 <PlaneGCSSolver_PointArrayWrapper.h>
+#include <PlaneGCSSolver_Tools.h>
+
+#include <GeomDataAPI_Point2DArray.h>
+
+#include <GeomAPI_Pnt2d.h>
+
+PlaneGCSSolver_PointArrayWrapper::PlaneGCSSolver_PointArrayWrapper(
+ const std::vector<PointWrapperPtr>& thePoints)
+ : myPoints(thePoints)
+{
+}
+
+bool PlaneGCSSolver_PointArrayWrapper::update(AttributePtr theAttribute)
+{
+ bool isUpdated = false;
+ std::shared_ptr<GeomDataAPI_Point2DArray> aPointArray =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(theAttribute);
+ if (aPointArray && aPointArray->size() == (int)myPoints.size()) {
+ std::vector<PointWrapperPtr>::iterator aPIt = myPoints.begin();
+ for (int anIndex = 0; aPIt != myPoints.end(); ++aPIt, ++anIndex) {
+ GeomPnt2dPtr aPnt = aPointArray->pnt(anIndex);
+
+ const GCSPointPtr& aGCSPoint = (*aPIt)->point();
+ isUpdated = PlaneGCSSolver_Tools::updateValue(aPnt->x(), *(aGCSPoint->x)) || isUpdated;
+ isUpdated = PlaneGCSSolver_Tools::updateValue(aPnt->y(), *(aGCSPoint->y)) || isUpdated;
+ }
+ }
+ return isUpdated;
+}
--- /dev/null
+// 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_PointArrayWrapper_H_
+#define PlaneGCSSolver_PointArrayWrapper_H_
+
+#include <PlaneGCSSolver_Defs.h>
+#include <PlaneGCSSolver_PointWrapper.h>
+
+/**
+ * Wrapper providing operations with arrays of PlaneGCS points.
+ */
+class PlaneGCSSolver_PointArrayWrapper : public PlaneGCSSolver_EntityWrapper
+{
+public:
+ PlaneGCSSolver_PointArrayWrapper(const std::vector<PointWrapperPtr>& thePoints);
+
+ /// \brief Return wrapper of PlaneGCS point
+ const PointWrapperPtr& value(const int theIndex) const
+ { return myPoints[theIndex]; }
+
+ /// \breif Size of array
+ int size() const { return (int)myPoints.size(); }
+
+ /// \brief Return array of points
+ const std::vector<PointWrapperPtr>& array() const { return myPoints; }
+ /// \breif Set points
+ void setArray(const std::vector<PointWrapperPtr>& thePoints) { myPoints = thePoints; }
+
+ /// \brief Return type of current entity
+ virtual SketchSolver_EntityType type() const
+ { return ENTITY_POINT_ARRAY; }
+
+protected:
+ /// \brief Update entity by the values of theAttribute
+ /// \return \c true if any value of attribute is not equal to the stored in the entity
+ virtual bool update(std::shared_ptr<ModelAPI_Attribute> theAttribute);
+
+private:
+ std::vector<PointWrapperPtr> myPoints;
+};
+
+typedef std::shared_ptr<PlaneGCSSolver_PointArrayWrapper> PointArrayWrapperPtr;
+
+#endif
//
#include <PlaneGCSSolver_PointWrapper.h>
+#include <PlaneGCSSolver_Tools.h>
+
+#include <GeomDataAPI_Point2D.h>
PlaneGCSSolver_PointWrapper::PlaneGCSSolver_PointWrapper(const GCSPointPtr thePoint)
: myPoint(thePoint)
{
}
+
+bool PlaneGCSSolver_PointWrapper::update(AttributePtr theAttribute)
+{
+ bool isUpdated = false;
+ std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
+ if (aPoint2D) {
+ isUpdated = PlaneGCSSolver_Tools::updateValue(aPoint2D->x(), *(myPoint->x)) || isUpdated;
+ isUpdated = PlaneGCSSolver_Tools::updateValue(aPoint2D->y(), *(myPoint->y)) || isUpdated;
+ }
+ return isUpdated;
+}
virtual SketchSolver_EntityType type() const
{ return ENTITY_POINT; }
+protected:
+ /// \brief Update entity by the values of theAttribute
+ /// \return \c true if any value of attribute is not equal to the stored in the entity
+ virtual bool update(std::shared_ptr<ModelAPI_Attribute> theAttribute);
+
private:
GCSPointPtr myPoint;
};
--- /dev/null
+// 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 <PlaneGCSSolver_ScalarArrayWrapper.h>
+#include <PlaneGCSSolver_Tools.h>
+
+PlaneGCSSolver_ScalarArrayWrapper::PlaneGCSSolver_ScalarArrayWrapper(const GCS::VEC_pD& theParam)
+ : myValue(theParam)
+{
+}
+
+bool PlaneGCSSolver_ScalarArrayWrapper::update(AttributePtr theAttribute)
+{
+ bool isUpdated = false;
+ PlaneGCSSolver_Tools::AttributeArray anArray(theAttribute);
+ if (anArray.isInitialized() && anArray.size() == (int)myValue.size()) {
+ for (int anIndex = 0; anIndex < anArray.size(); ++anIndex) {
+ isUpdated = PlaneGCSSolver_Tools::updateValue(anArray.value(anIndex), *(myValue[anIndex]))
+ || isUpdated;
+ }
+ }
+ return isUpdated;
+}
--- /dev/null
+// 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_ScalarArrayWrapper_H_
+#define PlaneGCSSolver_ScalarArrayWrapper_H_
+
+#include <PlaneGCSSolver_Defs.h>
+#include <PlaneGCSSolver_EntityWrapper.h>
+
+/**
+ * Wrapper providing operations with array of PlaneGCS scalars.
+ */
+class PlaneGCSSolver_ScalarArrayWrapper : public PlaneGCSSolver_EntityWrapper
+{
+public:
+ PlaneGCSSolver_ScalarArrayWrapper(const GCS::VEC_pD& theParam);
+
+ /// \breif Size of array
+ int size() const { return (int)myValue.size(); }
+
+ /// \brief Return array of PlaneGCS parameters
+ const GCS::VEC_pD& array() const { return myValue; }
+ /// \breif Set array of parameters
+ void setArray(const GCS::VEC_pD& theParams) { myValue = theParams; }
+
+ /// \brief Return type of current entity
+ virtual SketchSolver_EntityType type() const
+ { return ENTITY_SCALAR_ARRAY; }
+
+protected:
+ /// \brief Update entity by the values of theAttribute
+ /// \return \c true if any value of attribute is not equal to the stored in the entity
+ virtual bool update(std::shared_ptr<ModelAPI_Attribute> theAttribute);
+
+protected:
+ GCS::VEC_pD myValue; ///< list of pointers to values provided by the storage
+};
+
+typedef std::shared_ptr<PlaneGCSSolver_ScalarArrayWrapper> ScalarArrayWrapperPtr;
+
+#endif
//
#include <PlaneGCSSolver_ScalarWrapper.h>
+#include <PlaneGCSSolver_Tools.h>
-#include <cmath>
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeInteger.h>
PlaneGCSSolver_ScalarWrapper::PlaneGCSSolver_ScalarWrapper(double *const theParam)
: myValue(theParam)
{
return *myValue;
}
+
+bool PlaneGCSSolver_ScalarWrapper::update(AttributePtr theAttribute)
+{
+ double anAttrValue = 0.0;
+ AttributeDoublePtr aDouble =
+ std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
+ if (aDouble)
+ anAttrValue = aDouble->value();
+ else {
+ AttributeIntegerPtr anInt =
+ std::dynamic_pointer_cast<ModelAPI_AttributeInteger>(theAttribute);
+ if (anInt)
+ anAttrValue = anInt->value();
+ else
+ return false;
+ }
+
+ // There is possible an angular value, which is converted between degrees and radians.
+ // So, we use its value instead of using direct pointer to variable.
+ double aCurrentValue = value();
+
+ bool isUpdated = PlaneGCSSolver_Tools::updateValue(anAttrValue, aCurrentValue);
+ if (isUpdated)
+ setValue(aCurrentValue);
+ return isUpdated;
+}
virtual SketchSolver_EntityType type() const
{ return ENTITY_SCALAR; }
+protected:
+ /// \brief Update entity by the values of theAttribute
+ /// \return \c true if any value of attribute is not equal to the stored in the entity
+ virtual bool update(std::shared_ptr<ModelAPI_Attribute> theAttribute);
+
protected:
double* myValue; ///< pointer to value provided by the storage
};
#include <PlaneGCSSolver_ConstraintWrapper.h>
#include <PlaneGCSSolver_EdgeWrapper.h>
#include <PlaneGCSSolver_PointWrapper.h>
+#include <PlaneGCSSolver_PointArrayWrapper.h>
+#include <PlaneGCSSolver_ScalarArrayWrapper.h>
#include <PlaneGCSSolver_Tools.h>
#include <PlaneGCSSolver_AttributeBuilder.h>
#include <GeomAPI_Pnt2d.h>
#include <GeomAPI_XY.h>
#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
+#include <ModelAPI_AttributeDoubleArray.h>
#include <ModelAPI_AttributeRefAttr.h>
+#include <SketchPlugin_BSpline.h>
#include <SketchPlugin_Ellipse.h>
#include <SketchPlugin_Projection.h>
return aResult;
}
-/// \brief Update value
-static bool updateValue(const double& theSource, double& theDest)
-{
- static const double aTol = 1.e4 * tolerance;
- bool isUpdated = fabs(theSource - theDest) > aTol;
- if (isUpdated)
- theDest = theSource;
- return isUpdated;
-}
-
-/// \brief Update coordinates of the point or scalar using its base attribute
-static bool updateValues(AttributePtr& theAttribute, EntityWrapperPtr& theEntity)
-{
- bool isUpdated = false;
-
- std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
- if (aPoint2D) {
- const GCSPointPtr& aGCSPoint =
- std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theEntity)->point();
- isUpdated = updateValue(aPoint2D->x(), *(aGCSPoint->x)) || isUpdated;
- isUpdated = updateValue(aPoint2D->y(), *(aGCSPoint->y)) || isUpdated;
- } else {
- AttributeDoublePtr aScalar =
- std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
- if (aScalar) {
- ScalarWrapperPtr aWrapper =
- std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(theEntity);
- // There is possible angular value, which is converted between degrees and radians.
- // So, we use its value instead of using direct pointer to value.
- double aValue = aWrapper->value();
- isUpdated = updateValue(aScalar->value(), aValue);
- if (isUpdated)
- aWrapper->setValue(aValue);
- } else {
- AttributeBooleanPtr aBoolean =
- std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(theAttribute);
- if (aBoolean) {
- BooleanWrapperPtr aWrapper =
- std::dynamic_pointer_cast<PlaneGCSSolver_BooleanWrapper>(theEntity);
- isUpdated = aWrapper->value() != aBoolean->value();
- aWrapper->setValue(aBoolean->value());
- }
- }
- }
-
- return isUpdated;
-}
-
static bool hasReference(std::shared_ptr<SketchPlugin_Feature> theFeature,
const std::string& theFeatureKind)
{
std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
std::list<AttributePtr>::iterator anAttrIt = anAttributes.begin();
for (; anAttrIt != anAttributes.end(); ++anAttrIt)
- if ((*anAttrIt)->attributeType() == GeomDataAPI_Point2D::typeId() ||
- (*anAttrIt)->attributeType() == ModelAPI_AttributeDouble::typeId() ||
- (*anAttrIt)->attributeType() == ModelAPI_AttributeBoolean::typeId())
+ if (PlaneGCSSolver_Tools::isAttributeApplicable((*anAttrIt)->id(), theFeature->getKind()))
isUpdated = update(*anAttrIt) || isUpdated;
// check external attribute is changed
return aRelated.get() != 0;
}
- bool isUpdated = updateValues(anAttribute, aRelated);
+ PlaneGCSSolver_AttributeBuilder aBuilder(aRelated->isExternal() ? 0 : this);
+ bool isUpdated = aBuilder.updateAttribute(anAttribute, aRelated);
if (isUpdated) {
setNeedToResolve(true);
notify(aFeature);
constraintsToSolver(aConstraint, theSolver);
}
+static void createBSplineConstraints(
+ const EntityWrapperPtr& theCurve,
+ const SolverPtr& theSolver,
+ const ConstraintID theConstraintID,
+ std::map<EntityWrapperPtr, ConstraintWrapperPtr>& theConstraints)
+{
+ // set start and end point of B-spline equal to first and last pole correspondingly
+ EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theCurve);
+ std::shared_ptr<GCS::BSpline> aBSpline =
+ std::dynamic_pointer_cast<GCS::BSpline>(anEdge->entity());
+ if (aBSpline->periodic)
+ return; // additional constraints are not necessary
+
+ std::list<GCSConstraintPtr> aBSplineConstraints;
+
+ const std::map<std::string, EntityWrapperPtr>& anAdditional = anEdge->additionalAttributes();
+ PointWrapperPtr aStartPoint = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(
+ 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<PlaneGCSSolver_PointWrapper>(
+ 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())
createEllipticArcConstraints(theEntity, mySketchSolver,
++myConstraintLastID, myAuxConstraintMap);
}
+ else if (theEntity->type() == ENTITY_BSPLINE)
+ createBSplineConstraints(theEntity, mySketchSolver, ++myConstraintLastID, myAuxConstraintMap);
}
void PlaneGCSSolver_Storage::removeAuxiliaryConstraints(const EntityWrapperPtr& theEntity)
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
}
continue;
}
+ std::shared_ptr<GeomDataAPI_Point2DArray> aPointArray =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(anIt->first);
+ if (aPointArray) {
+ std::shared_ptr<PlaneGCSSolver_PointArrayWrapper> anArrayWrapper =
+ std::dynamic_pointer_cast<PlaneGCSSolver_PointArrayWrapper>(anIt->second);
+ int aSize = aPointArray->size();
+ for (int anIndex = 0; anIndex < aSize; ++anIndex) {
+ GeomPnt2dPtr anOriginal = aPointArray->pnt(anIndex);
+ GCSPointPtr aGCSPoint = anArrayWrapper->value(anIndex)->point();
+ if (fabs(anOriginal->x() - (*aGCSPoint->x)) > aTol ||
+ fabs(anOriginal->y() - (*aGCSPoint->y)) > aTol) {
+ aPointArray->setPnt(anIndex, *aGCSPoint->x, *aGCSPoint->y);
+ addOwnerToSet(anIt->first, anUpdatedFeatures);
+ }
+ }
+ continue;
+ }
AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anIt->first);
if (aScalar) {
ScalarWrapperPtr aScalarWrapper =
}
continue;
}
+ AttributeDoubleArrayPtr aRealArray =
+ std::dynamic_pointer_cast<ModelAPI_AttributeDoubleArray>(anIt->first);
+ if (aRealArray) {
+ std::shared_ptr<PlaneGCSSolver_ScalarArrayWrapper> anArrayWrapper =
+ std::dynamic_pointer_cast<PlaneGCSSolver_ScalarArrayWrapper>(anIt->second);
+ int aSize = aRealArray->size();
+ for (int anIndex = 0; anIndex < aSize; ++anIndex) {
+ if (fabs(aRealArray->value(anIndex) - *anArrayWrapper->array()[anIndex]) > aTol) {
+ aRealArray->setValue(anIndex, *anArrayWrapper->array()[anIndex]);
+ addOwnerToSet(anIt->first, anUpdatedFeatures);
+ }
+ }
+ continue;
+ }
}
// notify listeners about features update
#include <PlaneGCSSolver_Tools.h>
#include <PlaneGCSSolver_EdgeWrapper.h>
+#include <PlaneGCSSolver_PointArrayWrapper.h>
#include <PlaneGCSSolver_PointWrapper.h>
+#include <PlaneGCSSolver_ScalarArrayWrapper.h>
#include <PlaneGCSSolver_ScalarWrapper.h>
#include <PlaneGCSSolver_ConstraintWrapper.h>
#include <SketchSolver_ConstraintMultiRotation.h>
#include <SketchSolver_ConstraintMultiTranslation.h>
+#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_BSpline.h>
+#include <SketchPlugin_BSplinePeriodic.h>
+#include <SketchPlugin_Circle.h>
#include <SketchPlugin_ConstraintAngle.h>
#include <SketchPlugin_ConstraintCoincidence.h>
#include <SketchPlugin_ConstraintCollinear.h>
#include <SketchPlugin_ConstraintRigid.h>
#include <SketchPlugin_ConstraintPerpendicular.h>
#include <SketchPlugin_ConstraintTangent.h>
+#include <SketchPlugin_Ellipse.h>
+#include <SketchPlugin_EllipticArc.h>
#include <SketchPlugin_Line.h>
#include <SketchPlugin_MultiRotation.h>
#include <SketchPlugin_MultiTranslation.h>
+#include <SketchPlugin_Point.h>
#include <GeomAPI_Circ2d.h>
#include <GeomAPI_Dir2d.h>
#include <GeomAPI_Lin2d.h>
#include <GeomAPI_Pnt2d.h>
+#include <ModelAPI_AttributeDoubleArray.h>
+#include <ModelAPI_AttributeIntArray.h>
+
#include <cmath>
static ConstraintWrapperPtr
createConstraintPointOnEntity(const SketchSolver_ConstraintType& theType,
std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint,
- std::shared_ptr<PlaneGCSSolver_EdgeWrapper> theEntity);
+ std::shared_ptr<PlaneGCSSolver_EdgeWrapper> theEntity,
+ std::shared_ptr<PlaneGCSSolver_ScalarWrapper> theValue);
static ConstraintWrapperPtr
createConstraintPointsCollinear(std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint1,
std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint2,
std::shared_ptr<PlaneGCSSolver_EdgeWrapper> theEntity2);
static GCS::SET_pD scalarParameters(const ScalarWrapperPtr& theScalar);
+static GCS::SET_pD scalarArrayParameters(const EntityWrapperPtr& theArray);
static GCS::SET_pD pointParameters(const PointWrapperPtr& thePoint);
+static GCS::SET_pD pointArrayParameters(const EntityWrapperPtr& theArray);
static GCS::SET_pD lineParameters(const EdgeWrapperPtr& theLine);
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 double distance(const GCS::Point& thePnt1, const GCS::Point& thePnt2);
-
+static GCS::SET_pD bsplineParameters(const EdgeWrapperPtr& theEdge);
new SketchSolver_ConstraintMovement(theMovedAttribute));
}
+std::shared_ptr<SketchSolver_ConstraintMovement> PlaneGCSSolver_Tools::createMovementConstraint(
+ const std::pair<AttributePtr, int>& theMovedPointInArray)
+{
+ return std::shared_ptr<SketchSolver_ConstraintMovement>(
+ new SketchSolver_ConstraintMovement(theMovedPointInArray.first, theMovedPointInArray.second));
+}
+
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);
case ENTITY_SCALAR:
case ENTITY_ANGLE:
return scalarParameters(GCS_SCALAR_WRAPPER(theEntity));
+ case ENTITY_SCALAR_ARRAY:
+ return scalarArrayParameters(theEntity);
case ENTITY_POINT:
return pointParameters(GCS_POINT_WRAPPER(theEntity));
+ case ENTITY_POINT_ARRAY:
+ return pointArrayParameters(theEntity);
case ENTITY_LINE:
return lineParameters(GCS_EDGE_WRAPPER(theEntity));
case ENTITY_CIRCLE:
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();
}
+bool PlaneGCSSolver_Tools::isAttributeApplicable(const std::string& theAttrName,
+ const std::string& theOwnerName)
+{
+ if (theOwnerName == SketchPlugin_Arc::ID()) {
+ return theAttrName == SketchPlugin_Arc::CENTER_ID() ||
+ theAttrName == SketchPlugin_Arc::START_ID() ||
+ theAttrName == SketchPlugin_Arc::END_ID() ||
+ theAttrName == SketchPlugin_Arc::REVERSED_ID();
+ }
+ else if (theOwnerName == SketchPlugin_Circle::ID()) {
+ return theAttrName == SketchPlugin_Circle::CENTER_ID() ||
+ theAttrName == SketchPlugin_Circle::RADIUS_ID();
+ }
+ else if (theOwnerName == SketchPlugin_Line::ID()) {
+ return theAttrName == SketchPlugin_Line::START_ID() ||
+ theAttrName == SketchPlugin_Line::END_ID();
+ }
+ else if (theOwnerName == SketchPlugin_Ellipse::ID()) {
+ return theAttrName == SketchPlugin_Ellipse::CENTER_ID() ||
+ theAttrName == SketchPlugin_Ellipse::FIRST_FOCUS_ID() ||
+ theAttrName == SketchPlugin_Ellipse::SECOND_FOCUS_ID() ||
+ theAttrName == SketchPlugin_Ellipse::MAJOR_AXIS_START_ID() ||
+ theAttrName == SketchPlugin_Ellipse::MAJOR_AXIS_END_ID() ||
+ theAttrName == SketchPlugin_Ellipse::MINOR_AXIS_START_ID() ||
+ theAttrName == SketchPlugin_Ellipse::MINOR_AXIS_END_ID() ||
+ theAttrName == SketchPlugin_Ellipse::MAJOR_RADIUS_ID() ||
+ theAttrName == SketchPlugin_Ellipse::MINOR_RADIUS_ID();
+ }
+ else if (theOwnerName == SketchPlugin_EllipticArc::ID()) {
+ return theAttrName == SketchPlugin_EllipticArc::CENTER_ID() ||
+ theAttrName == SketchPlugin_EllipticArc::FIRST_FOCUS_ID() ||
+ theAttrName == SketchPlugin_EllipticArc::SECOND_FOCUS_ID() ||
+ theAttrName == SketchPlugin_EllipticArc::MAJOR_AXIS_START_ID() ||
+ theAttrName == SketchPlugin_EllipticArc::MAJOR_AXIS_END_ID() ||
+ theAttrName == SketchPlugin_EllipticArc::MINOR_AXIS_START_ID() ||
+ theAttrName == SketchPlugin_EllipticArc::MINOR_AXIS_END_ID() ||
+ theAttrName == SketchPlugin_EllipticArc::MAJOR_RADIUS_ID() ||
+ theAttrName == SketchPlugin_EllipticArc::MINOR_RADIUS_ID() ||
+ theAttrName == SketchPlugin_EllipticArc::START_POINT_ID() ||
+ theAttrName == SketchPlugin_EllipticArc::END_POINT_ID() ||
+ theAttrName == SketchPlugin_EllipticArc::REVERSED_ID();
+ }
+ 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() ||
+ theAttrName == SketchPlugin_BSpline::START_ID() ||
+ theAttrName == SketchPlugin_BSpline::END_ID();
+ }
+ else if (theOwnerName == SketchPlugin_BSplinePeriodic::ID()) {
+ return theAttrName == SketchPlugin_BSplinePeriodic::POLES_ID() ||
+ theAttrName == SketchPlugin_BSplinePeriodic::WEIGHTS_ID() ||
+ theAttrName == SketchPlugin_BSplinePeriodic::KNOTS_ID() ||
+ theAttrName == SketchPlugin_BSplinePeriodic::MULTS_ID() ||
+ theAttrName == SketchPlugin_BSplinePeriodic::DEGREE_ID();
+ }
+
+ // suppose that all remaining features are points
+ return theAttrName == SketchPlugin_Point::COORD_ID();
+}
+
+/// \brief Update value
+bool PlaneGCSSolver_Tools::updateValue(const double& theSource, double& theDest,
+ const double theTolerance)
+{
+ bool isUpdated = fabs(theSource - theDest) > theTolerance;
+ if (isUpdated)
+ theDest = theSource;
+ return isUpdated;
+}
+
+
+double PlaneGCSSolver_Tools::distance(const GCS::Point& thePnt1, const GCS::Point& thePnt2)
+{
+ double x = *thePnt1.x - *thePnt2.x;
+ double y = *thePnt1.y - *thePnt2.y;
+ return sqrt(x*x + y*y);
+}
+
+
+
+
+// ================ AttributeArray methods ==========================
+PlaneGCSSolver_Tools::AttributeArray::AttributeArray(AttributePtr theAttribute)
+{
+ myDouble = std::dynamic_pointer_cast<ModelAPI_AttributeDoubleArray>(theAttribute);
+ myInteger = std::dynamic_pointer_cast<ModelAPI_AttributeIntArray>(theAttribute);
+}
+
+bool PlaneGCSSolver_Tools::AttributeArray::isInitialized() const
+{
+ return (myDouble && myDouble->isInitialized()) || (myInteger && myInteger->isInitialized());
+}
+
+int PlaneGCSSolver_Tools::AttributeArray::size() const
+{
+ return myDouble.get() ? myDouble->size() : myInteger->size();
+}
+
+double PlaneGCSSolver_Tools::AttributeArray::value(const int theIndex) const
+{
+ return myDouble.get() ? myDouble->value(theIndex) : myInteger->value(theIndex);
+}
+
ConstraintWrapperPtr createConstraintPointOnEntity(
const SketchSolver_ConstraintType& theType,
std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint,
- std::shared_ptr<PlaneGCSSolver_EdgeWrapper> theEntity)
+ std::shared_ptr<PlaneGCSSolver_EdgeWrapper> theEntity,
+ std::shared_ptr<PlaneGCSSolver_ScalarWrapper> theValue)
{
GCSConstraintPtr aNewConstr;
new GCS::ConstraintPointOnEllipse(*(thePoint->point()), *anEllipse));
break;
}
+ case ENTITY_BSPLINE: {
+ std::list<GCSConstraintPtr> 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();
}
aConstrList.push_back(GCSConstraintPtr(
new GCS::ConstraintP2PDistance(aLine2->p1, aLine2->p2, theIntermed->scalar())));
// update value of intermediate parameter
- theIntermed->setValue(distance(aLine1->p1, aLine1->p2));
+ theIntermed->setValue(PlaneGCSSolver_Tools::distance(aLine1->p1, aLine1->p2));
}
else if (theType == CONSTRAINT_EQUAL_ELLIPSES) {
std::shared_ptr<GCS::Ellipse> anEllipse1 =
aConstrList.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance(
anEllipse2->center, anEllipse2->focus1, theIntermed->scalar())));
// update value of intermediate parameter
- theIntermed->setValue(distance(anEllipse1->center, anEllipse1->focus1));
+ theIntermed->setValue(PlaneGCSSolver_Tools::distance(anEllipse1->center, anEllipse1->focus1));
}
else {
std::shared_ptr<GCS::Circle> aCirc1 =
return aParams;
}
+GCS::SET_pD scalarArrayParameters(const EntityWrapperPtr& theArray)
+{
+ ScalarArrayWrapperPtr anArray =
+ std::dynamic_pointer_cast<PlaneGCSSolver_ScalarArrayWrapper>(theArray);
+ return GCS::SET_pD(anArray->array().begin(), anArray->array().end());
+}
+
GCS::SET_pD pointParameters(const PointWrapperPtr& thePoint)
{
GCS::SET_pD aParams;
return aParams;
}
+GCS::SET_pD pointArrayParameters(const EntityWrapperPtr& theArray)
+{
+ GCS::SET_pD aParams;
+ PointArrayWrapperPtr aPoints =
+ std::dynamic_pointer_cast<PlaneGCSSolver_PointArrayWrapper>(theArray);
+ for (std::vector<PointWrapperPtr>::const_iterator anIt = aPoints->array().begin();
+ anIt != aPoints->array().end(); ++anIt) {
+ GCS::SET_pD aPointParams = PlaneGCSSolver_Tools::parameters(*anIt);
+ aParams.insert(aPointParams.begin(), aPointParams.end());
+ }
+ return aParams;
+}
+
GCS::SET_pD lineParameters(const EdgeWrapperPtr& theLine)
{
GCS::SET_pD aParams;
return aParams;
}
-double distance(const GCS::Point& thePnt1, const GCS::Point& thePnt2)
+GCS::SET_pD bsplineParameters(const EdgeWrapperPtr& theEdge)
{
- double x = *thePnt1.x - *thePnt2.x;
- double y = *thePnt1.y - *thePnt2.y;
- return sqrt(x*x + y*y);
+ GCS::SET_pD aParams;
+
+ std::shared_ptr<GCS::BSpline> aBSpline =
+ std::dynamic_pointer_cast<GCS::BSpline>(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;
}
class GeomAPI_Lin2d;
class GeomAPI_Pnt2d;
+class ModelAPI_AttributeDoubleArray;
+class ModelAPI_AttributeIntArray;
+
/** \namespace PlaneGCSSolver_Tools
* \ingroup Plugins
* \brief Converter tools
/// \brief Creates temporary constraint to fix the attribute after movement
std::shared_ptr<SketchSolver_ConstraintMovement>
createMovementConstraint(AttributePtr theMovedAttribute);
+ /// \brief Creates temporary constraint to fix the point in array after movement
+ std::shared_ptr<SketchSolver_ConstraintMovement>
+ createMovementConstraint(const std::pair<AttributePtr, int>& theMovedPointInArray);
/// \brief Creates new constraint using given parameters
/// \param theConstraint [in] original constraint
const EntityWrapperPtr& theEntity3 = EntityWrapperPtr(),
const EntityWrapperPtr& theEntity4 = EntityWrapperPtr());
+ /// \brief Return \c true if the attribute is used in PlaneGCS solver
+ /// \param[in] theAttrName name of the attribute
+ /// \param[in] theOwnerName name of the parent feature
+ bool isAttributeApplicable(const std::string& theAttrName,
+ const std::string& theOwnerName);
+
/// \brief Convert entity to point
/// \return empty pointer if the entity is not a point
std::shared_ptr<GeomAPI_Pnt2d> point(EntityWrapperPtr theEntity);
/// brief Return list of parameters for the given entity
GCS::SET_pD parameters(const EntityWrapperPtr& theEntity);
+
+ /// \brief Update value in theDest if theSource is differ more than theTolerance
+ /// \return \c true if the value was updated.
+ bool updateValue(const double& theSource, double& theDest,
+ const double theTolerance = 1.e-4 * tolerance);
+
+ double distance(const GCS::Point& thePnt1, const GCS::Point& thePnt2);
+
+ /// \brief Provide an interface to access values in attribute which is an array of values
+ class AttributeArray
+ {
+ public:
+ AttributeArray(AttributePtr theAttribute);
+
+ bool isInitialized() const;
+
+ int size() const;
+
+ double value(const int theIndex) const;
+
+ private:
+ std::shared_ptr<ModelAPI_AttributeDoubleArray> myDouble;
+ std::shared_ptr<ModelAPI_AttributeIntArray> myInteger;
+ };
};
#endif
SketchSolver_EntityType aType = anEntity->type();
if (aType == ENTITY_UNKNOWN)
continue;
- else if (aType == ENTITY_POINT)
+ else if (aType == ENTITY_POINT || aType == ENTITY_POINT_ARRAY)
theAttributes[aPtInd++] = anEntity; // the point is created
else { // another entity (not a point) is created
if (aEntInd < anInitNbOfAttr)
#include <SketchSolver_ConstraintCoincidence.h>
#include <SketchSolver_Error.h>
+#include <PlaneGCSSolver_PointArrayWrapper.h>
+#include <PlaneGCSSolver_Storage.h>
#include <PlaneGCSSolver_Tools.h>
#include <PlaneGCSSolver_UpdateCoincidence.h>
#include <GeomDataAPI_Point2D.h>
+#include <ModelAPI_AttributeInteger.h>
+
#include <SketchPlugin_Arc.h>
#include <SketchPlugin_ConstraintCoincidenceInternal.h>
#include <SketchPlugin_Ellipse.h>
}
}
+static void getPointFromArray(EntityWrapperPtr& theArray,
+ const ConstraintPtr& theConstraint,
+ const std::string& theIndexAttrId)
+{
+ if (theArray && theArray->type() == ENTITY_POINT_ARRAY) {
+ AttributeIntegerPtr anIndexAttr = theConstraint->integer(theIndexAttrId);
+ if (anIndexAttr) {
+ PointArrayWrapperPtr aPointsArray =
+ std::dynamic_pointer_cast<PlaneGCSSolver_PointArrayWrapper>(theArray);
+ theArray = aPointsArray->value(anIndexAttr->value());
+ }
+ }
+}
+
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);
myInSolver = false;
myFeatureExtremities[0] = EntityWrapperPtr();
myFeatureExtremities[1] = EntityWrapperPtr();
+ if (myAuxValue) {
+ std::shared_ptr<PlaneGCSSolver_Storage> aStorage =
+ std::dynamic_pointer_cast<PlaneGCSSolver_Storage>(myStorage);
+ GCS::SET_pD aParams;
+ aParams.insert(myAuxValue->scalar());
+ aStorage->removeParameters(aParams);
+ }
return SketchSolver_Constraint::remove();
}
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<PlaneGCSSolver_Storage> aStorage =
+ std::dynamic_pointer_cast<PlaneGCSSolver_Storage>(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();
+
+ // process internal coincidence with a point in the array of points
+ getPointFromArray(theAttributes[0], myBaseConstraint,
+ SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_A());
+ getPointFromArray(theAttributes[1], myBaseConstraint,
+ SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_B());
}
void SketchSolver_ConstraintCoincidence::notify(const FeaturePtr& theFeature,
}
}
}
+
+void SketchSolver_ConstraintCoincidence::adjustConstraint()
+{
+ if (myBaseConstraint->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID()) {
+ AttributeIntegerPtr anIndexA = myBaseConstraint->integer(
+ SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_A());
+ AttributeIntegerPtr anIndexB = myBaseConstraint->integer(
+ SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_B());
+ if ((anIndexA && anIndexA->isInitialized()) ||
+ (anIndexB && anIndexB->isInitialized())) {
+ remove();
+ process();
+ }
+ }
+}
virtual void getAttributes(EntityWrapperPtr& theValue,
std::vector<EntityWrapperPtr>& theAttributes);
+ /// \brief This method is used in derived objects to check consistency of constraint.
+ /// E.g. the distance between line and point may be signed.
+ virtual void adjustConstraint();
+
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
aParameters.push_back(anEllArc->endAngle);
break;
}
+ case ENTITY_BSPLINE: {
+ std::shared_ptr<GCS::BSpline> aBSpline =
+ std::dynamic_pointer_cast<GCS::BSpline>(anEntity->entity());
+ for (GCS::VEC_P::iterator anIt = aBSpline->poles.begin();
+ anIt != aBSpline->poles.end(); ++anIt) {
+ aParameters.push_back(anIt->x);
+ aParameters.push_back(anIt->y);
+ }
+ break;
+ }
default:
break;
}
#include <SketchSolver_Manager.h>
#include <PlaneGCSSolver_EdgeWrapper.h>
+#include <PlaneGCSSolver_PointArrayWrapper.h>
#include <PlaneGCSSolver_PointWrapper.h>
#include <SketchPlugin_Arc.h>
{
}
-SketchSolver_ConstraintMovement::SketchSolver_ConstraintMovement(AttributePtr thePoint)
+SketchSolver_ConstraintMovement::SketchSolver_ConstraintMovement(AttributePtr theAttribute,
+ const int thePointIndex)
: SketchSolver_ConstraintFixed(ConstraintPtr()),
- myDraggedPoint(thePoint),
+ myDraggedAttribute(theAttribute),
+ myDraggedPointIndex(thePointIndex),
mySimpleMove(true)
{
- myMovedFeature = ModelAPI_Feature::feature(thePoint->owner());
+ myMovedFeature = ModelAPI_Feature::feature(theAttribute->owner());
}
void SketchSolver_ConstraintMovement::blockEvents(bool isBlocked)
return aConstraint;
}
- EntityWrapperPtr anEntity =
- myDraggedPoint ? myStorage->entity(myDraggedPoint) : myStorage->entity(myMovedFeature);
+ EntityWrapperPtr anEntity = myDraggedAttribute ? myStorage->entity(myDraggedAttribute)
+ : myStorage->entity(myMovedFeature);
if (!anEntity) {
myStorage->update(myMovedFeature, true);
- anEntity =
- myDraggedPoint ? myStorage->entity(myDraggedPoint) : myStorage->entity(myMovedFeature);
+ anEntity = myDraggedAttribute ? myStorage->entity(myDraggedAttribute)
+ : myStorage->entity(myMovedFeature);
if (!anEntity)
return aConstraint;
}
- mySimpleMove = isSimpleMove(myMovedFeature, myDraggedPoint);
+ mySimpleMove = isSimpleMove(myMovedFeature, myDraggedAttribute);
- if (mySimpleMove)
+ if (mySimpleMove) {
+ if (anEntity->type() == ENTITY_POINT_ARRAY) {
+ anEntity = std::dynamic_pointer_cast<PlaneGCSSolver_PointArrayWrapper>(anEntity)
+ ->value(myDraggedPointIndex);
+ }
aConstraint = fixFeature(anEntity);
+ }
else {
- if (myDraggedPoint) // start or end point of arc has been moved
+ if (myDraggedAttribute) // start or end point of arc has been moved
aConstraint = fixArcExtremity(anEntity);
else if (anEntity->type() == ENTITY_CIRCLE || anEntity->type() == ENTITY_ARC) {
// arc or circle has been moved
#ifdef CHANGE_RADIUS_WHILE_MOVE
int aMaxSize = mySimpleMove ? (int)myFixedValues.size() : 2;
#else
- int aMaxSize = myMovedFeature->getKind() == SketchPlugin_Line::ID() && !myDraggedPoint ? 4 : 2;
+ int aMaxSize =
+ myMovedFeature->getKind() == SketchPlugin_Line::ID() && !myDraggedAttribute ? 4 : 2;
#endif
for (int i = 0; i < aMaxSize; ++i)
myFixedValues[i] += aDelta[i % 2];
SketchSolver_ConstraintMovement(FeaturePtr theFeature);
/// Creates movement constraint based on point
- SketchSolver_ConstraintMovement(AttributePtr thePoint);
+ SketchSolver_ConstraintMovement(AttributePtr theMovedAttribute, const int thePointIndex = -1);
/// \brief Set coordinates of the start point of the movement
void startPoint(const std::shared_ptr<GeomAPI_Pnt2d>& theStartPoint);
private:
FeaturePtr myMovedFeature; ///< fixed feature (if set, myBaseConstraint should be NULL)
- AttributePtr myDraggedPoint; ///< one of the feature points which has been moved
+ AttributePtr myDraggedAttribute; ///< one of the feature points which has been moved
+ int myDraggedPointIndex; ///< index of the point if the moved attribute is an array
std::shared_ptr<GeomAPI_Pnt2d> myStartPoint; ///< start point of the movement
bool mySimpleMove; ///< simple move, thus all parameters should be increased by movement delta
#include <GeomAPI_Pnt2d.h>
#include <GeomAPI_Ellipse2d.h>
+#include <ModelAPI_AttributeInteger.h>
+
#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_BSpline.h>
#include <SketchPlugin_Circle.h>
#include <SketchPlugin_ConstraintCoincidence.h>
#include <SketchPlugin_ConstraintCoincidenceInternal.h>
mySharedPoint = AttributePtr();
if (myAuxPoint) {
GCS::SET_pD aParams = PlaneGCSSolver_Tools::parameters(myAuxPoint);
+ if (myAuxParameters[0])
+ aParams.insert(myAuxParameters[0]->scalar());
+ if (myAuxParameters[1])
+ aParams.insert(myAuxParameters[1]->scalar());
aStorage->removeParameters(aParams);
myAuxPoint = EntityWrapperPtr();
+ myAuxParameters[0] = myAuxParameters[1] = ScalarWrapperPtr();
}
// Check the quantity of entities of each type and their order (arcs first)
int aNbLines = 0;
int aNbCircles = 0;
int aNbEllipses = 0;
+ int aNbSplines = 0;
std::list<EntityWrapperPtr>::iterator anEntIt = myAttributes.begin();
for (; anEntIt != myAttributes.end(); ++anEntIt) {
if (!(*anEntIt).get())
++aNbCircles;
else if ((*anEntIt)->type() == ENTITY_ELLIPSE || (*anEntIt)->type() == ENTITY_ELLIPTIC_ARC)
++aNbEllipses;
+ else if ((*anEntIt)->type() == ENTITY_BSPLINE)
+ ++aNbSplines;
}
- if (aNbCircles + aNbEllipses < 1) {
+ if (aNbCircles + aNbEllipses + aNbSplines < 1) {
myErrorMsg = SketchSolver_Error::INCORRECT_TANGENCY_ATTRIBUTE();
return;
}
if (aNbLines == 1 && aNbCircles == 1) {
myType = CONSTRAINT_TANGENT_CIRCLE_LINE;
}
- else if (aNbLines + aNbCircles + aNbEllipses == 2) {
+ else if (aNbLines + aNbCircles + aNbEllipses + aNbSplines == 2) {
myType = CONSTRAINT_TANGENT_CURVE_CURVE;
isArcArcInternal = isArcArcTangencyInternal(myAttributes.front(), myAttributes.back());
}
return;
}
- FeaturePtr aFeature1, aFeature2;
- getTangentFeatures(myBaseConstraint, aFeature1, aFeature2);
+ FeaturePtr aFeatures[2];
+ getTangentFeatures(myBaseConstraint, aFeatures[0], aFeatures[1]);
// check number of coincident points
- std::set<AttributePtr> aCoincidentPoints = coincidentBoundaryPoints(aFeature1, aFeature2);
+ std::set<AttributePtr> aCoincidentPoints = coincidentBoundaryPoints(aFeatures[0], aFeatures[1]);
if (myType == CONSTRAINT_TANGENT_CIRCLE_LINE && aCoincidentPoints.size() > 2) {
myErrorMsg = SketchSolver_Error::TANGENCY_FAILED();
return;
}
- // Try to find non-boundary points coincident with both features.
- // It is necesasry to create tangency with ellipse
- if (aCoincidentPoints.empty() && aNbEllipses > 0)
- aCoincidentPoints = coincidentPoints(aFeature1, aFeature2);
+ EntityWrapperPtr aTgEntities[2] = { myAttributes.front(), myAttributes.back() };
+
+ if (aCoincidentPoints.empty()) {
+ // Try to find non-boundary points coincident with both features.
+ // It is necesasry to create tangency with ellipse.
+ if (aNbEllipses > 0)
+ aCoincidentPoints = coincidentPoints(aFeatures[0], aFeatures[1]);
+ }
+ else if (aNbSplines > 0) {
+ // General approach applying tangency to B-spline leads to hang-up in PlaneGCS.
+ // So, the tangency will be applied for the construction segment instead of B-spline curve.
+ for (int i = 0; i < 2; ++i) {
+ if (aTgEntities[i]->type() == ENTITY_BSPLINE) {
+ EdgeWrapperPtr anEdge =
+ std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(aTgEntities[i]);
+ std::shared_ptr<GCS::BSpline> aBSpline =
+ std::dynamic_pointer_cast<GCS::BSpline>(anEdge->entity());
+
+ // which boundary is coincident?
+ GCS::Point aPoint1, aPoint2;
+ for (std::set<AttributePtr>::iterator aPIt = aCoincidentPoints.begin();
+ aPIt != aCoincidentPoints.end(); ++aPIt) {
+ if ((*aPIt)->owner() == aFeatures[i]) {
+ if ((*aPIt)->id() == SketchPlugin_BSpline::START_ID()) {
+ aPoint1 = aBSpline->poles[0];
+ aPoint2 = aBSpline->poles[1];
+ }
+ else if ((*aPIt)->id() == SketchPlugin_BSpline::END_ID()) {
+ aPoint1 = aBSpline->poles[aBSpline->poles.size() - 2];
+ aPoint2 = aBSpline->poles[aBSpline->poles.size() - 1];
+ }
+ break;
+ }
+ }
+
+ // substitute B-spline by its boundary segment
+ std::shared_ptr<GCS::Line> aSegment(new GCS::Line);
+ aSegment->p1 = aPoint1;
+ aSegment->p2 = aPoint2;
+ aTgEntities[i] = EdgeWrapperPtr(new PlaneGCSSolver_EdgeWrapper(aSegment));
+ --aNbSplines;
+ ++aNbLines;
+ }
+ }
+ }
EntityWrapperPtr aSharedPointEntity;
std::list<GCSConstraintPtr> anAuxConstraints;
mySharedPoint = *aCoincidentPoints.begin();
aSharedPointEntity = myStorage->entity(mySharedPoint);
}
- else if (aNbEllipses > 0) {
+ else if (aNbEllipses + aNbSplines > 0) {
// create auxiliary point
GCSPointPtr aPoint(new GCS::Point);
aPoint->x = aStorage->createParameter();
aPoint->y = aStorage->createParameter();
- calculateTangencyPoint(myAttributes.front(), myAttributes.back(), aPoint);
+ calculateTangencyPoint(aTgEntities[0], aTgEntities[1], aPoint);
myAuxPoint.reset(new PlaneGCSSolver_PointWrapper(aPoint));
aSharedPointEntity = myAuxPoint;
- // create auxiliary coincident constraints for tangency with ellipse
EntityWrapperPtr aDummy;
- ConstraintWrapperPtr aCoincidence = PlaneGCSSolver_Tools::createConstraint(ConstraintPtr(),
- CONSTRAINT_PT_ON_CURVE, aDummy, aSharedPointEntity, aDummy, myAttributes.front(), aDummy);
- anAuxConstraints = aCoincidence->constraints();
- aCoincidence = PlaneGCSSolver_Tools::createConstraint(ConstraintPtr(),
- CONSTRAINT_PT_ON_CURVE, aDummy, aSharedPointEntity, aDummy, myAttributes.back(), aDummy);
- anAuxConstraints.insert(anAuxConstraints.end(),
- aCoincidence->constraints().begin(), aCoincidence->constraints().end());
+ for (int i = 0; i < 2; ++i) {
+ // create auxiliary parameters for coincidence with B-spline
+ if (aTgEntities[i]->type() == ENTITY_BSPLINE)
+ myAuxParameters[i].reset(new PlaneGCSSolver_ScalarWrapper(aStorage->createParameter()));
+
+ // create auxiliary coincident constraints for tangency with ellipse
+ ConstraintWrapperPtr aCoincidence = PlaneGCSSolver_Tools::createConstraint(ConstraintPtr(),
+ CONSTRAINT_PT_ON_CURVE, myAuxParameters[i],
+ aSharedPointEntity, aDummy, aTgEntities[i], aDummy);
+ anAuxConstraints.insert(anAuxConstraints.end(),
+ aCoincidence->constraints().begin(), aCoincidence->constraints().end());
+ }
}
if (myType == CONSTRAINT_TANGENT_CIRCLE_LINE) {
- mySolverConstraint = createArcLineTangency(myAttributes.front(), myAttributes.back(),
+ mySolverConstraint = createArcLineTangency(aTgEntities[0], aTgEntities[1],
aSharedPointEntity, &myCurveCurveAngle);
} else {
- mySolverConstraint = createCurveCurveTangency(myAttributes.front(), myAttributes.back(),
+ mySolverConstraint = createCurveCurveTangency(aTgEntities[0], aTgEntities[1],
isArcArcInternal, aSharedPointEntity, &myCurveCurveAngle);
}
rebuild();
}
+bool SketchSolver_ConstraintTangent::remove()
+{
+ if (myAuxPoint) {
+ std::shared_ptr<PlaneGCSSolver_Storage> aStorage =
+ std::dynamic_pointer_cast<PlaneGCSSolver_Storage>(myStorage);
+
+ GCS::SET_pD aParams = PlaneGCSSolver_Tools::parameters(myAuxPoint);
+ if (myAuxParameters[0])
+ aParams.insert(myAuxParameters[0]->scalar());
+ if (myAuxParameters[1])
+ aParams.insert(myAuxParameters[1]->scalar());
+ aStorage->removeParameters(aParams);
+ myAuxPoint = EntityWrapperPtr();
+ myAuxParameters[0] = myAuxParameters[1] = ScalarWrapperPtr();
+ }
+ return SketchSolver_Constraint::remove();
+}
+
const std::set<AttributePtr>& aRefs2 = theFeature2->data()->refsToMe();
std::set<FeaturePtr> aCoincidences;
+ std::map<AttributePtr, FeaturePtr> aCoincidentPoints;
std::set<AttributePtr>::const_iterator anIt;
// collect coincidences referred to the first feature
for (anIt = aRefs1.begin(); anIt != aRefs1.end(); ++anIt) {
FeaturePtr aRef = ModelAPI_Feature::feature((*anIt)->owner());
- if (aRef && aRef->getKind() == SketchPlugin_ConstraintCoincidence::ID())
+ if (aRef && (aRef->getKind() == SketchPlugin_ConstraintCoincidence::ID() ||
+ aRef->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID())) {
aCoincidences.insert(aRef);
+ AttributeRefAttrPtr aRefAttrA = aRef->refattr(SketchPlugin_Constraint::ENTITY_A());
+ if (!aRefAttrA->isObject())
+ aCoincidentPoints[aRefAttrA->attr()] = aRef;
+ AttributeRefAttrPtr aRefAttrB = aRef->refattr(SketchPlugin_Constraint::ENTITY_B());
+ if (!aRefAttrB->isObject())
+ aCoincidentPoints[aRefAttrB->attr()] = aRef;
+ }
}
// leave only coincidences referred to the second feature
FeaturePtr aRef = ModelAPI_Feature::feature((*anIt)->owner());
if (aCoincidences.find(aRef) != aCoincidences.end())
aCoincidencesBetweenFeatures.insert(aRef);
+ else if (aRef && (aRef->getKind() == SketchPlugin_ConstraintCoincidence::ID() ||
+ aRef->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID())) {
+ for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
+ AttributeRefAttrPtr aRefAttr = aRef->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
+ if (aRefAttr && !aRefAttr->isObject()) {
+ std::map<AttributePtr, FeaturePtr>::iterator aFound =
+ aCoincidentPoints.find(aRefAttr->attr());
+ if (aFound != aCoincidentPoints.end()) {
+ aCoincidencesBetweenFeatures.insert(aRef);
+ aCoincidencesBetweenFeatures.insert(aFound->second);
+ }
+ }
+ }
+ }
}
return aCoincidencesBetweenFeatures;
std::set<AttributePtr> aCoincidentPoints;
std::set<FeaturePtr>::const_iterator aCIt = aCoincidences.begin();
for (; aCIt != aCoincidences.end(); ++ aCIt) {
- AttributeRefAttrPtr aRefAttrA = (*aCIt)->refattr(SketchPlugin_Constraint::ENTITY_A());
- AttributeRefAttrPtr aRefAttrB = (*aCIt)->refattr(SketchPlugin_Constraint::ENTITY_B());
- if (!aRefAttrA || aRefAttrA->isObject() ||
- !aRefAttrB || aRefAttrB->isObject())
- continue;
-
- AttributePtr anAttrA = aRefAttrA->attr();
- AttributePtr anAttrB = aRefAttrB->attr();
- if (anAttrA->id() != SketchPlugin_Arc::CENTER_ID() &&
- anAttrA->id() != SketchPlugin_Circle::CENTER_ID() &&
- anAttrB->id() != SketchPlugin_Arc::CENTER_ID() &&
- anAttrB->id() != SketchPlugin_Circle::CENTER_ID()) {
- aCoincidentPoints.insert(anAttrA);
- aCoincidentPoints.insert(anAttrB);
+ for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
+ AttributeRefAttrPtr aRefAttr = (*aCIt)->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
+ if (!aRefAttr || aRefAttr->isObject())
+ continue;
+
+ AttributePtr anAttr = aRefAttr->attr();
+ FeaturePtr anOwner = ModelAPI_Feature::feature(anAttr->owner());
+ if (anOwner == theFeature1 || anOwner == theFeature2) {
+ if (anAttr->id() == SketchPlugin_BSplineBase::POLES_ID()) {
+ AttributeIntegerPtr anIndex = (*aCIt)->integer(i == 0 ?
+ SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_A() :
+ SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_B());
+ if (anIndex) {
+ if (anIndex->value() == 0)
+ anAttr = anOwner->attribute(SketchPlugin_BSpline::START_ID());
+ else
+ anAttr = anOwner->attribute(SketchPlugin_BSpline::END_ID());
+ if (anAttr)
+ aCoincidentPoints.insert(anAttr);
+ }
+ }
+ else if (anAttr->id() != SketchPlugin_Arc::CENTER_ID() &&
+ anAttr->id() != SketchPlugin_Circle::CENTER_ID())
+ aCoincidentPoints.insert(anAttr);
+ }
}
}
return aCoincidentPoints;
virtual void notify(const FeaturePtr& theFeature,
PlaneGCSSolver_Update* theUpdater);
+ /// \brief Tries to remove constraint
+ /// \return \c false, if current constraint contains another SketchPlugin constraints
+ /// (like for multiple coincidence)
+ virtual bool remove();
+
protected:
/// \brief Converts SketchPlugin constraint to a list of solver constraints
virtual void process();
double myCurveCurveAngle;
AttributePtr mySharedPoint;
EntityWrapperPtr myAuxPoint;
+ ScalarWrapperPtr myAuxParameters[2];
};
#endif
int theSketchDOF,
bool theEventsBlocked,
Type theFeatureOrPoint,
+ const EntityWrapperPtr& theSolverEntity,
const std::shared_ptr<GeomAPI_Pnt2d>& theFrom,
const std::shared_ptr<GeomAPI_Pnt2d>& theTo)
{
- bool isEntityExists = (theStorage->entity(theFeatureOrPoint).get() != 0);
+ bool isEntityExists = (theSolverEntity.get() != 0);
if (theSketchDOF == 0 && isEntityExists) {
// avoid moving elements of fully constrained sketch
theStorage->refresh();
const std::shared_ptr<GeomAPI_Pnt2d>& theFrom,
const std::shared_ptr<GeomAPI_Pnt2d>& theTo)
{
- SolverConstraintPtr aConstraint =
- move(myStorage, mySketchSolver, myDOF, myIsEventsBlocked, theFeature, theFrom, theTo);
+ EntityWrapperPtr anEntity = myStorage->entity(theFeature);
+ SolverConstraintPtr aConstraint = move(myStorage, mySketchSolver, myDOF, myIsEventsBlocked,
+ theFeature, anEntity, theFrom, theTo);
setTemporary(aConstraint);
return true;
}
bool SketchSolver_Group::movePoint(AttributePtr theAttribute,
+ const int thePointIndex,
const std::shared_ptr<GeomAPI_Pnt2d>& theFrom,
const std::shared_ptr<GeomAPI_Pnt2d>& theTo)
{
- SolverConstraintPtr aConstraint =
- move(myStorage, mySketchSolver, myDOF, myIsEventsBlocked, theAttribute, theFrom, theTo);
+ EntityWrapperPtr anEntity = myStorage->entity(theAttribute);
+ SolverConstraintPtr aConstraint;
+ if (thePointIndex < 0) {
+ aConstraint = move(myStorage, mySketchSolver, myDOF, myIsEventsBlocked,
+ theAttribute, anEntity, theFrom, theTo);
+ }
+ else {
+ aConstraint = move(myStorage, mySketchSolver, myDOF, myIsEventsBlocked,
+ std::pair<AttributePtr, int>(theAttribute, thePointIndex), anEntity,
+ theFrom, theTo);
+ }
setTemporary(aConstraint);
return true;
}
const std::shared_ptr<GeomAPI_Pnt2d>& theTo);
/** \brief Updates the data corresponding the specified point moved in GUI.
* Special kind of Fixed constraints is created.
- * \param[in] thePoint the attribute to be updated
- * \param[in] theFrom start point of the movement
- * \param[in] theTo final point of the movement
+ * \param[in] thePointOrArray the attribute to be updated
+ * \param[in] thePointIndex index of moved point in array
+ * \param[in] theFrom start point of the movement
+ * \param[in] theTo destination point of the movement
* \return \c true, if the attribute is really moved
*/
- bool movePoint(AttributePtr thePoint,
+ bool movePoint(AttributePtr thePointOrArray,
+ const int thePointIndex,
const std::shared_ptr<GeomAPI_Pnt2d>& theFrom,
const std::shared_ptr<GeomAPI_Pnt2d>& theTo);
#include <Events_Loop.h>
#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
#include <ModelAPI_Events.h>
#include <ModelAPI_ResultConstruction.h>
#include <ModelAPI_Session.h>
}
}
+static void setPoint(AttributePtr theAttribute,
+ const int thePointIndex,
+ const std::shared_ptr<GeomAPI_Pnt2d> theValue)
+{
+ AttributePoint2DPtr aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
+ AttributePoint2DArrayPtr aPointArrayAttr =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(theAttribute);
+ if (aPointAttr)
+ aPointAttr->setValue(theValue);
+ else if (aPointArrayAttr && thePointIndex >= 0)
+ aPointArrayAttr->setPnt(thePointIndex, theValue);
+}
+
// ========================================================
std::dynamic_pointer_cast<ModelAPI_ObjectMovedMessage>(theMessage);
ObjectPtr aMovedObject = aMoveMsg->movedObject();
- std::shared_ptr<GeomDataAPI_Point2D> aMovedPoint =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aMoveMsg->movedAttribute());
+ AttributePtr aMovedAttribute = aMoveMsg->movedAttribute();
+ int aMovedPoint = aMoveMsg->movedPointIndex();
const std::shared_ptr<GeomAPI_Pnt2d>& aFrom = aMoveMsg->originalPosition();
const std::shared_ptr<GeomAPI_Pnt2d>& aTo = aMoveMsg->currentPosition();
std::dynamic_pointer_cast<SketchPlugin_Feature>(aMovedFeature);
if (aSketchFeature && !aSketchFeature->isMacro())
needToResolve = moveFeature(aSketchFeature, aFrom, aTo);
- } else if (aMovedPoint)
- needToResolve = moveAttribute(aMovedPoint, aFrom, aTo);
+ } else if (aMovedAttribute)
+ needToResolve = moveAttribute(aMovedAttribute, aMovedPoint, aFrom, aTo);
} else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED)) {
std::shared_ptr<ModelAPI_ObjectDeletedMessage> aDeleteMsg =
// Purpose: move given attribute in appropriate group
// ============================================================================
bool SketchSolver_Manager::moveAttribute(
- const std::shared_ptr<GeomDataAPI_Point2D>& theMovedAttribute,
+ const std::shared_ptr<ModelAPI_Attribute>& theMovedAttribute,
+ const int theMovedPointIndex,
const std::shared_ptr<GeomAPI_Pnt2d>& theFrom,
const std::shared_ptr<GeomAPI_Pnt2d>& theTo)
{
std::dynamic_pointer_cast<SketchPlugin_Constraint>(anOwner);
if (aConstraint)
{
- theMovedAttribute->setValue(theTo);
+ setPoint(theMovedAttribute, theMovedPointIndex, theTo);
Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
return true;
}
if (aSketchFeature)
aGroup = findGroup(aSketchFeature);
if (!aGroup) {
- theMovedAttribute->setValue(theTo);
+ setPoint(theMovedAttribute, theMovedPointIndex, theTo);
return false;
}
aGroup->blockEvents(true);
- return aGroup->movePoint(theMovedAttribute, theFrom, theTo);
+ return aGroup->movePoint(theMovedAttribute, theMovedPointIndex, theFrom, theTo);
}
// ============================================================================
const std::shared_ptr<GeomAPI_Pnt2d>& theToPoint);
/** \brief Move feature using its moved attribute
- * \param[in] theMovedAttribute dragged point attribute of sketch feature
- * \param[in] theFromPoint original position of the moved point
- * \param[in] theToPoint prefereble position (current position of the mouse)
+ * \param[in] theMovedAttribute dragged point (array of points) attribute of sketch feature
+ * \param[in] theMovedPointIndex index of dragged point in an array (-1 otherwise)
+ * \param[in] theFromPoint original position of the moved point
+ * \param[in] theToPoint prefereble position (current position of the mouse)
* \return \c true if the attribute owner has been changed successfully
*/
- bool moveAttribute(const std::shared_ptr<GeomDataAPI_Point2D>& theMovedAttribute,
+ bool moveAttribute(const std::shared_ptr<ModelAPI_Attribute>& theMovedAttribute,
+ const int theMovedPointIndex,
const std::shared_ptr<GeomAPI_Pnt2d>& theFromPoint,
const std::shared_ptr<GeomAPI_Pnt2d>& theToPoint);
QString aXmlRepr = anOperation->getDescription()->xmlRepresentation();
ModuleBase_WidgetFactory aFactory(aXmlRepr.toStdString(), myOperationMgr->workshop());
- aFactory.createPanel(contentWidget(), theFeature);
- /// Apply button should be update if the feature was modified by the panel
+ ModuleBase_PageBase* aPage = contentWidget();
+ aFactory.createPanel(aPage, theFeature);
+ // update model widgets if exist
+ setModelWidgets(aPage->modelWidgets());
+ // Apply button should be update if the feature was modified by the panel
myOperationMgr->onValidateOperation();
}
ModuleBase_OperationFeature* aFeatureOp =