From 0745d40f86be9cfb09b3de6f01b0d4fea2b0ffc2 Mon Sep 17 00:00:00 2001 From: wandererfan Date: Tue, 3 Feb 2026 17:07:05 -0500 Subject: [PATCH] [TD]fix fail on single edge cutting profile --- src/Mod/TechDraw/App/DrawComplexSection.cpp | 63 ++++++++++++++++++--- src/Mod/TechDraw/App/DrawComplexSection.h | 2 + 2 files changed, 56 insertions(+), 9 deletions(-) diff --git a/src/Mod/TechDraw/App/DrawComplexSection.cpp b/src/Mod/TechDraw/App/DrawComplexSection.cpp index 2065c0926e..60d11c4873 100644 --- a/src/Mod/TechDraw/App/DrawComplexSection.cpp +++ b/src/Mod/TechDraw/App/DrawComplexSection.cpp @@ -57,7 +57,6 @@ #include #include #include -#include #include #include #include @@ -999,7 +998,7 @@ bool DrawComplexSection::boxesIntersect(TopoDS_Face& face, TopoDS_Shape& shape) Bnd_Box box0; Bnd_Box box1; BRepBndLib::Add(face, box0); - box0.SetGap(OverlapTolerance);//generous + box0.SetGap(OverlapTolerance); //generous BRepBndLib::Add(shape, box1); box1.SetGap(OverlapTolerance); return !box0.IsOut(box1); @@ -1048,23 +1047,33 @@ TopoDS_Wire DrawComplexSection::makeNoseToTailWire(const TopoDS_Shape& inShape) return {}; } - std::list inList; + std::list inEdges; TopExp_Explorer expEdges(inShape, TopAbs_EDGE); for (; expEdges.More(); expEdges.Next()) { TopoDS_Edge edge = TopoDS::Edge(expEdges.Current()); - inList.push_back(edge); + inEdges.push_back(edge); } + BRepBuilderAPI_MakeWire mkWire; + std::list sortedList; - if (inList.empty() || inList.size() == 1) { + if (inEdges.empty() ) { return {}; } - sortedList = DrawUtil::sort_Edges(EWTOLERANCE, inList); - BRepBuilderAPI_MakeWire mkWire; + // Prior to https://github.com/FreeCAD/FreeCAD/issues/26838, this method demanded that the + // tool profile shape have at least 2 edges. Allowing single edge tool here requires adding + // support for this case in closeProfileForCut(). + if (inEdges.size() == 1) { + mkWire.Add(inEdges.front()); + return mkWire.Wire(); + } + + sortedList = DrawUtil::sort_Edges(EWTOLERANCE, inEdges); for (auto& edge : sortedList) { mkWire.Add(edge); } + return mkWire.Wire(); } @@ -1397,7 +1406,7 @@ DrawComplexSection::getSegmentViewDirections(const TopoDS_Wire& profileWire, std::vector> normalKV; TopExp_Explorer expFaces(profileSolidTool, TopAbs_FACE); // are all these shenanigans necessary? - // no guarantee of order from TopExp_Explorer?? Need to match faces to the profile segment that + // no guarantee of order from TopExp_Explorer. Need to match faces to the profile segment that // generated it? for (int iFace = 0; expFaces.More(); expFaces.Next(), iFace++) { auto shape = expFaces.Current(); @@ -1645,7 +1654,7 @@ TopoDS_Shape DrawComplexSection::cuttingToolFromProfile(const TopoDS_Wire& inPro } TopoDS_Wire DrawComplexSection::closeProfileForCut(const TopoDS_Wire& profileWire, - double dMax) const + double dMax) const { // TODO: do these conversions gp_Pnt <-> Base::Vector3d <-> QPointF cause our problems with low // digits? @@ -1667,6 +1676,13 @@ TopoDS_Wire DrawComplexSection::closeProfileForCut(const TopoDS_Wire& profileWir awayDirection.Normalize(); std::vector profileEdges = DU::shapeToVector(flatWire); + if (profileEdges.size() == 1) { + // single edge tool profile needs special handling + TopoDS_Edge firstEdge = profileEdges.front(); + return closeSingleEdgeProfile(firstEdge, dMax); + } + + // traditional multi edge profile TopoDS_Edge firstEdge = profileEdges.front(); std::pair edgeEnds = getSegmentEnds(firstEdge); Base::Vector3d firstExtendDir = edgeEnds.first - edgeEnds.second; @@ -1722,6 +1738,35 @@ TopoDS_Wire DrawComplexSection::closeProfileForCut(const TopoDS_Wire& profileWir return mkWire.Wire(); } +//! make a rectangular wire based on the single edge +TopoDS_Wire DrawComplexSection::closeSingleEdgeProfile(const TopoDS_Edge& singleEdge, + double dMax) const +{ + std::pair edgeEnds = getSegmentEnds(singleEdge); + + Base::Vector3d midEdgePoint = (edgeEnds.first + edgeEnds.second / 2); + Base::Vector3d SNPoint = SectionNormal.getValue() * dMax; + Base::Vector3d awayDirection = SNPoint - midEdgePoint; // from midpoint to snpoint + awayDirection.Normalize(); + + Base::Vector3d far0 = edgeEnds.first + awayDirection * dMax; + Base::Vector3d far1 = edgeEnds.second + awayDirection * dMax; + TopoDS_Edge farEdge = BRepBuilderAPI_MakeEdge(Base::convertTo(far1 ), + Base::convertTo(far0)); //switch these parms? + TopoDS_Edge nearToFarEdge = BRepBuilderAPI_MakeEdge(Base::convertTo(edgeEnds.second), + Base::convertTo(far1)); + TopoDS_Edge farToNearEdge = BRepBuilderAPI_MakeEdge(Base::convertTo(far0), + Base::convertTo(edgeEnds.first)); + + BRepBuilderAPI_MakeWire mkWire; + mkWire.Add(singleEdge); + mkWire.Add(nearToFarEdge); + mkWire.Add(farEdge); + mkWire.Add(farToNearEdge); + + return mkWire.Wire(); +} + bool DrawComplexSection::isFacePlanar(const TopoDS_Face& face) { diff --git a/src/Mod/TechDraw/App/DrawComplexSection.h b/src/Mod/TechDraw/App/DrawComplexSection.h index a87ac1a06a..f81e4718c9 100644 --- a/src/Mod/TechDraw/App/DrawComplexSection.h +++ b/src/Mod/TechDraw/App/DrawComplexSection.h @@ -71,6 +71,8 @@ public: TopoDS_Shape makeCuttingToolFromClosedProfile(const TopoDS_Wire& profileWire, double dMax); TopoDS_Shape cuttingToolFromProfile(const TopoDS_Wire& inProfileWire, double dMax) const; + TopoDS_Wire closeSingleEdgeProfile(const TopoDS_Edge& singleEdge, + double dMax) const; void makeAlignedPieces(const TopoDS_Shape& rawShape);