PartDesign: Hole: get direction from cylindrical surface rather than normal (#22393)

* PartDesign: Hole: Find direction of cylindrical face in Hole::execute instead of FeatureSketchBased::getProfileNormal

* PartDesign: Minor cleanups in guessNormalDirection

---------

Co-authored-by: Kacper Donat <kadet1090@gmail.com>
This commit is contained in:
theo-vt
2025-07-27 22:06:50 -04:00
committed by GitHub
parent f2e9a7f62e
commit 7481a5d8dd
2 changed files with 34 additions and 11 deletions

View File

@@ -26,6 +26,7 @@
# include <limits>
# include <gp_Circ.hxx>
# include <gp_Dir.hxx>
# include <gp_Cylinder.hxx>
# include <BRep_Builder.hxx>
# include <Mod/Part/App/FCBRepAlgoAPI_Cut.h>
# include <Mod/Part/App/FCBRepAlgoAPI_Fuse.h>
@@ -39,6 +40,7 @@
# include <BRepOffsetAPI_MakePipeShell.hxx>
# include <BRepPrimAPI_MakeRevol.hxx>
# include <BRepAdaptor_Curve.hxx>
# include <BRepAdaptor_Surface.hxx>
# include <Geom_Circle.hxx>
# include <GC_MakeArcOfCircle.hxx>
# include <Geom_TrimmedCurve.hxx>
@@ -58,6 +60,7 @@
#include <Mod/Part/App/FaceMakerCheese.h>
#include <Mod/Part/App/TopoShapeMapper.h>
#include <Mod/Part/App/TopoShapeOpCode.h>
#include <Mod/Part/App/Tools.h>
#include "FeatureHole.h"
#include "json.hpp"
@@ -1410,7 +1413,7 @@ double Hole::getThreadProfileAngle()
void Hole::findClosestDesignation()
{
int threadType = ThreadType.getValue();
const int numTypes = static_cast<int>(std::size(threadDescription));
const int numTypes = static_cast<int>(std::size(threadDescription));
if (threadType < 0 || threadType >= numTypes) {
throw Base::IndexError(QT_TRANSLATE_NOOP("Exception", "Thread type is invalid"));
@@ -1758,9 +1761,9 @@ void Hole::setupObject()
Base::Reference<ParameterGrp> hGrp = App::GetApplication().GetUserParameter()
.GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/PartDesign");
BaseProfileType.setValue(baseProfileOption_idxToBitmask(hGrp->GetInt("defaultBaseTypeHole", 1)));
ProfileBased::setupObject();
}
@@ -1887,9 +1890,9 @@ static gp_Pnt toPnt(gp_Vec dir)
App::DocumentObjectExecReturn* Hole::execute()
{
TopoShape profileshape =
getProfileShape( Part::ShapeOption::NeedSubElement
getProfileShape( Part::ShapeOption::NeedSubElement
| Part::ShapeOption::ResolveLink
| Part::ShapeOption::Transform
| Part::ShapeOption::Transform
| Part::ShapeOption::DontSimplifyCompound);
// Find the base shape
@@ -1918,7 +1921,8 @@ App::DocumentObjectExecReturn* Hole::execute()
/* Build the prototype hole */
// Get vector normal to profile
Base::Vector3d SketchVector = getProfileNormal();
Base::Vector3d SketchVector = guessNormalDirection(profileshape);
if (Reversed.getValue())
SketchVector *= -1.0;
@@ -2254,6 +2258,24 @@ gp_Vec Hole::computePerpendicular(const gp_Vec& zDir) const
xDir.Normalize();
return xDir;
}
Base::Vector3d Hole::guessNormalDirection(const TopoShape& profileshape) const
{
// If trying to build a hole from a cylinder face
// we must try to find the direction ourselves as
// getProfileNormal() will try to find the normal to
// the middle of the face
if (profileshape.hasSubShape(TopAbs_FACE)) {
BRepAdaptor_Surface sf(TopoDS::Face(profileshape.getSubShape(TopAbs_FACE, 1)));
if (sf.GetType() != GeomAbs_Cylinder) {
throw Base::Exception("Cannot create hole from non cylindrical face");
}
return Base::convertTo<Base::Vector3d>(sf.Cylinder().Axis().Direction());
}
return getProfileNormal();
}
TopoShape Hole::findHoles(std::vector<TopoShape> &holes,
const TopoShape& profileshape,
const TopoDS_Shape& protoHole) const
@@ -2279,7 +2301,7 @@ TopoShape Hole::findHoles(std::vector<TopoShape> &holes,
int baseProfileType = BaseProfileType.getValue();
// Iterate over edges and filter out non-circle/non-arc types
if (baseProfileType & BaseProfileTypeOptions::OnCircles ||
if (baseProfileType & BaseProfileTypeOptions::OnCircles ||
baseProfileType & BaseProfileTypeOptions::OnArcs) {
for (const auto &profileEdge : profileshape.getSubTopoShapes(TopAbs_EDGE)) {
TopoDS_Edge edge = TopoDS::Edge(profileEdge.getShape());
@@ -2293,7 +2315,7 @@ TopoShape Hole::findHoles(std::vector<TopoShape> &holes,
if (!(baseProfileType & BaseProfileTypeOptions::OnCircles) && adaptor.IsClosed()) {
continue;
}
// Filter for arcs
if (!(baseProfileType & BaseProfileTypeOptions::OnArcs) && !adaptor.IsClosed()) {
continue;
@@ -2726,7 +2748,7 @@ int Hole::baseProfileOption_idxToBitmask(int index)
}
if (index == 2) {
return PartDesign::Hole::BaseProfileTypeOptions::OnPoints;
}
}
Base::Console().error("Unexpected hole base profile combobox index: %i", index);
return 0;
}
@@ -2734,10 +2756,10 @@ int Hole::baseProfileOption_bitmaskToIdx(int bitmask)
{
if (bitmask == PartDesign::Hole::BaseProfileTypeOptions::OnCirclesArcs) {
return 0;
}
}
if (bitmask == PartDesign::Hole::BaseProfileTypeOptions::OnPointsCirclesArcs) {
return 1;
}
}
if (bitmask == PartDesign::Hole::BaseProfileTypeOptions::OnPoints) {
return 2;
}

View File

@@ -254,6 +254,7 @@ private:
void findClosestDesignation();
void rotateToNormal(const gp_Dir& helixAxis, const gp_Dir& normalAxis, TopoDS_Shape& helixShape) const;
gp_Vec computePerpendicular(const gp_Vec&) const;
Base::Vector3d guessNormalDirection(const TopoShape& profileshape) const;
TopoDS_Shape makeThread(const gp_Vec&, const gp_Vec&, double);
TopoShape findHoles(std::vector<TopoShape> &holes, const TopoShape& profileshape, const TopoDS_Shape& protohole) const;