diff --git a/src/Mod/PartDesign/App/FeatureExtrude.cpp b/src/Mod/PartDesign/App/FeatureExtrude.cpp index e902e6504d..00c2dfe716 100644 --- a/src/Mod/PartDesign/App/FeatureExtrude.cpp +++ b/src/Mod/PartDesign/App/FeatureExtrude.cpp @@ -24,25 +24,14 @@ #include "PreCompiled.h" #ifndef _PreComp_ # include -# include -# include -# include -# include -# include -# include # include -# include -# include -# include -# include -# include -# include +# include +# include # include # include # include # include -# include -# include +# include # include #endif @@ -52,6 +41,7 @@ #include #include #include +#include #include "FeatureExtrude.h" @@ -135,3 +125,161 @@ Base::Vector3d FeatureExtrude::computeDirection(const Base::Vector3d& sketchVect Direction.setValue(extrudeDirection); return extrudeDirection; } + +void FeatureExtrude::Extrude(TopoDS_Shape& prism, + const TopoDS_Shape& sketchshape, + const std::string& method, + const gp_Dir& direction, + const double L, + const double L2, + const double angle, + const double angle2, + const bool midplane, + const bool reversed) +{ + if (method == "Length" || method == "TwoLengths" || method == "ThroughAll") { + double Ltotal = L; + double Loffset = 0.; + gp_Dir directionTaper = direction; + if (method == "ThroughAll") + Ltotal = getThroughAllLength(); + + + if (method == "TwoLengths") { + // midplane makes no sense here + Ltotal += L2; + if (reversed) + Loffset = -L; + else if (midplane) + Loffset = -0.5 * (L2 + L); + else + Loffset = -L2; + } + else if (midplane) { + Loffset = -Ltotal / 2; + } + + TopoDS_Shape from = sketchshape; + if (method == "TwoLengths" || midplane) { + gp_Trsf mov; + mov.SetTranslation(Loffset * gp_Vec(direction)); + TopLoc_Location loc(mov); + from = sketchshape.Moved(loc); + } + else if (reversed) { + Ltotal *= -1.0; + } + + if (fabs(Ltotal) < Precision::Confusion()) { + if (addSubType == Type::Additive) + throw Base::ValueError("Cannot create a pad with a height of zero."); + else + throw Base::ValueError("Cannot create a pocket with a depth of zero."); + } + + // now we can create either a tapered or linear prism. + // If tapered, we create is using Part's draft extrusion method. If linear we create a prism. + if (fabs(angle) > Base::toRadians(Precision::Angular()) || fabs(angle2) > Base::toRadians(Precision::Angular())) { + // prism is tapered + if (reversed) + directionTaper.Reverse(); + generateTaperedPrism(prism, sketchshape, method, directionTaper, L, L2, angle, angle2, midplane); + } + else { + // Without taper angle we create a prism because its shells are in every case no B-splines and can therefore + // be use as support for further features like Pads, Lofts etc. B-spline shells can break certain features, + // see e.g. https://forum.freecadweb.org/viewtopic.php?p=560785#p560785 + // It is better not to use BRepFeat_MakePrism here even if we have a support because the + // resulting shape creates problems with Pocket + BRepPrimAPI_MakePrism PrismMaker(from, Ltotal * gp_Vec(direction), 0, 1); // finite prism + if (!PrismMaker.IsDone()) + throw Base::RuntimeError("ProfileBased: Length: Could not extrude the sketch!"); + prism = PrismMaker.Shape(); + } + } + else { + std::stringstream str; + str << "ProfileBased: Internal error: Unknown method '" + << method << "' for generatePrism()"; + throw Base::RuntimeError(str.str()); + } +} + +void FeatureExtrude::Extrude(TopoDS_Shape& prism, + const std::string& method, + const TopoDS_Shape& baseshape, + const TopoDS_Shape& profileshape, + const TopoDS_Face& supportface, + const TopoDS_Face& uptoface, + const gp_Dir& direction, + PrismMode Mode, + Standard_Boolean Modify) +{ + if (method == "UpToFirst" || method == "UpToFace" || method == "UpToLast") { + BRepFeat_MakePrism PrismMaker; + TopoDS_Shape base = baseshape; + for (TopExp_Explorer xp(profileshape, TopAbs_FACE); xp.More(); xp.Next()) { + PrismMaker.Init(base, xp.Current(), supportface, direction, Mode, Modify); + PrismMaker.Perform(uptoface); + if (!PrismMaker.IsDone()) + throw Base::RuntimeError("ProfileBased: Up to face: Could not extrude the sketch!"); + + base = PrismMaker.Shape(); + if (Mode == PrismMode::None) + Mode = PrismMode::FuseWithBase; + } + + prism = base; + } + else { + std::stringstream str; + str << "ProfileBased: Internal error: Unknown method '" + << method << "' for generatePrism()"; + throw Base::RuntimeError(str.str()); + } +} + +void FeatureExtrude::generateTaperedPrism(TopoDS_Shape& prism, + const TopoDS_Shape& sketchshape, + const std::string& method, + const gp_Dir& direction, + const double L, + const double L2, + const double angle, + const double angle2, + const bool midplane) +{ + std::list drafts; + bool isSolid = true; // in PD we only generate solids, while Part Extrude can also create only shells + bool isPartDesign = true; // there is an OCC bug with single-edge wires (circles) we need to treat differently for PD and Part + if (method == "ThroughAll") + Part::ExtrusionHelper::makeDraft(sketchshape, direction, getThroughAllLength(), + 0.0, Base::toRadians(angle), 0.0, isSolid, drafts, isPartDesign); + else if (method == "TwoLengths") + Part::ExtrusionHelper::makeDraft(sketchshape, direction, L, L2, + Base::toRadians(angle), Base::toRadians(angle2), isSolid, drafts, isPartDesign); + else if (method == "Length") { + if (midplane) { + Part::ExtrusionHelper::makeDraft(sketchshape, direction, L / 2, L / 2, + Base::toRadians(angle), Base::toRadians(angle), isSolid, drafts, isPartDesign); + } + else + Part::ExtrusionHelper::makeDraft(sketchshape, direction, L, 0.0, + Base::toRadians(angle), 0.0, isSolid, drafts, isPartDesign); + } + + if (drafts.empty()) { + throw Base::RuntimeError("Creation of tapered object failed"); + } + else if (drafts.size() == 1) { + prism = drafts.front(); + } + else { + TopoDS_Compound comp; + BRep_Builder builder; + builder.MakeCompound(comp); + for (std::list::iterator it = drafts.begin(); it != drafts.end(); ++it) + builder.Add(comp, *it); + prism = comp; + } +} diff --git a/src/Mod/PartDesign/App/FeatureExtrude.h b/src/Mod/PartDesign/App/FeatureExtrude.h index bb77306272..76c252e566 100644 --- a/src/Mod/PartDesign/App/FeatureExtrude.h +++ b/src/Mod/PartDesign/App/FeatureExtrude.h @@ -30,6 +30,10 @@ #include #include "FeatureSketchBased.h" +class gp_Dir; +class TopoDS_Face; +class TopoDS_Shape; + namespace PartDesign { @@ -62,6 +66,54 @@ public: protected: Base::Vector3d computeDirection(const Base::Vector3d& sketchVector); + + /** + * Generates an extrusion of the input sketchshape and stores it in the given &prism + */ + void Extrude(TopoDS_Shape& prism, + const TopoDS_Shape& sketchshape, + const std::string& method, + const gp_Dir& direction, + const double L, + const double L2, + const double angle, + const double angle2, + const bool midplane, + const bool reversed); + + // See BRepFeat_MakePrism + enum PrismMode { + CutFromBase = 0, + FuseWithBase = 1, + None = 2 + }; + + /** + * Generates an extrusion of the input profileshape + * It will be a stand-alone solid created with BRepFeat_MakePrism + */ + static void Extrude(TopoDS_Shape& prism, + const std::string& method, + const TopoDS_Shape& baseshape, + const TopoDS_Shape& profileshape, + const TopoDS_Face& sketchface, + const TopoDS_Face& uptoface, + const gp_Dir& direction, + PrismMode Mode, + Standard_Boolean Modify); + + /** + * Generates a tapered prism of the input sketchshape and stores it in the given &prism + */ + void generateTaperedPrism(TopoDS_Shape& prism, + const TopoDS_Shape& sketchshape, + const std::string& method, + const gp_Dir& direction, + const double L, + const double L2, + const double angle, + const double angle2, + const bool midplane); }; } //namespace PartDesign diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.cpp b/src/Mod/PartDesign/App/FeatureSketchBased.cpp index aa26f88c0c..46b4fc759c 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.cpp +++ b/src/Mod/PartDesign/App/FeatureSketchBased.cpp @@ -80,7 +80,6 @@ #include #include #include -#include #include #include "FeatureSketchBased.h" #include "DatumPlane.h" @@ -585,164 +584,6 @@ double ProfileBased::getThroughAllLength() const return 2.02 * sqrt(box.SquareExtent()); } -void ProfileBased::Extrude(TopoDS_Shape& prism, - const TopoDS_Shape& sketchshape, - const std::string& method, - const gp_Dir& direction, - const double L, - const double L2, - const double angle, - const double angle2, - const bool midplane, - const bool reversed) -{ - if (method == "Length" || method == "TwoLengths" || method == "ThroughAll") { - double Ltotal = L; - double Loffset = 0.; - gp_Dir directionTaper = direction; - if (method == "ThroughAll") - Ltotal = getThroughAllLength(); - - - if (method == "TwoLengths") { - // midplane makes no sense here - Ltotal += L2; - if (reversed) - Loffset = -L; - else if (midplane) - Loffset = -0.5 * (L2 + L); - else - Loffset = -L2; - } - else if (midplane) { - Loffset = -Ltotal / 2; - } - - TopoDS_Shape from = sketchshape; - if (method == "TwoLengths" || midplane) { - gp_Trsf mov; - mov.SetTranslation(Loffset * gp_Vec(direction)); - TopLoc_Location loc(mov); - from = sketchshape.Moved(loc); - } - else if (reversed) { - Ltotal *= -1.0; - } - - if (fabs(Ltotal) < Precision::Confusion()) { - if (addSubType == Type::Additive) - throw Base::ValueError("Cannot create a pad with a height of zero."); - else - throw Base::ValueError("Cannot create a pocket with a depth of zero."); - } - - // now we can create either a tapered or linear prism. - // If tapered, we create is using Part's draft extrusion method. If linear we create a prism. - if (fabs(angle) > Base::toRadians(Precision::Angular()) || fabs(angle2) > Base::toRadians(Precision::Angular())) { - // prism is tapered - if (reversed) - directionTaper.Reverse(); - generateTaperedPrism(prism, sketchshape, method, directionTaper, L, L2, angle, angle2, midplane); - } - else { - // Without taper angle we create a prism because its shells are in every case no B-splines and can therefore - // be use as support for further features like Pads, Lofts etc. B-spline shells can break certain features, - // see e.g. https://forum.freecadweb.org/viewtopic.php?p=560785#p560785 - // It is better not to use BRepFeat_MakePrism here even if we have a support because the - // resulting shape creates problems with Pocket - BRepPrimAPI_MakePrism PrismMaker(from, Ltotal * gp_Vec(direction), 0, 1); // finite prism - if (!PrismMaker.IsDone()) - throw Base::RuntimeError("ProfileBased: Length: Could not extrude the sketch!"); - prism = PrismMaker.Shape(); - } - } - else { - std::stringstream str; - str << "ProfileBased: Internal error: Unknown method '" - << method << "' for generatePrism()"; - throw Base::RuntimeError(str.str()); - } -} - -void ProfileBased::Extrude(TopoDS_Shape& prism, - const std::string& method, - const TopoDS_Shape& baseshape, - const TopoDS_Shape& profileshape, - const TopoDS_Face& supportface, - const TopoDS_Face& uptoface, - const gp_Dir& direction, - PrismMode Mode, - Standard_Boolean Modify) -{ - if (method == "UpToFirst" || method == "UpToFace" || method == "UpToLast") { - BRepFeat_MakePrism PrismMaker; - TopoDS_Shape base = baseshape; - for (TopExp_Explorer xp(profileshape, TopAbs_FACE); xp.More(); xp.Next()) { - PrismMaker.Init(base, xp.Current(), supportface, direction, Mode, Modify); - PrismMaker.Perform(uptoface); - if (!PrismMaker.IsDone()) - throw Base::RuntimeError("ProfileBased: Up to face: Could not extrude the sketch!"); - - base = PrismMaker.Shape(); - if (Mode == PrismMode::None) - Mode = PrismMode::FuseWithBase; - } - - prism = base; - } - else { - std::stringstream str; - str << "ProfileBased: Internal error: Unknown method '" - << method << "' for generatePrism()"; - throw Base::RuntimeError(str.str()); - } -} - -void ProfileBased::generateTaperedPrism(TopoDS_Shape& prism, - const TopoDS_Shape& sketchshape, - const std::string& method, - const gp_Dir& direction, - const double L, - const double L2, - const double angle, - const double angle2, - const bool midplane) -{ - std::list drafts; - bool isSolid = true; // in PD we only generate solids, while Part Extrude can also create only shells - bool isPartDesign = true; // there is an OCC bug with single-edge wires (circles) we need to treat differently for PD and Part - if (method == "ThroughAll") - Part::ExtrusionHelper::makeDraft(sketchshape, direction, getThroughAllLength(), - 0.0, Base::toRadians(angle), 0.0, isSolid, drafts, isPartDesign); - else if (method == "TwoLengths") - Part::ExtrusionHelper::makeDraft(sketchshape, direction, L, L2, - Base::toRadians(angle), Base::toRadians(angle2), isSolid, drafts, isPartDesign); - else if (method == "Length") { - if (midplane) { - Part::ExtrusionHelper::makeDraft(sketchshape, direction, L / 2, L / 2, - Base::toRadians(angle), Base::toRadians(angle), isSolid, drafts, isPartDesign); - } - else - Part::ExtrusionHelper::makeDraft(sketchshape, direction, L, 0.0, - Base::toRadians(angle), 0.0, isSolid, drafts, isPartDesign); - } - - if (drafts.empty()) { - throw Base::RuntimeError("Creation of tapered object failed"); - } - else if (drafts.size() == 1) { - prism = drafts.front(); - } - else { - TopoDS_Compound comp; - BRep_Builder builder; - builder.MakeCompound(comp); - for (std::list::iterator it = drafts.begin(); it != drafts.end(); ++it) - builder.Add(comp, *it); - prism = comp; - } -} - bool ProfileBased::checkWireInsideFace(const TopoDS_Wire& wire, const TopoDS_Face& face, const gp_Dir& dir) { // Project wire onto the face (face, not surface! So limits of face apply) diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.h b/src/Mod/PartDesign/App/FeatureSketchBased.h index a4ba6cb7f1..e21dceb3fe 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.h +++ b/src/Mod/PartDesign/App/FeatureSketchBased.h @@ -28,11 +28,11 @@ #include #include "FeatureAddSub.h" -class TopoDS_Shape; -class TopoDS_Face; -class TopoDS_Wire; class gp_Dir; class gp_Lin; +class TopoDS_Face; +class TopoDS_Shape; +class TopoDS_Wire; namespace PartDesign { @@ -142,54 +142,6 @@ protected: const gp_Dir& dir, double offset); - /** - * Generates an extrusion of the input sketchshape and stores it in the given &prism - */ - void Extrude(TopoDS_Shape& prism, - const TopoDS_Shape& sketchshape, - const std::string& method, - const gp_Dir& direction, - const double L, - const double L2, - const double angle, - const double angle2, - const bool midplane, - const bool reversed); - - // See BRepFeat_MakePrism - enum PrismMode { - CutFromBase = 0, - FuseWithBase = 1, - None = 2 - }; - - /** - * Generates an extrusion of the input profileshape - * It will be a stand-alone solid created with BRepFeat_MakePrism - */ - static void Extrude(TopoDS_Shape& prism, - const std::string& method, - const TopoDS_Shape& baseshape, - const TopoDS_Shape& profileshape, - const TopoDS_Face& sketchface, - const TopoDS_Face& uptoface, - const gp_Dir& direction, - PrismMode Mode, - Standard_Boolean Modify); - - /** - * Generates a tapered prism of the input sketchshape and stores it in the given &prism - */ - void generateTaperedPrism(TopoDS_Shape& prism, - const TopoDS_Shape& sketchshape, - const std::string& method, - const gp_Dir& direction, - const double L, - const double L2, - const double angle, - const double angle2, - const bool midplane); - /// Check whether the wire after projection on the face is inside the face static bool checkWireInsideFace(const TopoDS_Wire& wire, const TopoDS_Face& face,