From 6f3f0b1d0db8da748b464e96d19ae187ebfd7955 Mon Sep 17 00:00:00 2001 From: Kacper Donat Date: Tue, 15 Jul 2025 00:14:39 +0200 Subject: [PATCH] Attacher: Orient normals correctly for Midpoint Co-authored-by: Max Wilfinger --- src/Mod/Part/App/Attacher.cpp | 34 ++++++++++++++++++++-------------- src/Mod/Part/App/Geometry.cpp | 9 ++++++++- src/Mod/Part/App/Geometry.h | 2 ++ 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/src/Mod/Part/App/Attacher.cpp b/src/Mod/Part/App/Attacher.cpp index 4ef29ccbe7..4f1e041de9 100644 --- a/src/Mod/Part/App/Attacher.cpp +++ b/src/Mod/Part/App/Attacher.cpp @@ -1969,32 +1969,38 @@ AttachEngine3D::_calculateAttachedPlacement(const std::vector(geom.get()); + auto face = TopoDS::Face(shape->getShape()); + auto adaptorSurface = BRepAdaptor_Surface(face, true); + + auto u1 = adaptorSurface.FirstUParameter(); + auto u2 = adaptorSurface.LastUParameter(); + auto v1 = adaptorSurface.FirstVParameter(); + auto v2 = adaptorSurface.LastVParameter(); + + auto midU = (u1 + u2) / 2; + auto midV = (v1 + v2) / 2; + if (auto sphere = freecad_cast(geom.get())) { placement.setPosition(sphere->getLocation()); } else if (auto cone = freecad_cast(geom.get())) { placement.setPosition(cone->getApex()); + } else if (auto point = surface->point(midU, midV)) { + placement.setPosition(*point); } else if (auto com = shape->centerOfGravity()) { placement.setPosition(*com); } else { placement.setPosition(shape->getBoundBox().GetCenter()); } - if (auto rotation = surface->getRotation()) { - placement.setRotation(*rotation); - } else { - auto adaptorSurface = BRepAdaptor_Surface(TopoDS::Face(shape->getShape()), true); + // calculate the normal at midpoint of the surface and use it as Z axis + gp_Dir dir; + surface->normal(midU, midV, dir); - auto u1 = adaptorSurface.FirstUParameter(); - auto u2 = adaptorSurface.LastUParameter(); - auto v1 = adaptorSurface.FirstVParameter(); - auto v2 = adaptorSurface.LastVParameter(); - - // calculate the normal at midpoint of the surface and use it as Z axis - gp_Dir dir; - surface->normal((u1 + u2) / 2, (v1 + v2) / 2, dir); - - placement.setRotation(Base::Rotation::fromNormalVector(Base::convertTo(-dir))); + if (face.Orientation() == TopAbs_REVERSED) { + dir = -dir; } + + placement.setRotation(Base::Rotation::fromNormalVector(Base::convertTo(dir))); } break; diff --git a/src/Mod/Part/App/Geometry.cpp b/src/Mod/Part/App/Geometry.cpp index 626f288eda..552022e147 100644 --- a/src/Mod/Part/App/Geometry.cpp +++ b/src/Mod/Part/App/Geometry.cpp @@ -4884,12 +4884,19 @@ bool GeomSurface::normal(double u, double v, gp_Dir& dir) const Tools::getNormal(s, u, v, Precision::Confusion(), dir, done); - if (done) + if (done) { return true; + } return false; } +std::optional GeomSurface::point(double u, double v) const +{ + Handle(Geom_Surface) s = Handle(Geom_Surface)::DownCast(handle()); + return Base::convertTo(s->Value(u, v)); +} + gp_Vec GeomSurface::getDN(double u, double v, int Nu, int Nv) const { Handle(Geom_Surface) s = Handle(Geom_Surface)::DownCast(handle()); diff --git a/src/Mod/Part/App/Geometry.h b/src/Mod/Part/App/Geometry.h index 2912d30659..d1f5e37288 100644 --- a/src/Mod/Part/App/Geometry.h +++ b/src/Mod/Part/App/Geometry.h @@ -889,6 +889,8 @@ 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; + std::optional point(double u, double v) const; + /*! Computes the derivative of order Nu in the direction U and Nv in the direction V at the point P(U, V).