From 6ec601dade3a2fd08c6706cb76153efa833d7976 Mon Sep 17 00:00:00 2001 From: tomate44 Date: Thu, 18 Aug 2022 14:58:05 +0200 Subject: [PATCH] Surface: Various fixes --- src/Mod/Surface/App/AppSurface.cpp | 6 + src/Mod/Surface/App/Blending/BlendCurve.cpp | 171 +++++++++++++++ src/Mod/Surface/App/Blending/BlendCurve.h | 76 +++++++ src/Mod/Surface/App/Blending/BlendCurvePy.xml | 42 ++++ .../Surface/App/Blending/BlendCurvePyImp.cpp | 119 +++++++++++ src/Mod/Surface/App/Blending/BlendPoint.cpp | 101 +++++++++ src/Mod/Surface/App/Blending/BlendPoint.h | 83 ++++++++ src/Mod/Surface/App/Blending/BlendPointPy.xml | 57 +++++ .../Surface/App/Blending/BlendPointPyImp.cpp | 194 ++++++++++++++++++ .../App/Blending/FeatureBlendCurve.cpp | 181 ++++++++++++++++ src/Mod/Surface/App/CMakeLists.txt | 17 ++ 11 files changed, 1047 insertions(+) create mode 100644 src/Mod/Surface/App/Blending/BlendCurve.cpp create mode 100644 src/Mod/Surface/App/Blending/BlendCurve.h create mode 100644 src/Mod/Surface/App/Blending/BlendCurvePy.xml create mode 100644 src/Mod/Surface/App/Blending/BlendCurvePyImp.cpp create mode 100644 src/Mod/Surface/App/Blending/BlendPoint.cpp create mode 100644 src/Mod/Surface/App/Blending/BlendPoint.h create mode 100644 src/Mod/Surface/App/Blending/BlendPointPy.xml create mode 100644 src/Mod/Surface/App/Blending/BlendPointPyImp.cpp create mode 100644 src/Mod/Surface/App/Blending/FeatureBlendCurve.cpp 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