diff --git a/src/Mod/Part/App/Attacher.cpp b/src/Mod/Part/App/Attacher.cpp
index 441b5d6c07..eeb2901706 100644
--- a/src/Mod/Part/App/Attacher.cpp
+++ b/src/Mod/Part/App/Attacher.cpp
@@ -62,6 +62,7 @@
#include "Attacher.h"
#include "AttachExtension.h"
+#include "Tools.h"
#include
#include
#include
@@ -1177,7 +1178,6 @@ Base::Placement AttachEngine3D::calculateAttachedPlacement(const Base::Placement
if (vertex.IsNull())
throw Base::ValueError("Null vertex in AttachEngine3D::calculateAttachedPlacement()!");
- BRepAdaptor_Surface surf (face);
Handle (Geom_Surface) hSurf = BRep_Tool::Surface(face);
gp_Pnt p = BRep_Tool::Pnt(vertex);
@@ -1185,19 +1185,33 @@ Base::Placement AttachEngine3D::calculateAttachedPlacement(const Base::Placement
double u, v;
if (projector.NbPoints()==0)
throw Base::ValueError("AttachEngine3D::calculateAttachedPlacement: projecting point onto surface failed.");
+
projector.LowerDistanceParameters(u, v);
-
- BRepLProp_SLProps prop(surf,u,v,1, Precision::Confusion());
- SketchNormal = prop.Normal();
-
+ BRepAdaptor_Surface surf(face);
+ BRepLProp_SLProps prop(surf, u, v, 1, Precision::Confusion());
gp_Dir dirX;
- prop.TangentU(dirX); //if normal is defined, this should be defined too
+ Standard_Boolean done;
+
+ Tools::getNormal(face, u, v, Precision::Confusion(), SketchNormal, done);
+
+ if (!done)
+ throw Base::ValueError("AttachEngine3D::calculateAttachedPlacement: finding normal to surface at projected point failed.");
+
+ // if getNormal succeeds, at least one of the tangent is defined
+ if (prop.IsTangentUDefined()) {
+ prop.TangentU(dirX);
+ if (face.Orientation() == TopAbs_REVERSED)
+ dirX.Reverse();
+ }
+ // here the orientation of dirX is managed by SketchNormal orientation
+ else {
+ gp_Dir dirY;
+ prop.TangentV(dirY);
+ dirX = dirY.Crossed(SketchNormal);
+ }
+
SketchXAxis = gp_Vec(dirX).Reversed();//yields upside-down sketches less often.
- if (face.Orientation() == TopAbs_REVERSED) {
- SketchNormal.Reverse();
- SketchXAxis.Reverse();
- }
if (bThruVertex) {
SketchBasePoint = p;
} else {
diff --git a/src/Mod/Part/App/Geometry.cpp b/src/Mod/Part/App/Geometry.cpp
index 757b3048a1..2aa0bf59a8 100644
--- a/src/Mod/Part/App/Geometry.cpp
+++ b/src/Mod/Part/App/Geometry.cpp
@@ -145,6 +145,7 @@
#include "GeometryMigrationExtension.h"
#include "Geometry.h"
+#include "Tools.h"
#if OCC_VERSION_HEX >= 0x070600
using GeomAdaptor_HCurve = GeomAdaptor_Curve;
@@ -4235,11 +4236,12 @@ bool GeomSurface::tangentV(double u, double v, gp_Dir& dirV) const
bool GeomSurface::normal(double u, double v, gp_Dir& dir) const
{
Handle(Geom_Surface) s = Handle(Geom_Surface)::DownCast(handle());
- GeomLProp_SLProps prop(s,u,v,2,Precision::Confusion());
- if (prop.IsNormalDefined()) {
- dir = prop.Normal();
+ Standard_Boolean done;
+
+ Tools::getNormal(s, u, v, Precision::Confusion(), dir, done);
+
+ if (done)
return true;
- }
return false;
}
diff --git a/src/Mod/Part/App/TopoShapeFacePyImp.cpp b/src/Mod/Part/App/TopoShapeFacePyImp.cpp
index 089857d117..38aae52b2f 100644
--- a/src/Mod/Part/App/TopoShapeFacePyImp.cpp
+++ b/src/Mod/Part/App/TopoShapeFacePyImp.cpp
@@ -521,23 +521,20 @@ PyObject* TopoShapeFacePy::normalAt(PyObject *args)
{
double u,v;
if (!PyArg_ParseTuple(args, "dd",&u,&v))
- return 0;
+ return nullptr;
const TopoDS_Face& f = TopoDS::Face(getTopoShapePtr()->getShape());
- BRepAdaptor_Surface adapt(f);
+ Standard_Boolean done;
+ gp_Dir dir;
- BRepLProp_SLProps prop(adapt,u,v,2,Precision::Confusion());
- if (prop.IsNormalDefined()) {
- gp_Pnt pnt; gp_Vec vec;
- // handles the orientation state of the shape
- BRepGProp_Face(f).Normal(u,v,pnt,vec);
- vec.Normalize();
- return new Base::VectorPy(new Base::Vector3d(vec.X(),vec.Y(),vec.Z()));
- }
- else {
+ Tools::getNormal(f, u, v, Precision::Confusion(), dir, done);
+
+ if (!done) {
PyErr_SetString(PartExceptionOCCError, "normal not defined");
- return 0;
+ return nullptr;
}
+
+ return new Base::VectorPy(new Base::Vector3d(dir.X(),dir.Y(),dir.Z()));
}
PyObject* TopoShapeFacePy::getUVNodes(PyObject *args)