diff --git a/src/Mod/Surface/App/AppSurface.cpp b/src/Mod/Surface/App/AppSurface.cpp
index 149ace3c93..773c2b3924 100644
--- a/src/Mod/Surface/App/AppSurface.cpp
+++ b/src/Mod/Surface/App/AppSurface.cpp
@@ -30,6 +30,9 @@
#include "FeatureGeomFillSurface.h"
#include "FeatureExtend.h"
#include "FeatureSections.h"
+#include "Blending/BlendPointPy.h"
+#include "Blending/BlendCurvePy.h"
+#include "Blending/FeatureBlendCurve.h"
#include
#include
@@ -78,6 +81,9 @@ PyMOD_INIT_FUNC(Surface)
Surface::GeomFillSurface ::init();
Surface::Extend ::init();
Surface::Sections ::init();
+ Surface::BlendPoint ::init();
+ Surface::BlendCurve ::init();
+ Surface::FeatureBlendCurve ::init();
PyMOD_Return(mod);
}
diff --git a/src/Mod/Surface/App/Blending/BlendCurve.cpp b/src/Mod/Surface/App/Blending/BlendCurve.cpp
new file mode 100644
index 0000000000..c3b7e12bdb
--- /dev/null
+++ b/src/Mod/Surface/App/Blending/BlendCurve.cpp
@@ -0,0 +1,171 @@
+/***************************************************************************
+ * Copyright (c) 2022 Matteo Grellier *
+ * *
+ * *
+ * This file is part of the FreeCAD CAx development system. *
+ * *
+ * This library is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Library General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2 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 Library General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Library General Public *
+ * License along with this library; see the file COPYING.LIB. If not, *
+ * write to the Free Software Foundation, Inc., 59 Temple Place, *
+ * Suite 330, Boston, MA 02111-1307, USA *
+ * *
+ ***************************************************************************/
+
+#include "PreCompiled.h"
+#ifndef _PreComp_
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#endif
+#include
+#include
+#include "Blending/BlendCurve.h"
+#include "Blending/BlendCurvePy.h"
+
+using namespace Surface;
+
+BlendCurve::BlendCurve()
+{
+}
+
+BlendCurve::BlendCurve(std::vector blendPointsList)
+{
+ // Retrieve number of blendPoints and push them into blendPoints.
+ int nb_pts = blendPointsList.size();
+
+ if (nb_pts > 2) {
+ throw Base::ValueError("Not implemented");
+ }
+ else if (nb_pts < 2) {
+ throw Base::ValueError("Need two points for working");
+ }
+ blendPoints = blendPointsList;
+}
+
+BlendCurve::~BlendCurve()
+{
+}
+
+Handle(Geom_BezierCurve) BlendCurve::compute()
+{
+ int nb_pts = blendPoints.size();
+ try {
+ // Uniform Parametrization
+ TColStd_Array1OfReal params(1, nb_pts);
+ for (int i = 0; i < nb_pts; ++i) {
+ params(i + 1) = (double)i / ((double)nb_pts - 1);
+ }
+
+ int num_poles = 0;
+ for (int i = 0; i < nb_pts; ++i) {
+ num_poles += blendPoints[i].nbVectors();
+ }
+
+ Handle(Geom_BezierCurve) curve;
+ if (num_poles > (curve->MaxDegree()+1))// use Geom_BezierCurve max degree
+ Standard_Failure::Raise("number of constraints exceeds bezier curve capacity");
+
+ TColStd_Array1OfReal knots(1, 2 * num_poles);
+ for (int i = 1; i <= num_poles; ++i) {
+ knots(i) = params(1);
+ knots(num_poles + i) = params(nb_pts);
+ }
+
+ math_Matrix OCCmatrix(1, num_poles, 1, num_poles, 0.0);
+ math_Vector res_x(1, num_poles, 0.0);
+ math_Vector res_y(1, num_poles, 0.0);
+ math_Vector res_z(1, num_poles, 0.0);
+ int row_idx = 1;
+ int cons_idx = 1;
+ for (int i = 0; i < nb_pts; ++i) {
+ math_Matrix bezier_eval(1, blendPoints[i].nbVectors(), 1, num_poles, 0.0);
+ Standard_Integer first_non_zero;
+ BSplCLib::EvalBsplineBasis(blendPoints[i].nbVectors() - 1, num_poles, knots, params(cons_idx), first_non_zero, bezier_eval, Standard_False);
+ int idx2 = 1;
+ for (int it2 = 0; it2 < blendPoints[i].nbVectors(); ++it2) {
+ OCCmatrix.SetRow(row_idx, bezier_eval.Row(idx2));
+ Base::Vector3d pnt = blendPoints[i].vectors[it2];
+ res_x(row_idx) = pnt.x;
+ res_y(row_idx) = pnt.y;
+ res_z(row_idx) = pnt.z;
+ idx2++;
+ row_idx++;
+ }
+ cons_idx++;
+ }
+ math_Gauss gauss(OCCmatrix);
+ gauss.Solve(res_x);
+ if (!gauss.IsDone())
+ Standard_Failure::Raise("Failed to solve equations");
+ gauss.Solve(res_y);
+ if (!gauss.IsDone())
+ Standard_Failure::Raise("Failed to solve equations");
+ gauss.Solve(res_z);
+ if (!gauss.IsDone())
+ Standard_Failure::Raise("Failed to solve equations");
+
+ TColgp_Array1OfPnt poles(1, num_poles);
+ for (int idx = 1; idx <= num_poles; ++idx) {
+ poles.SetValue(idx, gp_Pnt(res_x(idx), res_y(idx), res_z(idx)));
+ }
+ Handle(Geom_BezierCurve) bezier = new Geom_BezierCurve(poles);
+ return bezier;
+ }
+
+ catch (Standard_Failure &e) {
+ PyErr_SetString(PyExc_Exception, "Failed to compute bezier curve");
+ }
+ return nullptr;
+}
+
+void BlendCurve::setSize(int i, double f, bool relative)
+{
+ double size = f;
+ try {
+ if (relative) {
+ double nb_poles = blendPoints.front().nbVectors() + blendPoints[1].nbVectors();
+ Base::Vector3d diff = blendPoints[1].vectors[0] - blendPoints[0].vectors[0];
+ size = size * diff.Length() / nb_poles;
+ }
+ blendPoints[i].setSize(size);
+ }
+ catch (Standard_Failure &e) {
+ PyErr_SetString(PyExc_Exception, e.GetMessageString());
+ }
+}
+
+unsigned int BlendCurve::getMemSize(void) const
+{
+ return 1;
+}
+
+PyObject *BlendCurve::getPyObject(void)
+{
+ return new BlendCurvePy(new BlendCurve(blendPoints));
+}
+
+void BlendCurve::Save(Base::Writer & /*writer*/) const
+{
+ throw Base::NotImplementedError("BlendCurve::Save");
+}
+
+void BlendCurve::Restore(Base::XMLReader & /*reader*/)
+{
+ throw Base::NotImplementedError("BlendCurve::Restore");
+}
diff --git a/src/Mod/Surface/App/Blending/BlendCurve.h b/src/Mod/Surface/App/Blending/BlendCurve.h
new file mode 100644
index 0000000000..5e75e0ca8f
--- /dev/null
+++ b/src/Mod/Surface/App/Blending/BlendCurve.h
@@ -0,0 +1,76 @@
+/***************************************************************************
+ * Copyright (c) 2022 Matteo Grellier *
+ * *
+ * This file is part of the FreeCAD CAx development system. *
+ * *
+ * This library is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Library General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2 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 Library General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Library General Public *
+ * License along with this library; see the file COPYING.LIB. If not, *
+ * write to the Free Software Foundation, Inc., 59 Temple Place, *
+ * Suite 330, Boston, MA 02111-1307, USA *
+ * *
+ ***************************************************************************/
+
+#ifndef BLEND_CURVE_H
+#define BLEND_CURVE_H
+#include
+// #include
+// #include
+// #include
+// #include
+// #include
+// #include
+#include
+#include
+
+namespace Surface
+{
+/*!
+* Create a BezierCurve interpolating a list of BlendPoints
+*/
+class SurfaceExport BlendCurve: public Base::Persistence
+{
+public:
+
+ std::vector blendPoints;
+
+ BlendCurve();
+ /*!
+ * Constructor
+ *\param std::vector
+ */
+ BlendCurve(std::vector blendPointsList);
+ virtual ~BlendCurve();
+ /*!
+ * Perform the interpolate algorithm
+ *\return the BezierCurve
+ */
+ Handle(Geom_BezierCurve) compute();
+ /*!
+ * Set the size of the first derivative of a BlendPoint
+ *\param int index of the BlendPoint to modify
+ *\param double new size
+ *\param bool interpret new size relative to chordlength
+ */
+ void setSize(int, double, bool);
+
+ virtual PyObject *getPyObject(void);
+ // Persistence implementer ---------------------
+ virtual unsigned int getMemSize(void) const;
+ virtual void Save(Base::Writer & /*writer*/) const;
+ virtual void Restore(Base::XMLReader & /*reader*/);
+
+};
+}// namespace Surface
+
+#endif
+
diff --git a/src/Mod/Surface/App/Blending/BlendCurvePy.xml b/src/Mod/Surface/App/Blending/BlendCurvePy.xml
new file mode 100644
index 0000000000..12cf9293c5
--- /dev/null
+++ b/src/Mod/Surface/App/Blending/BlendCurvePy.xml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+ Create a BlendCurve that interpolate a list of BlendPoints.
+ curve = BlendCurve([BlendPoint1, BlendPoint2])
+ curve = BlendCurve(BlendPoint1, BlendPoint2)
+
+
+
+
+
+ Return the BezierCurve that interpolate the input BlendPoints.
+
+
+
+
+
+
+ Set the tangent size of the blendpoint at given index.
+ If relative is true, the size is considered relative to the distance between the two blendpoints.
+ myBlendCurve.setSize(idx, size, relative)
+
+
+
+
+
diff --git a/src/Mod/Surface/App/Blending/BlendCurvePyImp.cpp b/src/Mod/Surface/App/Blending/BlendCurvePyImp.cpp
new file mode 100644
index 0000000000..5d169ece5e
--- /dev/null
+++ b/src/Mod/Surface/App/Blending/BlendCurvePyImp.cpp
@@ -0,0 +1,119 @@
+///***************************************************************************
+// * Copyright (c) 2022 Matteo Grellier *
+// * *
+// * This file is part of the FreeCAD CAx development system. *
+// * *
+// * This library is free software; you can redistribute it and/or *
+// * modify it under the terms of the GNU Library General Public *
+// * License as published by the Free Software Foundation; either *
+// * version 2 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 Library General Public License for more details. *
+// * *
+// * You should have received a copy of the GNU Library General Public *
+// * License along with this library; see the file COPYING.LIB. If not, *
+// * write to the Free Software Foundation, Inc., 59 Temple Place, *
+// * Suite 330, Boston, MA 02111-1307, USA *
+// * *
+// ***************************************************************************/
+
+#include "PreCompiled.h"
+#ifndef _PreComp_
+#include
+#include
+#endif
+#include "Blending/BlendCurvePy.h"
+#include "Blending/BlendPointPy.h"
+// #include "Mod/Part/App/Geometry.h"
+// #include
+#include
+#include
+#include "Blending/BlendCurvePy.cpp"
+
+using namespace Surface;
+
+std::string BlendCurvePy::representation(void) const
+{
+ return "BlendCurve";
+}
+
+PyObject *BlendCurvePy::PyMake(struct _typeobject *, PyObject *, PyObject *)// Python wrapper
+{
+ // create a new instance of BlendCurvePy
+ return new BlendCurvePy(new BlendCurve);
+}
+
+int BlendCurvePy::PyInit(PyObject *args, PyObject * /*kwds*/)
+{
+ PyObject *plist;
+ if (PyArg_ParseTuple(args, "O", &plist)) {
+ Py::Sequence list(plist);
+ if (list.size() != 2) {
+ PyErr_SetString(PyExc_TypeError, "Currently BlendCurve need exactly 2 BlendPoints");
+ return -1;
+ }
+ std::vector bpList;
+ for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
+ Py::Object obj(*it);
+ if (PyObject_TypeCheck(obj.ptr(), &BlendPointPy::Type)) {
+ BlendPoint *geom = static_cast(obj.ptr())->getBlendPointPtr();
+ bpList.emplace_back(*geom);
+ }
+ }
+ this->getBlendCurvePtr()->blendPoints = bpList;
+ return 0;
+ }
+
+ PyErr_Clear();
+ PyObject *b1;
+ PyObject *b2;
+ std::vector bpList;
+
+ if (PyArg_ParseTuple(args, "O!O!", &(Surface::BlendPointPy::Type), &b1, &(Surface::BlendPointPy::Type), &b2)) {
+ BlendPoint *geom1 = static_cast(b1)->getBlendPointPtr();
+ BlendPoint *geom2 = static_cast(b2)->getBlendPointPtr();
+ bpList.emplace_back(*geom1);
+ bpList.emplace_back(*geom2);
+ this->getBlendCurvePtr()->blendPoints = bpList;
+ return 0;
+ }
+ return -1;
+}
+PyObject *BlendCurvePy::compute(PyObject * /*args*/)
+{
+ BlendCurve *bc = getBlendCurvePtr();
+ Handle(Geom_BezierCurve) gc = bc->compute();
+ return new Part::BezierCurvePy(new Part::GeomBezierCurve(gc));
+}
+
+
+PyObject *BlendCurvePy::setSize(PyObject *args)
+{
+ int i;
+ double size;
+ PyObject* relative = Py_True;
+ if (!PyArg_ParseTuple(args, "idO!", &i, &size, &PyBool_Type, &relative)) {
+ return nullptr;
+ }
+ try {
+ getBlendCurvePtr()->setSize(i, size, Base::asBoolean(relative));
+ }
+ catch (Standard_Failure &e) {
+ PyErr_SetString(PyExc_Exception, e.GetMessageString());
+ return nullptr;
+ }
+ Py_Return;
+}
+
+PyObject *BlendCurvePy::getCustomAttributes(const char * /*attr*/) const
+{
+ return nullptr;
+}
+
+int BlendCurvePy::setCustomAttributes(const char * /*attr*/, PyObject * /*obj*/)
+{
+ return 0;
+}
diff --git a/src/Mod/Surface/App/Blending/BlendPoint.cpp b/src/Mod/Surface/App/Blending/BlendPoint.cpp
new file mode 100644
index 0000000000..1d0ee30c16
--- /dev/null
+++ b/src/Mod/Surface/App/Blending/BlendPoint.cpp
@@ -0,0 +1,101 @@
+/***************************************************************************
+ * Copyright (c) 2022 Matteo Grellier *
+ * *
+ * *
+ * This file is part of the FreeCAD CAx development system. *
+ * *
+ * This library is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Library General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2 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 Library General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Library General Public *
+ * License along with this library; see the file COPYING.LIB. If not, *
+ * write to the Free Software Foundation, Inc., 59 Temple Place, *
+ * Suite 330, Boston, MA 02111-1307, USA *
+ * *
+ ***************************************************************************/
+
+#include "PreCompiled.h"
+#ifndef _PreComp_
+#include
+#include
+#include
+#include
+#include
+#include
+#endif
+#include "Blending/BlendPoint.h"
+#include "Blending/BlendPointPy.h"
+
+
+using namespace Surface;
+
+BlendPoint::BlendPoint(std::vector vectorList)
+{
+ for (size_t i = 0; i < vectorList.size(); i++) {
+ vectors.emplace_back(vectorList[i]);
+ }
+}
+
+BlendPoint::BlendPoint()
+{
+ vectors.emplace_back(Base::Vector3d(0, 0, 0));
+}
+
+BlendPoint::~BlendPoint()
+{
+}
+
+void BlendPoint::multiply(double f)
+{
+ for (int i = 0; i < nbVectors(); i++) {
+ vectors[i] *= Pow(f, i);
+ }
+}
+
+void BlendPoint::setSize(double f)
+{
+ if (nbVectors() > 1) {
+ double il = vectors[1].Length();
+ if (il > Precision::Confusion()) {
+ multiply(f / il);
+ }
+ }
+}
+
+int BlendPoint::getContinuity()
+{
+ return vectors.size() - 1;
+}
+
+int BlendPoint::nbVectors()
+{
+ return vectors.size();
+}
+
+PyObject *BlendPoint::getPyObject(void)
+{
+ return new BlendPointPy(new BlendPoint(vectors));
+}
+
+void BlendPoint::Save(Base::Writer & /*writer*/) const
+{
+ throw Base::NotImplementedError("BlendPoint::Save");
+}
+
+void BlendPoint::Restore(Base::XMLReader & /*reader*/)
+{
+ throw Base::NotImplementedError("BlendPoint::Restore");
+}
+
+unsigned int BlendPoint::getMemSize(void) const
+{
+ // do we need to loop on the vectors list ?
+ return sizeof(vectors) * sizeof(vectors.front());
+}
diff --git a/src/Mod/Surface/App/Blending/BlendPoint.h b/src/Mod/Surface/App/Blending/BlendPoint.h
new file mode 100644
index 0000000000..c555521c4d
--- /dev/null
+++ b/src/Mod/Surface/App/Blending/BlendPoint.h
@@ -0,0 +1,83 @@
+/***************************************************************************
+ * Copyright (c) 2014 Matteo Grellier *
+ * *
+ * This file is part of the FreeCAD CAx development system. *
+ * *
+ * This library is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Library General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2 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 Library General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Library General Public *
+ * License along with this library; see the file COPYING.LIB. If not, *
+ * write to the Free Software Foundation, Inc., 59 Temple Place, *
+ * Suite 330, Boston, MA 02111-1307, USA *
+ * *
+ ***************************************************************************/
+
+#ifndef BLEND_POINT_H
+#define BLEND_POINT_H
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+namespace Surface
+{
+
+/*!
+* Create a list of vectors formed by a point and some derivatives
+* obtained from a curve or surface
+*/
+class SurfaceExport BlendPoint: public Base::Persistence
+{
+public:
+ std::vector vectors;
+ BlendPoint();
+ /*!
+ * Constructor
+ *\param std::vector
+ */
+ BlendPoint(std::vector vectorList);
+ virtual ~BlendPoint();
+ /*!
+ * Scale the blendpoint vectors
+ *\param double scaling factor
+ */
+ void multiply(double f);
+ /*!
+ * Resize the blendpoint vectors
+ * by setting the size of the first derivative
+ *\param double new size
+ */
+ void setSize(double f);
+ /*!
+ *\return continuity of this BlendPoint
+ */
+ int getContinuity();
+ /*!
+ *\return Number of vectors of this BlendPoint
+ */
+ int nbVectors();
+ virtual PyObject *getPyObject(void);
+ // Persistence implementer ---------------------
+ virtual unsigned int getMemSize(void) const;
+ virtual void Save(Base::Writer & /*writer*/) const;
+ virtual void Restore(Base::XMLReader & /*reader*/);
+
+private:
+};
+}// namespace Surface
+
+#endif
+
diff --git a/src/Mod/Surface/App/Blending/BlendPointPy.xml b/src/Mod/Surface/App/Blending/BlendPointPy.xml
new file mode 100644
index 0000000000..c3ec282eec
--- /dev/null
+++ b/src/Mod/Surface/App/Blending/BlendPointPy.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+ Create BlendPoint from a point and some derivatives.
+ myBlendPoint = BlendPoint([Point, D1, D2, ..., DN])
+ BlendPoint can also be constructed from an edge
+ myBlendPoint = BlendPoint(Edge, parameter = float, continuity = int)
+
+
+
+
+ The list of vectors of this BlendPoint.
+
+
+
+
+
+
+ Return BlendPoint first derivative length.
+
+
+
+
+
+
+ Resizes the BlendPoint vectors,
+ by setting the lenght of the first derivative.
+ theBlendPoint.setSize(new_size)
+
+
+
+
+
+
+ Set the vectors of BlendPoint.
+ BlendPoint.setvectors([Point, D1, D2, ..., DN])
+
+
+
+
+
diff --git a/src/Mod/Surface/App/Blending/BlendPointPyImp.cpp b/src/Mod/Surface/App/Blending/BlendPointPyImp.cpp
new file mode 100644
index 0000000000..b9e7d88adc
--- /dev/null
+++ b/src/Mod/Surface/App/Blending/BlendPointPyImp.cpp
@@ -0,0 +1,194 @@
+///***************************************************************************
+// * Copyright (c) 2022 Matteo Grellier *
+// * *
+// * This file is part of the FreeCAD CAx development system. *
+// * *
+// * This library is free software; you can redistribute it and/or *
+// * modify it under the terms of the GNU Library General Public *
+// * License as published by the Free Software Foundation; either *
+// * version 2 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 Library General Public License for more details. *
+// * *
+// * You should have received a copy of the GNU Library General Public *
+// * License along with this library; see the file COPYING.LIB. If not, *
+// * write to the Free Software Foundation, Inc., 59 Temple Place, *
+// * Suite 330, Boston, MA 02111-1307, USA *
+// * *
+// ***************************************************************************/
+
+#include "PreCompiled.h"
+#ifndef _PreComp_
+#include
+#include
+#include
+#include
+#endif
+#include
+#include
+#include
+#include "Blending/BlendPoint.h"
+#include "Blending/BlendPointPy.h"
+#include "Blending/BlendPointPy.cpp"
+
+using namespace Surface;
+
+std::string BlendPointPy::representation(void) const
+{
+ Base::Vector3d bp = getBlendPointPtr()->vectors[0];
+ std::stringstream str;
+ str << "G" << getBlendPointPtr()->getContinuity()
+ << " BlendPoint at (" << bp.x << ", " << bp.y << ", " << bp.z << "), ";
+ return str.str();
+}
+
+PyObject *BlendPointPy::PyMake(struct _typeobject *, PyObject *, PyObject *)// Python wrapper
+{
+ // create a new instance of BlendPointPy
+ return new BlendPointPy(new BlendPoint);
+}
+
+int BlendPointPy::PyInit(PyObject* args, PyObject*)
+{
+ PyObject *plist;
+ std::vector vecs;
+ if (PyArg_ParseTuple(args, "O", &plist)) {
+ Py::Sequence list(plist);
+ if (list.size() == 0) {
+ vecs.emplace_back(Base::Vector3d(0, 0, 0));
+ }
+ else {
+ for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
+ Py::Vector v(*it);
+ Base::Vector3d vec = v.toVector();
+ vecs.emplace_back(vec);
+ }
+ }
+ this->getBlendPointPtr()->vectors = vecs;
+ return 0;
+ }
+
+ PyErr_Clear();
+ if (PyArg_ParseTuple(args, "")) {
+ vecs.emplace_back(Base::Vector3d(0, 0, 0));
+ this->getBlendPointPtr()->vectors = vecs;
+ return 0;
+ }
+
+ double param;
+ int cont;
+ PyObject *pcObj;
+ PyErr_Clear();
+ // Create a curve with an edge, parameter and continiuity.
+ if (PyArg_ParseTuple(args, "O!di", &(Part::TopoShapePy::Type), &pcObj, ¶m, &cont)) {
+ try {
+ gp_Pnt Pt;
+ TopoDS_Shape shape = static_cast(pcObj)->getTopoShapePtr()->getShape();
+ const TopoDS_Edge &e = TopoDS::Edge(shape);
+ BRepAdaptor_Curve adapt(e);
+
+ adapt.D0(param, Pt);
+ Base::Vector3d bv(Pt.X(), Pt.Y(), Pt.Z());
+ vecs.emplace_back(bv);
+
+ for (int i = 1; i <= cont; i++) {
+ gp_Vec v1 = adapt.DN(param, i);
+ Base::Vector3d bbv1(v1.X(), v1.Y(), v1.Z());
+ vecs.emplace_back(bbv1);
+ }
+ this->getBlendPointPtr()->vectors = vecs;
+ return 0;
+ }
+ catch (const std::exception &e) {
+ std::cerr << e.what() << '\n';
+ return -1;
+ }
+ }
+ return -1;
+}
+
+PyObject *BlendPointPy::setSize(PyObject *args)
+{
+ double size = 1.0;
+
+ if (!PyArg_ParseTuple(args, "d", &size))
+ return nullptr;
+ try {
+ getBlendPointPtr()->setSize(size);
+ Py_Return;
+ }
+ catch (Standard_Failure &e) {
+ PyErr_SetString(PyExc_Exception, "Failed to set size");
+ return nullptr;
+ }
+}
+
+PyObject *BlendPointPy::getSize(PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, ""))
+ return nullptr;
+ int nb = getBlendPointPtr()->nbVectors();
+ if (nb >= 2) {
+ double bpTangentLength = getBlendPointPtr()->vectors[1].Length();
+ return Py_BuildValue("d", bpTangentLength);
+ }
+ return nullptr;
+}
+
+Py::List BlendPointPy::getVectors() const
+{
+ try {
+ BlendPoint *bp = getBlendPointPtr();
+ std::vector p = bp->vectors;
+ Py::List vecs;
+ for (size_t i = 0; i < p.size(); i++) {
+ Base::VectorPy *vec = new Base::VectorPy(Base::Vector3d(
+ p[i].x, p[i].y, p[i].z));
+ vecs.append(Py::asObject(vec));
+ }
+ return vecs;
+ }
+ catch (Standard_Failure &e) {
+ PyErr_SetString(PyExc_RuntimeError,
+ e.GetMessageString());
+ return Py::List();
+ }
+}
+
+PyObject *BlendPointPy::setvectors(PyObject *args)
+{
+ BlendPoint *bp = getBlendPointPtr();
+ PyObject *plist;
+ if (!PyArg_ParseTuple(args, "O", &plist)) {
+ PyErr_SetString(PyExc_TypeError, "List of vectors required.");
+ return nullptr;
+ }
+ try {
+ Py::Sequence list(plist);
+ std::vector vecs;
+ for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
+ Py::Vector v(*it);
+ Base::Vector3d pole = v.toVector();
+ vecs.emplace_back(pole);
+ }
+ bp->vectors = vecs;
+ Py_Return;
+ }
+ catch (Standard_Failure &e) {
+ PyErr_SetString(PyExc_RuntimeError, e.GetMessageString());
+ }
+ return nullptr;
+}
+
+PyObject *BlendPointPy::getCustomAttributes(const char * /*attr*/) const
+{
+ return nullptr;
+}
+
+int BlendPointPy::setCustomAttributes(const char * /*attr*/, PyObject * /*obj*/)
+{
+ return 0;
+}
diff --git a/src/Mod/Surface/App/Blending/FeatureBlendCurve.cpp b/src/Mod/Surface/App/Blending/FeatureBlendCurve.cpp
new file mode 100644
index 0000000000..2510d39cf9
--- /dev/null
+++ b/src/Mod/Surface/App/Blending/FeatureBlendCurve.cpp
@@ -0,0 +1,181 @@
+/***************************************************************************
+ * Copyright (c) 2022 Matteo Grellier *
+ * *
+ * *
+ * This file is part of the FreeCAD CAx development system. *
+ * *
+ * This library is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Library General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2 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 Library General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Library General Public *
+ * License along with this library; see the file COPYING.LIB. If not, *
+ * write to the Free Software Foundation, Inc., 59 Temple Place, *
+ * Suite 330, Boston, MA 02111-1307, USA *
+ * *
+ ***************************************************************************/
+
+#include "PreCompiled.h"
+#ifndef _PreComp_
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#endif
+#include "FeatureBlendCurve.h"
+#include "Mod/Surface/App/Blending/BlendCurve.h"
+#include "Mod/Surface/App/Blending/BlendPoint.h"
+
+using namespace Surface;
+
+const App::PropertyFloatConstraint::Constraints StartParameterConstraint = {0.0, 1.0, 0.05};
+const App::PropertyFloatConstraint::Constraints EndParameterConstraint = {0.0, 1.0, 0.05};
+const App::PropertyIntegerConstraint::Constraints StartContinuityConstraint = {0, 25, 1};
+const App::PropertyIntegerConstraint::Constraints EndContinuityConstraint = {0, 25, 1};
+
+PROPERTY_SOURCE(Surface::FeatureBlendCurve, Part::Spline)
+
+FeatureBlendCurve::FeatureBlendCurve() : lockOnChangeMutex(false)
+{
+ ADD_PROPERTY_TYPE(StartEdge, (nullptr), "FirstEdge", App::Prop_None, "");
+ ADD_PROPERTY_TYPE(StartContinuity, (2), "FirstEdge", App::Prop_None, "");
+ StartContinuity.setConstraints(&StartContinuityConstraint);
+ ADD_PROPERTY_TYPE(StartParameter, (0.0f), "FirstEdge", App::Prop_None, "");
+ StartParameter.setConstraints(&StartParameterConstraint);
+ ADD_PROPERTY_TYPE(StartSize, (1.0f), "FirstEdge", App::Prop_None, "");
+
+ ADD_PROPERTY_TYPE(EndEdge, (nullptr), "SecondEdge", App::Prop_None, "");
+ ADD_PROPERTY_TYPE(EndContinuity, (2), "SecondEdge", App::Prop_None, "");
+ EndContinuity.setConstraints(&EndContinuityConstraint);
+ ADD_PROPERTY_TYPE(EndParameter, (0.0f), "SecondEdge", App::Prop_None, "");
+ EndParameter.setConstraints(&EndParameterConstraint);
+ ADD_PROPERTY_TYPE(EndSize, (1.0f), "SecondEdge", App::Prop_None, "");
+ Handle(Geom_BezierCurve) maxDegreeCurve;
+ maxDegree = maxDegreeCurve->MaxDegree();
+}
+
+short FeatureBlendCurve::mustExecute() const
+{
+ if (StartEdge.isTouched())
+ return 1;
+ if (StartParameter.isTouched())
+ return 1;
+ if (StartContinuity.isTouched())
+ return 1;
+ if (StartSize.isTouched())
+ return 1;
+ if (EndEdge.isTouched())
+ return 1;
+ if (EndParameter.isTouched())
+ return 1;
+ if (EndContinuity.isTouched())
+ return 1;
+ if (EndSize.isTouched())
+ return 1;
+ return 0;
+}
+
+BlendPoint FeatureBlendCurve::GetBlendPoint(App::PropertyLinkSub &link, App::PropertyFloatConstraint ¶m, App::PropertyIntegerConstraint &continuity)
+{
+ auto linked = link.getValue();
+
+ TopoDS_Shape axEdge;
+ if (link.getSubValues().size() > 0 && link.getSubValues()[0].length() > 0) {
+ axEdge = Feature::getTopoShape(linked, link.getSubValues()[0].c_str(), true /*need element*/).getShape();
+ }
+ else {
+ axEdge = Feature::getShape(linked);
+ }
+
+ if (axEdge.IsNull())
+ throw Base::ValueError("DirLink shape is null");
+ if (axEdge.ShapeType() != TopAbs_EDGE)
+ throw Base::TypeError("DirLink shape is not an edge");
+ const TopoDS_Edge &e = TopoDS::Edge(axEdge);
+ BRepAdaptor_Curve adapt(e);
+ double fp = adapt.FirstParameter();
+ double lp = adapt.LastParameter();
+
+ double RealPar = RelativeToRealParameters(param.getValue(), fp, lp);
+
+ std::vector constraints;
+ gp_Pnt Pt;
+
+ adapt.D0(RealPar, Pt);
+ Base::Vector3d bv(Pt.X(), Pt.Y(), Pt.Z());
+ constraints.emplace_back(bv);
+
+ for (int i = 1; i <= continuity.getValue(); i++) {
+ gp_Vec v1 = adapt.DN(RealPar, i);
+ Base::Vector3d bbv1(v1.X(), v1.Y(), v1.Z());
+ constraints.emplace_back(bbv1);
+ }
+
+ BlendPoint bp(constraints);
+
+ return bp;
+}
+
+App::DocumentObjectExecReturn *FeatureBlendCurve::execute(void)
+{
+
+ BlendPoint bp1 = GetBlendPoint(StartEdge, StartParameter, StartContinuity);
+ BlendPoint bp2 = GetBlendPoint(EndEdge, EndParameter, EndContinuity);
+
+ std::vector blendPointsList;
+
+ blendPointsList.emplace_back(bp1);
+ blendPointsList.emplace_back(bp2);
+
+ BlendCurve curve(blendPointsList);
+ curve.setSize(0, StartSize.getValue(), true);
+ curve.setSize(1, EndSize.getValue(), true);
+
+ Handle(Geom_BezierCurve) bc(curve.compute());
+ BRepBuilderAPI_MakeEdge mkEdge(bc);
+
+ Shape.setValue(mkEdge.Edge());
+
+ return StdReturn;
+}
+
+double FeatureBlendCurve::RelativeToRealParameters(double relativeValue, double fp, double lp)
+{
+ return fp + relativeValue * (lp - fp);
+}
+
+
+void FeatureBlendCurve::onChanged(const App::Property *prop)
+{
+ // using a mutex and lock to protect a recursive calling when setting the new values
+ if (lockOnChangeMutex)
+ return;
+ Base::StateLocker lock(lockOnChangeMutex);
+
+ if (prop == &StartContinuity) {
+ auto changedStartProp = dynamic_cast(prop);
+
+ if (changedStartProp->getValue() > (maxDegree - 2 - EndContinuity.getValue())) {
+
+ StartContinuity.setValue(maxDegree - 2 - EndContinuity.getValue());
+ }
+ }
+ else if (prop == &EndContinuity) {
+ auto changedEndProp = dynamic_cast(prop);
+
+ if (changedEndProp->getValue() > (maxDegree - 2 - StartContinuity.getValue())) {
+ EndContinuity.setValue(maxDegree - 2 - StartContinuity.getValue());
+ }
+ }
+ Part::Spline::onChanged(prop);
+}
diff --git a/src/Mod/Surface/App/CMakeLists.txt b/src/Mod/Surface/App/CMakeLists.txt
index df574bca63..9d332f7eb9 100644
--- a/src/Mod/Surface/App/CMakeLists.txt
+++ b/src/Mod/Surface/App/CMakeLists.txt
@@ -16,6 +16,23 @@ set(Surface_LIBS
Part
)
+SET(BlendingPy_SRCS
+ Blending/BlendPointPy.xml
+ Blending/BlendPointPyImp.cpp
+ Blending/BlendCurvePy.xml
+ Blending/BlendCurvePyImp.cpp
+)
+SOURCE_GROUP("Blending" FILES ${BlendingPy_SRCS})
+
+SET(Blending_SRCS
+ Blending/FeatureBlendCurve.cpp
+ Blending/FeatureBlendCurve.h
+ Blending/BlendPoint.cpp
+ Blending/BlendPoint.h
+ Blending/BlendCurve.cpp
+ Blending/BlendCurve.h
+)
+
SET(Surface_SRCS
AppSurface.cpp
PreCompiled.cpp