[PD] Refactor FeatureRevolution further

New methods created to reduce size of `execute`.

Use BRepPrimAPI instead of BRepFeat whenever possible since otherwise there are
some limitations.
This commit is contained in:
Ajinkya Dahale
2022-07-21 00:01:08 +05:30
parent 149738af7f
commit 43a8104926
2 changed files with 138 additions and 51 deletions

View File

@@ -92,10 +92,6 @@ App::DocumentObjectExecReturn *Revolution::execute()
double angle2 = Base::toRadians(Angle2.getValue());
// Reverse angle if selected
if (Reversed.getValue() && !Midplane.getValue())
angle *= (-1.0);
TopoDS_Shape sketchshape;
try {
sketchshape = getVerifiedFace();
@@ -131,22 +127,6 @@ App::DocumentObjectExecReturn *Revolution::execute()
std::string method(Type.getValueAsString());
// Rotate the face by half the angle to get Revolution symmetric to sketch plane
if (Midplane.getValue()) {
gp_Trsf mov;
mov.SetRotation(gp_Ax1(pnt, dir), Base::toRadians<double>(Angle.getValue()) * (-1.0) / 2.0);
TopLoc_Location loc(mov);
sketchshape.Move(loc);
}
else if (method == "TwoAngles") {
gp_Trsf mov;
mov.SetRotation(gp_Ax1(pnt, dir), angle2 * (-1.0));
TopLoc_Location loc(mov);
sketchshape.Move(loc);
angle = angle + angle2;
}
this->positionByPrevious();
TopLoc_Location invObjLoc = this->getLocation().Inverted();
pnt.Transform(invObjLoc.Transformation());
@@ -162,6 +142,7 @@ App::DocumentObjectExecReturn *Revolution::execute()
return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Revolve axis intersects the sketch"));
}
// Create a fresh support even when base exists so that it can be used for patterns
TopoDS_Shape result;
TopoDS_Face supportface = getSupportFace();
supportface.Move(invObjLoc);
@@ -175,43 +156,25 @@ App::DocumentObjectExecReturn *Revolution::execute()
else
throw Base::RuntimeError("ProfileBased: Revolution up to first/last is not yet supported");
// TODO: This method is designed for extrusions. needs to be adapted for revolutions.
getUpToFace(upToFace, base, sketchshape, method, dir);
// TODO: Make enum
int mode = 2;
BRepFeat_MakeRevol RevolMaker;
for (TopExp_Explorer xp(sketchshape, TopAbs_FACE); xp.More(); xp.Next()) {
RevolMaker.Init(base, xp.Current(), supportface, gp_Ax1(pnt, dir), mode, Standard_True);
RevolMaker.Perform(upToFace);
TopoDS_Face supportface = getSupportFace();
supportface.Move(invObjLoc);
if (!RevolMaker.IsDone())
throw Base::RuntimeError("ProfileBased: Up to face: Could not revolve the sketch!");
if (Reversed.getValue())
dir.Reverse();
base = RevolMaker.Shape();
if (mode == 2)
mode = 1;
}
result = base;
TopExp_Explorer Ex(supportface,TopAbs_WIRE);
if (!Ex.More())
supportface = TopoDS_Face();
RevolMode mode = RevolMode::None;
generateRevolution(result, method, base, sketchshape, supportface, upToFace, gp_Ax1(pnt, dir), mode, Standard_True);
}
else {
// TODO: Make enum
int mode = 2;
BRepFeat_MakeRevol RevolMaker;
for (TopExp_Explorer xp(sketchshape, TopAbs_FACE); xp.More(); xp.Next()) {
RevolMaker.Init(base, xp.Current(), supportface, gp_Ax1(pnt, dir), mode, Standard_True);
RevolMaker.Perform(angle);
if (!RevolMaker.IsDone())
throw Base::RuntimeError("ProfileBased: Could not revolve the sketch!");
base = RevolMaker.Shape();
if (mode == 2)
mode = 1;
}
if (RevolMaker.IsDone())
result = RevolMaker.Shape();
bool midplane = Midplane.getValue();
bool reversed = Reversed.getValue();
generateRevolution(result, sketchshape, method, gp_Ax1(pnt, dir), angle, angle2, midplane, reversed);
}
if (!result.IsNull()) {
@@ -272,4 +235,95 @@ void Revolution::updateAxis()
Axis.setValue(dir.x,dir.y,dir.z);
}
void Revolution::generateRevolution(TopoDS_Shape& revol,
const TopoDS_Shape& sketchshape,
const std::string& method,
const gp_Ax1& axis,
const double angle,
const double angle2,
const bool midplane,
const bool reversed)
{
if (method == "Angle" || method == "TwoAngles" || method == "ThroughAll") {
double angleTotal = angle;
double angleOffset = 0.;
if (method == "TwoAngles") {
// Rotate the face by `angle2`/`angle` to get "second" angle
angleTotal += angle2;
angleOffset = angle2 * -1.0;
}
else if (midplane) {
// Rotate the face by half the angle to get Revolution symmetric to sketch plane
angleOffset = -angle / 2;
}
if (fabs(angleTotal) < Precision::Angular())
throw Base::ValueError("Cannot create a revolution with zero angle.");
gp_Ax1 revolAx(axis);
if (reversed) {
revolAx.Reverse();
}
TopoDS_Shape from = sketchshape;
if (method == "TwoAngles" || midplane) {
gp_Trsf mov;
mov.SetRotation(revolAx, angleOffset);
TopLoc_Location loc(mov);
from.Move(loc);
}
// revolve the face to a solid
// BRepPrimAPI is the only option that allows use of this shape for patterns.
// See https://forum.freecadweb.org/viewtopic.php?f=8&t=70185&p=611673#p611673.
BRepPrimAPI_MakeRevol RevolMaker(from, revolAx, angleTotal);
if (!RevolMaker.IsDone())
throw Base::RuntimeError("ProfileBased: RevolMaker failed! Could not revolve the sketch!");
else
revol = RevolMaker.Shape();
}
else {
std::stringstream str;
str << "ProfileBased: Internal error: Unknown method '"
<< method << "' for generateRevolution()";
throw Base::RuntimeError(str.str());
}
}
void Revolution::generateRevolution(TopoDS_Shape& revol,
const std::string& method,
const TopoDS_Shape& baseshape,
const TopoDS_Shape& profileshape,
const TopoDS_Face& supportface,
const TopoDS_Face& uptoface,
const gp_Ax1& axis,
RevolMode Mode,
Standard_Boolean Modify)
{
if (method == "UpToFirst" || method == "UpToFace" || method == "UpToLast") {
BRepFeat_MakeRevol RevolMaker;
TopoDS_Shape base = baseshape;
for (TopExp_Explorer xp(profileshape, TopAbs_FACE); xp.More(); xp.Next()) {
RevolMaker.Init(base, xp.Current(), supportface, axis, Mode, Modify);
RevolMaker.Perform(uptoface);
if (!RevolMaker.IsDone())
throw Base::RuntimeError("ProfileBased: Up to face: Could not revolve the sketch!");
base = RevolMaker.Shape();
if (Mode == RevolMode::None)
Mode = RevolMode::FuseWithBase;
}
revol = base;
}
else {
std::stringstream str;
str << "ProfileBased: Internal error: Unknown method '"
<< method << "' for generateRevolution()";
throw Base::RuntimeError(str.str());
}
}
}

View File

@@ -74,6 +74,39 @@ protected:
static const App::PropertyAngle::Constraints floatAngle;
/**
* Generates a revolution of the input sketchshape and stores it in the given \a revol.
*/
void generateRevolution(TopoDS_Shape& revol,
const TopoDS_Shape& sketchshape,
const std::string& method,
const gp_Ax1& ax1,
const double angle,
const double angle2,
const bool midplane,
const bool reversed);
// See BRepFeat_MakeRevol
enum RevolMode {
CutFromBase = 0,
FuseWithBase = 1,
None = 2
};
/**
* Generates a revolution of the input \a profileshape.
* It will be a stand-alone solid created with BRepFeat_MakeRevol.
*/
void generateRevolution(TopoDS_Shape& revol,
const std::string& method,
const TopoDS_Shape& baseshape,
const TopoDS_Shape& profileshape,
const TopoDS_Face& supportface,
const TopoDS_Face& uptoface,
const gp_Ax1& ax1,
RevolMode Mode,
Standard_Boolean Modify);
private:
static const char* TypeEnums[];
};