From 9252f5f9ec63d9fdb158f50528e1e142e9bd94b0 Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 1 Mar 2022 14:59:26 +0100 Subject: [PATCH] Part: issue #6488: Cone surface returns wrong dv derivative This is a workaround to fix a bug in ElSLib::ConeDN --- src/Mod/Part/App/Geometry.cpp | 50 +++++++++++++++++++++++ src/Mod/Part/App/Geometry.h | 9 ++++ src/Mod/Part/App/GeometrySurfacePyImp.cpp | 16 +++----- 3 files changed, 65 insertions(+), 10 deletions(-) diff --git a/src/Mod/Part/App/Geometry.cpp b/src/Mod/Part/App/Geometry.cpp index 2aa0bf59a8..cab33def09 100644 --- a/src/Mod/Part/App/Geometry.cpp +++ b/src/Mod/Part/App/Geometry.cpp @@ -4246,6 +4246,12 @@ bool GeomSurface::normal(double u, double v, gp_Dir& dir) const return false; } +gp_Vec GeomSurface::getDN(double u, double v, int Nu, int Nv) const +{ + Handle(Geom_Surface) s = Handle(Geom_Surface)::DownCast(handle()); + return s->DN(u, v, Nu, Nv); +} + bool GeomSurface::isUmbillic(double u, double v) const { Handle(Geom_Surface) s = Handle(Geom_Surface)::DownCast(handle()); @@ -4499,6 +4505,50 @@ PyObject *GeomCone::getPyObject(void) return new ConePy(static_cast(this->clone())); } +gp_Vec GeomCone::getDN(double u, double v, int Nu, int Nv) const +{ + // Copied from ElSLib::ConeDN() and applied the needed fix + auto ElSLib__ConeDN = [](const Standard_Real U, + const Standard_Real V, + const gp_Ax3& Pos, + const Standard_Real Radius, + const Standard_Real SAngle, + const Standard_Integer Nu, + const Standard_Integer Nv) + { + gp_XYZ Xdir = Pos.XDirection().XYZ(); + gp_XYZ Ydir = Pos.YDirection().XYZ(); + gp_XYZ ZDir = Pos.Direction ().XYZ(); + Standard_Real Um = U + Nu * M_PI_2; // M_PI * 0.5 + Xdir.Multiply(cos(Um)); + Ydir.Multiply(sin(Um)); + Xdir.Add(Ydir); + if(Nv == 0) { + Xdir.Multiply(Radius + V * sin(SAngle)); + if(Nu == 0) Xdir.Add(Pos.Location().XYZ()); + return gp_Vec(Xdir); + } + else if(Nv == 1) { + Xdir.Multiply(sin(SAngle)); + ZDir.Multiply(cos(SAngle)); + Xdir.Add(ZDir); + return gp_Vec(Xdir); + } + return gp_Vec(0.0,0.0,0.0); + }; + + // Workaround for cones to get the correct derivatives + // https://forum.freecadweb.org/viewtopic.php?f=10&t=66677 + Handle(Geom_ConicalSurface) s = Handle(Geom_ConicalSurface)::DownCast(handle()); + Standard_RangeError_Raise_if (Nu + Nv < 1 || Nu < 0 || Nv < 0, " "); + if (Nv > 1) { + return gp_Vec (0.0, 0.0, 0.0); + } + else { + return ElSLib__ConeDN(u, v, s->Position(), s->RefRadius(), s->SemiAngle(), Nu, Nv); + } +} + // ------------------------------------------------- TYPESYSTEM_SOURCE(Part::GeomToroid,Part::GeomSurface) diff --git a/src/Mod/Part/App/Geometry.h b/src/Mod/Part/App/Geometry.h index adc55da70a..3bc70703d0 100644 --- a/src/Mod/Part/App/Geometry.h +++ b/src/Mod/Part/App/Geometry.h @@ -66,6 +66,7 @@ #include #include +#include #include "GeometryExtension.h" namespace Part { @@ -795,6 +796,11 @@ public: bool tangentU(double u, double v, gp_Dir& dirU) const; bool tangentV(double u, double v, gp_Dir& dirV) const; bool normal(double u, double v, gp_Dir& dir) const; + /*! + Computes the derivative of order Nu in the direction U and Nv + in the direction V at the point P(U, V). + */ + virtual gp_Vec getDN(double u, double v, int Nu, int Nv) const; /** @name Curvature information */ //@{ @@ -892,6 +898,9 @@ public: void setHandle(const Handle(Geom_ConicalSurface)&); const Handle(Geom_Geometry)& handle() const; + // Overloaded for Geom_ConicalSurface because of an OCC bug + virtual gp_Vec getDN(double u, double v, int Nu, int Nv) const; + private: Handle(Geom_ConicalSurface) mySurface; }; diff --git a/src/Mod/Part/App/GeometrySurfacePyImp.cpp b/src/Mod/Part/App/GeometrySurfacePyImp.cpp index a7dddde693..4b4fa9edd5 100644 --- a/src/Mod/Part/App/GeometrySurfacePyImp.cpp +++ b/src/Mod/Part/App/GeometrySurfacePyImp.cpp @@ -226,17 +226,13 @@ PyObject* GeometrySurfacePy::getD0(PyObject *args) PyObject* GeometrySurfacePy::getDN(PyObject *args) { - Handle(Geom_Geometry) g = getGeometryPtr()->handle(); - Handle(Geom_Surface) s = Handle(Geom_Surface)::DownCast(g); try { - if (!s.IsNull()) { - int nu, nv; - double u,v; - if (!PyArg_ParseTuple(args, "ddii", &u, &v, &nu, &nv)) - return nullptr; - gp_Vec v1 = s->DN(u, v, nu, nv); - return new Base::VectorPy(Base::Vector3d(v1.X(),v1.Y(),v1.Z())); - } + int nu, nv; + double u,v; + if (!PyArg_ParseTuple(args, "ddii", &u, &v, &nu, &nv)) + return nullptr; + gp_Vec v1 = getGeomSurfacePtr()->getDN(u, v, nu, nv); + return new Base::VectorPy(Base::Vector3d(v1.X(),v1.Y(),v1.Z())); } catch (Standard_Failure& e) { PyErr_SetString(PartExceptionOCCError, e.GetMessageString());