Merge pull request #21713 from 3x380V/pd_fixes
PartDesign: Random fixes
This commit is contained in:
@@ -2697,8 +2697,15 @@ TopoShape& TopoShape::makeElementOffset2D(const TopoShape& shape,
|
||||
if (shape.getShape().ShapeType() == TopAbs_COMPOUND) {
|
||||
if (!intersection) {
|
||||
// simply recursively process the children, independently
|
||||
expandCompound(shape, shapesToProcess);
|
||||
outputPolicy = SingleShapeCompoundCreationPolicy::forceCompound;
|
||||
for(TopoDS_Iterator it(shape.getShape()); it.More() ; it.Next()) {
|
||||
shapesToReturn.push_back(TopoShape(it.Value()).makeElementOffset2D(offset,
|
||||
joinType,
|
||||
fill,
|
||||
allowOpenResult,
|
||||
intersection,
|
||||
op));
|
||||
outputPolicy = SingleShapeCompoundCreationPolicy::forceCompound;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// collect non-compounds from this compound for collective offset. Process other shapes
|
||||
|
||||
@@ -126,9 +126,13 @@ App::DocumentObjectExecReturn *Draft::execute()
|
||||
App::DocumentObject* refDirection = PullDirection.getValue();
|
||||
if (refDirection) {
|
||||
if (refDirection->isDerivedFrom<PartDesign::Line>()) {
|
||||
PartDesign::Line* line = static_cast<PartDesign::Line*>(refDirection);
|
||||
Base::Vector3d d = line->getDirection();
|
||||
pullDirection = gp_Dir(d.x, d.y, d.z);
|
||||
PartDesign::Line* line = static_cast<PartDesign::Line*>(refDirection);
|
||||
Base::Vector3d d = line->getDirection();
|
||||
pullDirection = gp_Dir(d.x, d.y, d.z);
|
||||
} else if (refDirection->isDerivedFrom<App::Line>()) {
|
||||
App::Line* line = static_cast<App::Line*>(refDirection);
|
||||
Base::Vector3d d = line->getDirection();
|
||||
pullDirection = gp_Dir(d.x, d.y, d.z);
|
||||
} else if (refDirection->isDerivedFrom<Part::Feature>()) {
|
||||
std::vector<std::string> subStrings = PullDirection.getSubValues();
|
||||
if (subStrings.empty() || subStrings[0].empty())
|
||||
|
||||
@@ -25,10 +25,9 @@
|
||||
# include <BRepPrimAPI_MakeRevol.hxx>
|
||||
# include <BRepFeat_MakeRevol.hxx>
|
||||
# include <gp_Lin.hxx>
|
||||
# include <TopoDS.hxx>
|
||||
# include <TopExp_Explorer.hxx>
|
||||
# include <Precision.hxx>
|
||||
|
||||
# include <TopExp_Explorer.hxx>
|
||||
# include <TopoDS.hxx>
|
||||
|
||||
#include <Base/Exception.h>
|
||||
#include <Base/Tools.h>
|
||||
@@ -36,7 +35,6 @@
|
||||
#include "FeatureGroove.h"
|
||||
#include "Mod/Part/App/TopoShapeOpCode.h"
|
||||
|
||||
|
||||
using namespace PartDesign;
|
||||
|
||||
namespace PartDesign {
|
||||
@@ -47,7 +45,7 @@ const char* Groove::TypeEnums[]= {"Angle", "ThroughAll", "UpToFirst", "UpToFace"
|
||||
|
||||
PROPERTY_SOURCE(PartDesign::Groove, PartDesign::ProfileBased)
|
||||
|
||||
const App::PropertyAngle::Constraints Groove::floatAngle = { Base::toDegrees<double>(Precision::Angular()), 360.0, 1.0 };
|
||||
const App::PropertyAngle::Constraints Groove::floatAngle = { 0.0, 360.0, 1.0 };
|
||||
|
||||
Groove::Groove()
|
||||
{
|
||||
@@ -58,10 +56,10 @@ Groove::Groove()
|
||||
ADD_PROPERTY_TYPE(Base, (Base::Vector3d(0.0f,0.0f,0.0f)), "Groove", App::PropertyType(App::Prop_ReadOnly | App::Prop_Hidden), "Base");
|
||||
ADD_PROPERTY_TYPE(Axis, (Base::Vector3d(0.0f,1.0f,0.0f)), "Groove", App::PropertyType(App::Prop_ReadOnly | App::Prop_Hidden), "Axis");
|
||||
ADD_PROPERTY_TYPE(Angle, (360.0),"Groove", App::Prop_None, "Angle");
|
||||
ADD_PROPERTY_TYPE(Angle2, (60.0), "Groove", App::Prop_None, "Groove length in 2nd direction");
|
||||
ADD_PROPERTY_TYPE(Angle2, (0.0), "Groove", App::Prop_None, "Groove length in 2nd direction");
|
||||
ADD_PROPERTY_TYPE(UpToFace, (nullptr), "Groove", App::Prop_None, "Face where groove will end");
|
||||
Angle.setConstraints(&floatAngle);
|
||||
ADD_PROPERTY_TYPE(ReferenceAxis, (nullptr), "Groove", (App::PropertyType)(App::Prop_None), "Reference axis of Groove");
|
||||
ADD_PROPERTY_TYPE(ReferenceAxis, (nullptr), "Groove", (App::Prop_None), "Reference axis of groove");
|
||||
}
|
||||
|
||||
short Groove::mustExecute() const
|
||||
@@ -81,57 +79,63 @@ App::DocumentObjectExecReturn *Groove::execute()
|
||||
{
|
||||
if (onlyHaveRefined()) { return App::DocumentObject::StdReturn; }
|
||||
|
||||
constexpr double maxDegree = 360.0;
|
||||
auto method = methodFromString(Type.getValueAsString());
|
||||
|
||||
// Validate parameters
|
||||
double angle = Angle.getValue();
|
||||
if (angle > 360.0)
|
||||
return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Angle of groove too large"));
|
||||
|
||||
angle = Base::toRadians<double>(angle);
|
||||
if (angle < Precision::Angular())
|
||||
return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Angle of groove too small"));
|
||||
|
||||
// Reverse angle if selected
|
||||
if (Reversed.getValue() && !Midplane.getValue())
|
||||
angle *= (-1.0);
|
||||
|
||||
TopoShape sketchshape;
|
||||
try {
|
||||
sketchshape = getTopoShapeVerifiedFace();
|
||||
} catch (const Base::Exception& e) {
|
||||
return new App::DocumentObjectExecReturn(e.what());
|
||||
double angleDeg = Angle.getValue();
|
||||
if (angleDeg > maxDegree) {
|
||||
return new App::DocumentObjectExecReturn(
|
||||
QT_TRANSLATE_NOOP("Exception", "Angle of groove too large"));
|
||||
}
|
||||
|
||||
// if the Base property has a valid shape, fuse the prism into it
|
||||
double angle = Base::toRadians<double>(angleDeg);
|
||||
if (angle < Precision::Angular() && method == RevolMethod::Angle) {
|
||||
return new App::DocumentObjectExecReturn(
|
||||
QT_TRANSLATE_NOOP("Exception", "Angle of groove too small"));
|
||||
}
|
||||
|
||||
double angle2 = Base::toRadians(Angle2.getValue());
|
||||
if (std::fabs(angle + angle2) < Precision::Angular() && method == RevolMethod::TwoAngles) {
|
||||
return new App::DocumentObjectExecReturn(
|
||||
QT_TRANSLATE_NOOP("Exception", "Angles of groove nullify each other"));
|
||||
}
|
||||
|
||||
TopoShape sketchshape = getTopoShapeVerifiedFace();
|
||||
|
||||
// if the Base property has a valid shape, fuse the AddShape into it
|
||||
TopoShape base;
|
||||
try {
|
||||
base = getBaseTopoShape();
|
||||
}
|
||||
catch (const Base::Exception&) {
|
||||
std::string text(QT_TRANSLATE_NOOP("Exception", "The requested feature cannot be created. The reason may be that:\n"
|
||||
" - the active Body does not contain a base shape, so there is no\n"
|
||||
" material to be removed;\n"
|
||||
" - the selected sketch does not belong to the active Body."));
|
||||
return new App::DocumentObjectExecReturn(text);
|
||||
// fall back to support (for legacy features)
|
||||
}
|
||||
|
||||
updateAxis();
|
||||
|
||||
// get revolve axis
|
||||
Base::Vector3d b = Base.getValue();
|
||||
gp_Pnt pnt(b.x,b.y,b.z);
|
||||
Base::Vector3d v = Axis.getValue();
|
||||
gp_Dir dir(v.x,v.y,v.z);
|
||||
// update Axis from ReferenceAxis
|
||||
try {
|
||||
updateAxis();
|
||||
}
|
||||
catch (const Base::Exception& e) {
|
||||
return new App::DocumentObjectExecReturn(e.what());
|
||||
}
|
||||
|
||||
try {
|
||||
if (sketchshape.isNull())
|
||||
return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Creating a face from sketch failed"));
|
||||
// get revolve axis
|
||||
Base::Vector3d b = Base.getValue();
|
||||
gp_Pnt pnt(b.x, b.y, b.z);
|
||||
Base::Vector3d v = Axis.getValue();
|
||||
|
||||
// Rotate the face by half the angle to get Groove 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);
|
||||
if (v.IsNull()) {
|
||||
return new App::DocumentObjectExecReturn(
|
||||
QT_TRANSLATE_NOOP("Exception", "Reference axis is invalid"));
|
||||
}
|
||||
|
||||
gp_Dir dir(v.x, v.y, v.z);
|
||||
|
||||
if (sketchshape.isNull()) {
|
||||
return new App::DocumentObjectExecReturn(
|
||||
QT_TRANSLATE_NOOP("Exception", "Creating a face from sketch failed"));
|
||||
}
|
||||
|
||||
this->positionByPrevious();
|
||||
@@ -144,66 +148,112 @@ App::DocumentObjectExecReturn *Groove::execute()
|
||||
// Check distance between sketchshape and axis - to avoid failures and crashes
|
||||
TopExp_Explorer xp;
|
||||
xp.Init(sketchshape.getShape(), TopAbs_FACE);
|
||||
for (;xp.More(); xp.Next()) {
|
||||
if (checkLineCrossesFace(gp_Lin(pnt, dir), TopoDS::Face(xp.Current())))
|
||||
return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Revolve axis intersects the sketch"));
|
||||
}
|
||||
|
||||
// revolve the face to a solid
|
||||
TopoShape result(0);
|
||||
try {
|
||||
result.makeElementRevolve(sketchshape, gp_Ax1(pnt, dir), angle);
|
||||
}catch(Standard_Failure &) {
|
||||
return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Could not revolve the sketch!"));
|
||||
}
|
||||
this->AddSubShape.setValue(result);
|
||||
|
||||
if(base.isNull()) {
|
||||
Shape.setValue(getSolid(result));
|
||||
return App::DocumentObject::StdReturn;
|
||||
}
|
||||
|
||||
result.Tag = -getID();
|
||||
TopoShape boolOp(0);
|
||||
|
||||
try {
|
||||
const char *maker;
|
||||
switch (getAddSubType()) {
|
||||
case Additive:
|
||||
maker = Part::OpCodes::Fuse;
|
||||
break;
|
||||
// case Intersecting:
|
||||
// maker = Part::OpCodes::Common;
|
||||
// break;
|
||||
default:
|
||||
maker = Part::OpCodes::Cut;
|
||||
for (; xp.More(); xp.Next()) {
|
||||
if (checkLineCrossesFace(gp_Lin(pnt, dir), TopoDS::Face(xp.Current()))) {
|
||||
return new App::DocumentObjectExecReturn(
|
||||
QT_TRANSLATE_NOOP("Exception", "Revolve axis intersects the sketch"));
|
||||
}
|
||||
// this->fixShape(result);
|
||||
boolOp.makeElementBoolean(maker, {base,result});
|
||||
}catch(Standard_Failure &) {
|
||||
return new App::DocumentObjectExecReturn("Failed to cut base feature");
|
||||
}
|
||||
TopoShape solid = this->getSolid(boolOp);
|
||||
if (solid.isNull())
|
||||
return new App::DocumentObjectExecReturn("Resulting shape is not a solid");
|
||||
|
||||
// store shape before refinement
|
||||
this->rawShape = boolOp;
|
||||
boolOp = refineShapeIfActive(boolOp);
|
||||
if (!isSingleSolidRuleSatisfied(boolOp.getShape())) {
|
||||
return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Result has multiple solids: enable 'Allow Compound' in the active body."));
|
||||
// Create a fresh support even when base exists so that it can be used for patterns
|
||||
TopoShape result(0);
|
||||
TopoShape supportface(0);
|
||||
try {
|
||||
supportface = getSupportFace();
|
||||
}
|
||||
boolOp = getSolid(boolOp);
|
||||
Shape.setValue(boolOp);
|
||||
catch(...) {
|
||||
// do nothing, null shape is handled below
|
||||
}
|
||||
|
||||
supportface.move(invObjLoc);
|
||||
|
||||
if (method == RevolMethod::ToFace || method == RevolMethod::ToFirst) {
|
||||
TopoShape upToFace;
|
||||
if (method == RevolMethod::ToFace) {
|
||||
getUpToFaceFromLinkSub(upToFace, UpToFace);
|
||||
upToFace.move(invObjLoc);
|
||||
}
|
||||
else {
|
||||
throw Base::RuntimeError(
|
||||
"ProfileBased: Revolution up to first/last is not yet supported");
|
||||
}
|
||||
|
||||
if (Reversed.getValue()) {
|
||||
dir.Reverse();
|
||||
}
|
||||
|
||||
TopExp_Explorer Ex(supportface.getShape(), TopAbs_WIRE);
|
||||
if (!Ex.More()) {
|
||||
supportface = TopoDS_Face();
|
||||
}
|
||||
|
||||
try {
|
||||
result = base.makeElementRevolution(base,
|
||||
TopoDS::Face(sketchshape.getShape()),
|
||||
gp_Ax1(pnt, dir),
|
||||
TopoDS::Face(supportface.getShape()),
|
||||
TopoDS::Face(upToFace.getShape()),
|
||||
nullptr,
|
||||
Part::RevolMode::CutFromBase,
|
||||
Standard_True);
|
||||
}
|
||||
catch (Standard_Failure&) {
|
||||
return new App::DocumentObjectExecReturn("Could not revolve the sketch!");
|
||||
}
|
||||
}
|
||||
else {
|
||||
bool midplane = Midplane.getValue();
|
||||
bool reversed = Reversed.getValue();
|
||||
generateRevolution(result,
|
||||
sketchshape.getShape(),
|
||||
gp_Ax1(pnt, dir),
|
||||
angle,
|
||||
angle2,
|
||||
midplane,
|
||||
reversed,
|
||||
method);
|
||||
}
|
||||
|
||||
if (!result.isNull()) {
|
||||
// store shape before refinement
|
||||
this->rawShape = result;
|
||||
result = refineShapeIfActive(result);
|
||||
// set the additive shape property for later usage in e.g. pattern
|
||||
this->AddSubShape.setValue(result);
|
||||
|
||||
if (!base.isNull()) {
|
||||
result = base.makeElementCut(result);
|
||||
// store shape before refinement
|
||||
this->rawShape = result;
|
||||
result = refineShapeIfActive(result);
|
||||
}
|
||||
if (!isSingleSolidRuleSatisfied(result.getShape())) {
|
||||
return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Result has multiple solids: enable 'Allow Compound' in the active body."));
|
||||
}
|
||||
result = getSolid(result);
|
||||
this->Shape.setValue(result);
|
||||
}
|
||||
else {
|
||||
return new App::DocumentObjectExecReturn(
|
||||
QT_TRANSLATE_NOOP("Exception", "Could not revolve the sketch!"));
|
||||
}
|
||||
|
||||
// eventually disable some settings that are not valid for the current method
|
||||
updateProperties(method);
|
||||
|
||||
return App::DocumentObject::StdReturn;
|
||||
}
|
||||
catch (Standard_Failure& e) {
|
||||
|
||||
if (std::string(e.GetMessageString()) == "TopoDS::Face")
|
||||
return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Could not create face from sketch.\n"
|
||||
"Intersecting sketch entities in a sketch are not allowed."));
|
||||
else
|
||||
if (std::string(e.GetMessageString()) == "TopoDS::Face") {
|
||||
return new App::DocumentObjectExecReturn(
|
||||
QT_TRANSLATE_NOOP("Exception",
|
||||
"Could not create face from sketch.\n"
|
||||
"Intersecting sketch entities in a sketch are not allowed."));
|
||||
}
|
||||
else {
|
||||
return new App::DocumentObjectExecReturn(e.GetMessageString());
|
||||
}
|
||||
}
|
||||
catch (Base::Exception& e) {
|
||||
return new App::DocumentObjectExecReturn(e.what());
|
||||
@@ -212,7 +262,12 @@ App::DocumentObjectExecReturn *Groove::execute()
|
||||
|
||||
bool Groove::suggestReversed()
|
||||
{
|
||||
updateAxis();
|
||||
try {
|
||||
updateAxis();
|
||||
} catch (const Base::Exception&) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ProfileBased::getReversedAngle(Base.getValue(), Axis.getValue()) > 0.0;
|
||||
}
|
||||
|
||||
@@ -224,16 +279,14 @@ void Groove::updateAxis()
|
||||
Base::Vector3d dir;
|
||||
getAxis(pcReferenceAxis, subReferenceAxis, base, dir, ForbiddenAxis::NotParallelWithNormal);
|
||||
|
||||
if (dir.Length() > Precision::Confusion()) {
|
||||
Base.setValue(base.x,base.y,base.z);
|
||||
Axis.setValue(dir.x,dir.y,dir.z);
|
||||
}
|
||||
Base.setValue(base.x,base.y,base.z);
|
||||
Axis.setValue(dir.x,dir.y,dir.z);
|
||||
}
|
||||
|
||||
Groove::RevolMethod Groove::methodFromString(const std::string& methodStr)
|
||||
{
|
||||
if (methodStr == "Angle")
|
||||
return RevolMethod::Dimension;
|
||||
return RevolMethod::Angle;
|
||||
if (methodStr == "UpToLast")
|
||||
return RevolMethod::ToLast;
|
||||
if (methodStr == "ThroughAll")
|
||||
@@ -243,14 +296,13 @@ Groove::RevolMethod Groove::methodFromString(const std::string& methodStr)
|
||||
if (methodStr == "UpToFace")
|
||||
return RevolMethod::ToFace;
|
||||
if (methodStr == "TwoAngles")
|
||||
return RevolMethod::TwoDimensions;
|
||||
return RevolMethod::TwoAngles;
|
||||
|
||||
throw Base::ValueError("Groove:: No such method");
|
||||
return RevolMethod::Dimension;
|
||||
}
|
||||
|
||||
void Groove::generateRevolution(TopoDS_Shape& revol,
|
||||
const TopoDS_Shape& sketchshape,
|
||||
void Groove::generateRevolution(TopoShape& revol,
|
||||
const TopoShape& sketchshape,
|
||||
const gp_Ax1& axis,
|
||||
const double angle,
|
||||
const double angle2,
|
||||
@@ -258,11 +310,11 @@ void Groove::generateRevolution(TopoDS_Shape& revol,
|
||||
const bool reversed,
|
||||
RevolMethod method)
|
||||
{
|
||||
if (method == RevolMethod::Dimension || method == RevolMethod::TwoDimensions || method == RevolMethod::ThroughAll) {
|
||||
if (method == RevolMethod::Angle || method == RevolMethod::TwoAngles || method == RevolMethod::ThroughAll) {
|
||||
double angleTotal = angle;
|
||||
double angleOffset = 0.;
|
||||
|
||||
if (method == RevolMethod::TwoDimensions) {
|
||||
if (method == RevolMethod::TwoAngles) {
|
||||
// Rotate the face by `angle2`/`angle` to get "second" angle
|
||||
angleTotal += angle2;
|
||||
angleOffset = angle2 * -1.0;
|
||||
@@ -271,43 +323,41 @@ void Groove::generateRevolution(TopoDS_Shape& revol,
|
||||
angleTotal = 2 * std::numbers::pi;
|
||||
}
|
||||
else if (midplane) {
|
||||
// Rotate the face by half the angle to get Groove symmetric to sketch plane
|
||||
// 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.");
|
||||
|
||||
TopoDS_Shape from = sketchshape;
|
||||
if (method == RevolMethod::TwoDimensions || midplane) {
|
||||
gp_Trsf mov;
|
||||
mov.SetRotation(axis, angleOffset);
|
||||
TopLoc_Location loc(mov);
|
||||
from.Move(loc);
|
||||
gp_Ax1 revolAx(axis);
|
||||
if (reversed) {
|
||||
revolAx.Reverse();
|
||||
}
|
||||
else if (reversed) {
|
||||
angleTotal *= -1.0;
|
||||
|
||||
TopoShape from = sketchshape;
|
||||
if (method == RevolMethod::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, axis, angleTotal);
|
||||
|
||||
if (!RevolMaker.IsDone())
|
||||
throw Base::RuntimeError("ProfileBased: RevolMaker failed! Could not revolve the sketch!");
|
||||
else
|
||||
revol = RevolMaker.Shape();
|
||||
}
|
||||
else {
|
||||
revol = from;
|
||||
revol = revol.makeElementRevolve(revolAx,angleTotal);
|
||||
revol.Tag = -getID();
|
||||
} else {
|
||||
std::stringstream str;
|
||||
str << "ProfileBased: Internal error: Unknown method for generateGroove()";
|
||||
str << "ProfileBased: Internal error: Unknown method for generateRevolution()";
|
||||
throw Base::RuntimeError(str.str());
|
||||
}
|
||||
}
|
||||
|
||||
void Groove::generateRevolution(TopoDS_Shape& revol,
|
||||
const TopoDS_Shape& baseshape,
|
||||
void Groove::generateRevolution(TopoShape& revol,
|
||||
const TopoShape& baseshape,
|
||||
const TopoDS_Shape& profileshape,
|
||||
const TopoDS_Face& supportface,
|
||||
const TopoDS_Face& uptoface,
|
||||
@@ -317,20 +367,8 @@ void Groove::generateRevolution(TopoDS_Shape& revol,
|
||||
Standard_Boolean Modify)
|
||||
{
|
||||
if (method == RevolMethod::ToFirst || method == RevolMethod::ToFace || method == RevolMethod::ToLast) {
|
||||
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;
|
||||
revol = revol.makeElementRevolution(baseshape, profileshape, axis, supportface, uptoface, nullptr,
|
||||
static_cast<Part::RevolMode>(Mode), Modify, nullptr);
|
||||
}
|
||||
else {
|
||||
std::stringstream str;
|
||||
@@ -348,7 +386,7 @@ void Groove::updateProperties(RevolMethod method)
|
||||
bool isMidplaneEnabled = false;
|
||||
bool isReversedEnabled = false;
|
||||
bool isUpToFaceEnabled = false;
|
||||
if (method == RevolMethod::Dimension) {
|
||||
if (method == RevolMethod::Angle) {
|
||||
isAngleEnabled = true;
|
||||
isMidplaneEnabled = true;
|
||||
isReversedEnabled = !Midplane.getValue();
|
||||
@@ -367,7 +405,7 @@ void Groove::updateProperties(RevolMethod method)
|
||||
isReversedEnabled = true;
|
||||
isUpToFaceEnabled = true;
|
||||
}
|
||||
else if (method == RevolMethod::TwoDimensions) {
|
||||
else if (method == RevolMethod::TwoAngles) {
|
||||
isAngleEnabled = true;
|
||||
isAngle2Enabled = true;
|
||||
isReversedEnabled = true;
|
||||
@@ -380,7 +418,5 @@ void Groove::updateProperties(RevolMethod method)
|
||||
UpToFace.setReadOnly(!isUpToFaceEnabled);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -69,12 +69,12 @@ public:
|
||||
bool suggestReversed();
|
||||
|
||||
enum class RevolMethod {
|
||||
Dimension,
|
||||
Angle,
|
||||
ThroughAll,
|
||||
ToLast = ThroughAll,
|
||||
ToFirst,
|
||||
ToFace,
|
||||
TwoDimensions
|
||||
TwoAngles
|
||||
};
|
||||
|
||||
protected:
|
||||
@@ -95,8 +95,8 @@ protected:
|
||||
/**
|
||||
* Generates a [groove] of the input sketchshape and stores it in the given \a revol.
|
||||
*/
|
||||
void generateRevolution(TopoDS_Shape& revol,
|
||||
const TopoDS_Shape& sketchshape,
|
||||
void generateRevolution(TopoShape& revol,
|
||||
const TopoShape& sketchshape,
|
||||
const gp_Ax1& ax1,
|
||||
const double angle,
|
||||
const double angle2,
|
||||
@@ -108,8 +108,8 @@ protected:
|
||||
* Generates a [groove] of the input \a profileshape.
|
||||
* It will be a stand-alone solid created with BRepFeat_MakeRevol.
|
||||
*/
|
||||
void generateRevolution(TopoDS_Shape& revol,
|
||||
const TopoDS_Shape& baseshape,
|
||||
void generateRevolution(TopoShape& revol,
|
||||
const TopoShape& baseshape,
|
||||
const TopoDS_Shape& profileshape,
|
||||
const TopoDS_Face& supportface,
|
||||
const TopoDS_Face& uptoface,
|
||||
|
||||
@@ -393,6 +393,10 @@ gp_Dir LinearPattern::getDirectionFromProperty(const App::PropertyLinkSub& dirPr
|
||||
Base::Vector3d d = line->getDirection();
|
||||
dir = gp_Dir(d.x, d.y, d.z);
|
||||
}
|
||||
else if (auto* plane = freecad_cast<App::Plane*>(refObject)) {
|
||||
Base::Vector3d d = plane->getDirection();
|
||||
dir = gp_Dir(d.x, d.y, d.z);
|
||||
}
|
||||
else if (auto* line = freecad_cast<App::Line*>(refObject)) {
|
||||
Base::Vector3d d = line->getDirection();
|
||||
dir = gp_Dir(d.x, d.y, d.z);
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
# include <TopTools_HSequenceOfShape.hxx>
|
||||
|
||||
|
||||
#include <App/Document.h>
|
||||
#include <App/DocumentObject.h>
|
||||
#include <Base/Exception.h>
|
||||
#include <Base/Reader.h>
|
||||
@@ -151,7 +152,6 @@ App::DocumentObjectExecReturn *Pipe::execute()
|
||||
// As the shell begins always at the spine and not the profile, the sketchshape
|
||||
// cannot be used directly as front face. We would need a method to translate
|
||||
// the front shape to match the shell starting position somehow...
|
||||
std::vector<TopoDS_Wire> wires;
|
||||
TopoDS_Shape profilePoint;
|
||||
|
||||
// if the Base property has a valid shape, fuse the pipe into it
|
||||
@@ -162,6 +162,8 @@ App::DocumentObjectExecReturn *Pipe::execute()
|
||||
base = TopoShape();
|
||||
}
|
||||
|
||||
auto hasher = getDocument()->getStringHasher();
|
||||
|
||||
try {
|
||||
// setup the location
|
||||
this->positionByPrevious();
|
||||
@@ -287,7 +289,7 @@ App::DocumentObjectExecReturn *Pipe::execute()
|
||||
"Exception", "Path must not be a null shape"));
|
||||
|
||||
// build all shells
|
||||
std::vector<TopoDS_Shape> shells;
|
||||
std::vector<TopoShape> shells;
|
||||
|
||||
TopoDS_Shape copyProfilePoint(profilePoint);
|
||||
if (!profilePoint.IsNull())
|
||||
@@ -320,7 +322,7 @@ App::DocumentObjectExecReturn *Pipe::execute()
|
||||
if (!mkPS.IsReady())
|
||||
return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Pipe could not be built"));
|
||||
|
||||
shells.push_back(mkPS.Shape());
|
||||
shells.emplace_back(mkPS.Shape());
|
||||
|
||||
if (!mkPS.Shape().Closed()) {
|
||||
// shell is not closed - use simulate to get the end wires
|
||||
@@ -336,8 +338,7 @@ App::DocumentObjectExecReturn *Pipe::execute()
|
||||
}
|
||||
}
|
||||
|
||||
BRepBuilderAPI_MakeSolid mkSolid;
|
||||
|
||||
TopoShape result(0, hasher);
|
||||
if (!frontwires.empty() || !backwires.empty()) {
|
||||
BRepBuilderAPI_Sewing sewer;
|
||||
sewer.SetTolerance(Precision::Confusion());
|
||||
@@ -346,94 +347,103 @@ App::DocumentObjectExecReturn *Pipe::execute()
|
||||
if (!frontwires.empty()) {
|
||||
TopoDS_Shape front = Part::FaceMakerCheese::makeFace(frontwires);
|
||||
sewer.Add(front);
|
||||
shells.emplace_back(front);
|
||||
}
|
||||
if (!backwires.empty()) {
|
||||
TopoDS_Shape back = Part::FaceMakerCheese::makeFace(backwires);
|
||||
sewer.Add(back);
|
||||
shells.emplace_back(back);
|
||||
}
|
||||
for (TopoDS_Shape& s : shells)
|
||||
sewer.Add(s);
|
||||
for (TopoShape& s : shells)
|
||||
sewer.Add(s.getShape());
|
||||
|
||||
sewer.Perform();
|
||||
mkSolid.Add(TopoDS::Shell(sewer.SewedShape())); } else {
|
||||
result = result.makeShapeWithElementMap(sewer.SewedShape(), Part::MapperSewing(sewer), shells, Part::OpCodes::Sewing);
|
||||
} else {
|
||||
// shells are already closed - add them directly
|
||||
for (TopoDS_Shape& s : shells) {
|
||||
mkSolid.Add(TopoDS::Shell(s));
|
||||
BRepBuilderAPI_MakeSolid mkSolid;
|
||||
for (TopoShape& s : shells) {
|
||||
mkSolid.Add(TopoDS::Shell(s.getShape()));
|
||||
}
|
||||
|
||||
if (!mkSolid.IsDone())
|
||||
return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Result is not a solid"));
|
||||
result.setShape(mkSolid.Shape());
|
||||
}
|
||||
|
||||
if (!mkSolid.IsDone())
|
||||
return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Result is not a solid"));
|
||||
if(!result.countSubShapes(TopAbs_SHELL))
|
||||
return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Loft: Failed to create shell"));
|
||||
|
||||
TopoDS_Shape result = mkSolid.Shape();
|
||||
BRepClass3d_SolidClassifier SC(result);
|
||||
SC.PerformInfinitePoint(Precision::Confusion());
|
||||
if (SC.State() == TopAbs_IN) {
|
||||
result.Reverse();
|
||||
auto shapes = result.getSubTopoShapes(TopAbs_SHELL);
|
||||
for (auto &s : shapes) {
|
||||
// build the solid
|
||||
s = s.makeElementSolid();
|
||||
BRepClass3d_SolidClassifier SC(s.getShape());
|
||||
SC.PerformInfinitePoint(Precision::Confusion());
|
||||
if ( SC.State() == TopAbs_IN)
|
||||
s.setShape(s.getShape().Reversed(),false);
|
||||
}
|
||||
|
||||
//result.Move(invObjLoc);
|
||||
AddSubShape.setValue(result); // Converts result to a TopoShape, but no tag.
|
||||
AddSubShape.setValue(result.makeElementCompound(shapes, nullptr, Part::TopoShape::SingleShapeCompoundCreationPolicy::returnShape));
|
||||
|
||||
if (base.isNull()) {
|
||||
if (shapes.size() > 1)
|
||||
result.makeElementFuse(shapes);
|
||||
else
|
||||
result = shapes.front();
|
||||
|
||||
if(base.isNull()) {
|
||||
if (getAddSubType() == FeatureAddSub::Subtractive)
|
||||
return new App::DocumentObjectExecReturn(
|
||||
QT_TRANSLATE_NOOP("Exception", "Pipe: There is nothing to subtract from"));
|
||||
|
||||
if (!isSingleSolidRuleSatisfied(result.getShape())) {
|
||||
return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Result has multiple solids: enable 'Allow Compound' in the active body."));
|
||||
}
|
||||
|
||||
// store shape before refinement
|
||||
this->rawShape = result;
|
||||
auto ts_result = refineShapeIfActive(result);
|
||||
Shape.setValue(getSolid(ts_result));
|
||||
|
||||
result = refineShapeIfActive(result);
|
||||
Shape.setValue(getSolid(result));
|
||||
return App::DocumentObject::StdReturn;
|
||||
}
|
||||
|
||||
if (getAddSubType() == FeatureAddSub::Additive) {
|
||||
|
||||
FCBRepAlgoAPI_Fuse mkFuse(base.getShape(), result);
|
||||
if (!mkFuse.IsDone())
|
||||
return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Adding the pipe failed"));
|
||||
// we have to get the solids (fuse sometimes creates compounds)
|
||||
TopoShape boolOp = this->getSolid(mkFuse.Shape());
|
||||
// lets check if the result is a solid
|
||||
if (boolOp.isNull())
|
||||
return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Resulting shape is not a solid"));
|
||||
|
||||
if (!isSingleSolidRuleSatisfied(boolOp.getShape())) {
|
||||
return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception",
|
||||
"Result has multiple solids: enable 'Allow Compound' in the active body."));
|
||||
}
|
||||
|
||||
// store shape before refinement
|
||||
this->rawShape = boolOp;
|
||||
boolOp = refineShapeIfActive(boolOp);
|
||||
Shape.setValue(getSolid(boolOp));
|
||||
TopoShape boolOp(0, getDocument()->getStringHasher());
|
||||
const char *maker;
|
||||
switch (getAddSubType()) {
|
||||
case Additive:
|
||||
maker = Part::OpCodes::Fuse;
|
||||
break;
|
||||
case Subtractive:
|
||||
maker = Part::OpCodes::Cut;
|
||||
break;
|
||||
default:
|
||||
return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Unknown operation type"));
|
||||
}
|
||||
else if (getAddSubType() == FeatureAddSub::Subtractive) {
|
||||
|
||||
FCBRepAlgoAPI_Cut mkCut(base.getShape(), result);
|
||||
if (!mkCut.IsDone())
|
||||
return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Subtracting the pipe failed"));
|
||||
// we have to get the solids (fuse sometimes creates compounds)
|
||||
TopoShape boolOp = this->getSolid(mkCut.Shape());
|
||||
// lets check if the result is a solid
|
||||
if (boolOp.isNull())
|
||||
return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Resulting shape is not a solid"));
|
||||
|
||||
if (!isSingleSolidRuleSatisfied(boolOp.getShape())) {
|
||||
return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception",
|
||||
"Result has multiple solids: enable 'Allow Compound' in the active body."));
|
||||
}
|
||||
|
||||
// store shape before refinement
|
||||
this->rawShape = boolOp;
|
||||
boolOp = refineShapeIfActive(boolOp);
|
||||
Shape.setValue(getSolid(boolOp));
|
||||
try {
|
||||
boolOp.makeElementBoolean(maker, {base,result});
|
||||
}
|
||||
catch(Standard_Failure&) {
|
||||
return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Failed to perform boolean operation"));
|
||||
}
|
||||
|
||||
TopoShape solid = getSolid(boolOp);
|
||||
// lets check if the result is a solid
|
||||
if (solid.isNull())
|
||||
return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Resulting shape is not a solid"));
|
||||
|
||||
// store shape before refinement
|
||||
this->rawShape = boolOp;
|
||||
boolOp = refineShapeIfActive(boolOp);
|
||||
if (!isSingleSolidRuleSatisfied(boolOp.getShape())) {
|
||||
return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception",
|
||||
"Result has multiple solids: enable 'Allow Compound' in the active body."));
|
||||
}
|
||||
boolOp = getSolid(boolOp);
|
||||
Shape.setValue(boolOp);
|
||||
return App::DocumentObject::StdReturn;
|
||||
}
|
||||
catch (Standard_Failure& e) {
|
||||
|
||||
return new App::DocumentObjectExecReturn(e.GetMessageString());
|
||||
}
|
||||
catch (...) {
|
||||
@@ -636,4 +646,3 @@ void Pipe::handleChangedPropertyName(Base::XMLReader& reader,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -30,9 +30,7 @@
|
||||
# include <TopoDS.hxx>
|
||||
|
||||
|
||||
#include <Base/Axis.h>
|
||||
#include <Base/Exception.h>
|
||||
#include <Base/Placement.h>
|
||||
#include <Base/Tools.h>
|
||||
|
||||
#include "FeatureRevolution.h"
|
||||
@@ -42,11 +40,13 @@ using namespace PartDesign;
|
||||
|
||||
namespace PartDesign {
|
||||
|
||||
/* TRANSLATOR PartDesign::Revolution */
|
||||
|
||||
const char* Revolution::TypeEnums[]= {"Angle", "UpToLast", "UpToFirst", "UpToFace", "TwoAngles", nullptr};
|
||||
|
||||
PROPERTY_SOURCE(PartDesign::Revolution, PartDesign::ProfileBased)
|
||||
|
||||
const App::PropertyAngle::Constraints Revolution::floatAngle = { Base::toDegrees<double>(Precision::Angular()), 360.0, 1.0 };
|
||||
const App::PropertyAngle::Constraints Revolution::floatAngle = { 0.0, 360.0, 1.0 };
|
||||
|
||||
Revolution::Revolution()
|
||||
{
|
||||
@@ -54,14 +54,14 @@ Revolution::Revolution()
|
||||
|
||||
ADD_PROPERTY_TYPE(Type, (0L), "Revolution", App::Prop_None, "Revolution type");
|
||||
Type.setEnums(TypeEnums);
|
||||
ADD_PROPERTY_TYPE(Base,(Base::Vector3d(0.0,0.0,0.0)),"Revolution", App::PropertyType(App::Prop_ReadOnly | App::Prop_Hidden), "Base");
|
||||
ADD_PROPERTY_TYPE(Axis,(Base::Vector3d(0.0,1.0,0.0)),"Revolution", App::PropertyType(App::Prop_ReadOnly | App::Prop_Hidden), "Axis");
|
||||
ADD_PROPERTY_TYPE(Angle,(360.0),"Revolution", App::Prop_None, "Angle");
|
||||
ADD_PROPERTY_TYPE(Angle2, (60.0), "Revolution", App::Prop_None, "Revolution length in 2nd direction");
|
||||
ADD_PROPERTY_TYPE(Base, (Base::Vector3d(0.0,0.0,0.0)), "Revolution", App::PropertyType(App::Prop_ReadOnly | App::Prop_Hidden), "Base");
|
||||
ADD_PROPERTY_TYPE(Axis, (Base::Vector3d(0.0,1.0,0.0)), "Revolution", App::PropertyType(App::Prop_ReadOnly | App::Prop_Hidden), "Axis");
|
||||
ADD_PROPERTY_TYPE(Angle, (360.0), "Revolution", App::Prop_None, "Angle");
|
||||
ADD_PROPERTY_TYPE(Angle2, (0.0), "Revolution", App::Prop_None, "Revolution length in 2nd direction");
|
||||
ADD_PROPERTY_TYPE(UpToFace, (nullptr), "Revolution", App::Prop_None, "Face where revolution will end");
|
||||
Angle.setConstraints(&floatAngle);
|
||||
Angle2.setConstraints(&floatAngle);
|
||||
ADD_PROPERTY_TYPE(ReferenceAxis,(nullptr),"Revolution",(App::Prop_None),"Reference axis of revolution");
|
||||
ADD_PROPERTY_TYPE(ReferenceAxis, (nullptr), "Revolution", (App::Prop_None), "Reference axis of revolution");
|
||||
}
|
||||
|
||||
short Revolution::mustExecute() const
|
||||
@@ -82,21 +82,27 @@ App::DocumentObjectExecReturn* Revolution::execute()
|
||||
if (onlyHaveRefined()) { return App::DocumentObject::StdReturn; }
|
||||
|
||||
|
||||
constexpr double maxDegree = 360.0;
|
||||
auto method = methodFromString(Type.getValueAsString());
|
||||
|
||||
// Validate parameters
|
||||
// All angles are in radians unless explicitly stated
|
||||
double angleDeg = Angle.getValue();
|
||||
if (angleDeg > 360.0) {
|
||||
if (angleDeg > maxDegree) {
|
||||
return new App::DocumentObjectExecReturn(
|
||||
QT_TRANSLATE_NOOP("Exception", "Angle of revolution too large"));
|
||||
}
|
||||
|
||||
double angle = Base::toRadians<double>(angleDeg);
|
||||
if (angle < Precision::Angular()) {
|
||||
if (angle < Precision::Angular() && method == RevolMethod::Angle) {
|
||||
return new App::DocumentObjectExecReturn(
|
||||
QT_TRANSLATE_NOOP("Exception", "Angle of revolution too small"));
|
||||
}
|
||||
|
||||
double angle2 = Base::toRadians(Angle2.getValue());
|
||||
if (std::fabs(angle + angle2) < Precision::Angular() && method == RevolMethod::TwoAngles) {
|
||||
return new App::DocumentObjectExecReturn(
|
||||
QT_TRANSLATE_NOOP("Exception", "Angles of revolution nullify each other"));
|
||||
}
|
||||
|
||||
TopoShape sketchshape = getTopoShapeVerifiedFace();
|
||||
|
||||
@@ -135,10 +141,8 @@ App::DocumentObjectExecReturn* Revolution::execute()
|
||||
QT_TRANSLATE_NOOP("Exception", "Creating a face from sketch failed"));
|
||||
}
|
||||
|
||||
RevolMethod method = methodFromString(Type.getValueAsString());
|
||||
|
||||
this->positionByPrevious();
|
||||
TopLoc_Location invObjLoc = this->getLocation().Inverted();
|
||||
auto invObjLoc = getLocation().Inverted();
|
||||
pnt.Transform(invObjLoc.Transformation());
|
||||
dir.Transform(invObjLoc.Transformation());
|
||||
base.move(invObjLoc);
|
||||
@@ -166,8 +170,7 @@ App::DocumentObjectExecReturn* Revolution::execute()
|
||||
|
||||
supportface.move(invObjLoc);
|
||||
|
||||
if (method == RevolMethod::ToFace || method == RevolMethod::ToFirst
|
||||
|| method == RevolMethod::ToLast) {
|
||||
if (method == RevolMethod::ToFace || method == RevolMethod::ToFirst) {
|
||||
TopoShape upToFace;
|
||||
if (method == RevolMethod::ToFace) {
|
||||
getUpToFaceFromLinkSub(upToFace, UpToFace);
|
||||
@@ -194,7 +197,7 @@ App::DocumentObjectExecReturn* Revolution::execute()
|
||||
TopoDS::Face(supportface.getShape()),
|
||||
TopoDS::Face(upToFace.getShape()),
|
||||
nullptr,
|
||||
Part::RevolMode::None,
|
||||
Part::RevolMode::FuseWithBase,
|
||||
Standard_True);
|
||||
}
|
||||
catch (Standard_Failure&) {
|
||||
@@ -286,7 +289,7 @@ void Revolution::updateAxis()
|
||||
Revolution::RevolMethod Revolution::methodFromString(const std::string& methodStr)
|
||||
{
|
||||
if (methodStr == "Angle")
|
||||
return RevolMethod::Dimension;
|
||||
return RevolMethod::Angle;
|
||||
if (methodStr == "UpToLast")
|
||||
return RevolMethod::ToLast;
|
||||
if (methodStr == "ThroughAll")
|
||||
@@ -296,10 +299,9 @@ Revolution::RevolMethod Revolution::methodFromString(const std::string& methodSt
|
||||
if (methodStr == "UpToFace")
|
||||
return RevolMethod::ToFace;
|
||||
if (methodStr == "TwoAngles")
|
||||
return RevolMethod::TwoDimensions;
|
||||
return RevolMethod::TwoAngles;
|
||||
|
||||
throw Base::ValueError("Revolution:: No such method");
|
||||
return RevolMethod::Dimension;
|
||||
}
|
||||
|
||||
void Revolution::generateRevolution(TopoShape& revol,
|
||||
@@ -311,15 +313,18 @@ void Revolution::generateRevolution(TopoShape& revol,
|
||||
const bool reversed,
|
||||
RevolMethod method)
|
||||
{
|
||||
if (method == RevolMethod::Dimension || method == RevolMethod::TwoDimensions || method == RevolMethod::ThroughAll) {
|
||||
if (method == RevolMethod::Angle || method == RevolMethod::TwoAngles || method == RevolMethod::ThroughAll) {
|
||||
double angleTotal = angle;
|
||||
double angleOffset = 0.;
|
||||
|
||||
if (method == RevolMethod::TwoDimensions) {
|
||||
if (method == RevolMethod::TwoAngles) {
|
||||
// Rotate the face by `angle2`/`angle` to get "second" angle
|
||||
angleTotal += angle2;
|
||||
angleOffset = angle2 * -1.0;
|
||||
}
|
||||
else if (method == RevolMethod::ThroughAll) {
|
||||
angleTotal = 2 * M_PI;
|
||||
}
|
||||
else if (midplane) {
|
||||
// Rotate the face by half the angle to get Revolution symmetric to sketch plane
|
||||
angleOffset = -angle / 2;
|
||||
@@ -334,13 +339,16 @@ void Revolution::generateRevolution(TopoShape& revol,
|
||||
}
|
||||
|
||||
TopoShape from = sketchshape;
|
||||
if (method == RevolMethod::TwoDimensions || midplane) {
|
||||
if (method == RevolMethod::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.
|
||||
revol = from;
|
||||
revol = revol.makeElementRevolve(revolAx,angleTotal);
|
||||
revol.Tag = -getID();
|
||||
@@ -381,7 +389,7 @@ void Revolution::updateProperties(RevolMethod method)
|
||||
bool isMidplaneEnabled = false;
|
||||
bool isReversedEnabled = false;
|
||||
bool isUpToFaceEnabled = false;
|
||||
if (method == RevolMethod::Dimension) {
|
||||
if (method == RevolMethod::Angle) {
|
||||
isAngleEnabled = true;
|
||||
isMidplaneEnabled = true;
|
||||
isReversedEnabled = !Midplane.getValue();
|
||||
@@ -400,7 +408,7 @@ void Revolution::updateProperties(RevolMethod method)
|
||||
isReversedEnabled = true;
|
||||
isUpToFaceEnabled = true;
|
||||
}
|
||||
else if (method == RevolMethod::TwoDimensions) {
|
||||
else if (method == RevolMethod::TwoAngles) {
|
||||
isAngleEnabled = true;
|
||||
isAngle2Enabled = true;
|
||||
isReversedEnabled = true;
|
||||
|
||||
@@ -69,12 +69,12 @@ public:
|
||||
bool suggestReversed();
|
||||
|
||||
enum class RevolMethod {
|
||||
Dimension,
|
||||
Angle,
|
||||
ThroughAll,
|
||||
ToLast = ThroughAll,
|
||||
ToFirst,
|
||||
ToFace,
|
||||
TwoDimensions
|
||||
TwoAngles
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
@@ -57,7 +57,6 @@ namespace sp = std::placeholders;
|
||||
TaskHoleParameters::TaskHoleParameters(ViewProviderHole* HoleView, QWidget* parent)
|
||||
: TaskSketchBasedParameters(HoleView, parent, "PartDesign_Hole", tr("Hole Parameters"))
|
||||
, observer(new Observer(this, getObject<PartDesign::Hole>()))
|
||||
, isApplying(false)
|
||||
, ui(new Ui_TaskHoleParameters)
|
||||
{
|
||||
// we need a separate container widget to add all controls to
|
||||
@@ -1087,8 +1086,6 @@ void TaskHoleParameters::apply()
|
||||
{
|
||||
auto hole = getObject<PartDesign::Hole>();
|
||||
|
||||
isApplying = true;
|
||||
|
||||
ui->Diameter->apply();
|
||||
ui->HoleCutDiameter->apply();
|
||||
ui->HoleCutDepth->apply();
|
||||
@@ -1152,8 +1149,6 @@ void TaskHoleParameters::apply()
|
||||
if (!hole->BaseProfileType.isReadOnly()) {
|
||||
FCMD_OBJ_CMD(hole, "BaseProfileType = " << getBaseProfileType());
|
||||
}
|
||||
|
||||
isApplying = false;
|
||||
}
|
||||
|
||||
void TaskHoleParameters::updateHoleCutLimits(PartDesign::Hole* hole)
|
||||
|
||||
@@ -143,7 +143,6 @@ private:
|
||||
Connection connectPropChanged;
|
||||
|
||||
std::unique_ptr<Observer> observer;
|
||||
bool isApplying;
|
||||
QWidget* proxy;
|
||||
std::unique_ptr<Ui_TaskHoleParameters> ui;
|
||||
|
||||
|
||||
@@ -188,7 +188,7 @@ void TaskRevolutionParameters::setupDialog()
|
||||
void TaskRevolutionParameters::translateModeList(int index)
|
||||
{
|
||||
ui->changeMode->clear();
|
||||
ui->changeMode->addItem(tr("Dimension"));
|
||||
ui->changeMode->addItem(tr("Angle"));
|
||||
if (!isGroove) {
|
||||
ui->changeMode->addItem(tr("To last"));
|
||||
}
|
||||
@@ -197,7 +197,7 @@ void TaskRevolutionParameters::translateModeList(int index)
|
||||
}
|
||||
ui->changeMode->addItem(tr("To first"));
|
||||
ui->changeMode->addItem(tr("Up to face"));
|
||||
ui->changeMode->addItem(tr("Two dimensions"));
|
||||
ui->changeMode->addItem(tr("Two angles"));
|
||||
ui->changeMode->setCurrentIndex(index);
|
||||
}
|
||||
|
||||
@@ -294,7 +294,7 @@ void TaskRevolutionParameters::setCheckboxes(PartDesign::Revolution::RevolMethod
|
||||
bool isReversedEnabled = false;
|
||||
bool isFaceEditEnabled = false;
|
||||
|
||||
if (mode == PartDesign::Revolution::RevolMethod::Dimension) {
|
||||
if (mode == PartDesign::Revolution::RevolMethod::Angle) {
|
||||
isRevolveAngleVisible = true;
|
||||
ui->revolveAngle->selectNumber();
|
||||
QMetaObject::invokeMethod(ui->revolveAngle, "setFocus", Qt::QueuedConnection);
|
||||
@@ -320,7 +320,7 @@ void TaskRevolutionParameters::setCheckboxes(PartDesign::Revolution::RevolMethod
|
||||
ui->buttonFace->setChecked(true);
|
||||
}
|
||||
}
|
||||
else if (mode == PartDesign::Revolution::RevolMethod::TwoDimensions) {
|
||||
else if (mode == PartDesign::Revolution::RevolMethod::TwoAngles) {
|
||||
isRevolveAngleVisible = true;
|
||||
isRevolveAngle2Visible = true;
|
||||
isReversedEnabled = true;
|
||||
@@ -624,7 +624,7 @@ void TaskRevolutionParameters::onModeChanged(int index)
|
||||
: &(getObject<PartDesign::Revolution>()->Type);
|
||||
|
||||
switch (static_cast<PartDesign::Revolution::RevolMethod>(index)) {
|
||||
case PartDesign::Revolution::RevolMethod::Dimension:
|
||||
case PartDesign::Revolution::RevolMethod::Angle:
|
||||
propEnum->setValue("Angle");
|
||||
break;
|
||||
case PartDesign::Revolution::RevolMethod::ToLast:
|
||||
@@ -636,7 +636,7 @@ void TaskRevolutionParameters::onModeChanged(int index)
|
||||
case PartDesign::Revolution::RevolMethod::ToFace:
|
||||
propEnum->setValue("UpToFace");
|
||||
break;
|
||||
case PartDesign::Revolution::RevolMethod::TwoDimensions:
|
||||
case PartDesign::Revolution::RevolMethod::TwoAngles:
|
||||
propEnum->setValue("TwoAngles");
|
||||
break;
|
||||
}
|
||||
@@ -809,12 +809,12 @@ void TaskRevolutionParameters::setGizmoVisibility()
|
||||
auto type = static_cast<PartDesign::Revolution::RevolMethod>(ui->changeMode->currentIndex());
|
||||
|
||||
switch (type) {
|
||||
case PartDesign::Revolution::RevolMethod::Dimension:
|
||||
case PartDesign::Revolution::RevolMethod::Angle:
|
||||
gizmoContainer->visible = true;
|
||||
rotationGizmo->setVisibility(true);
|
||||
rotationGizmo2->setVisibility(false);
|
||||
break;
|
||||
case PartDesign::Revolution::RevolMethod::TwoDimensions:
|
||||
case PartDesign::Revolution::RevolMethod::TwoAngles:
|
||||
gizmoContainer->visible = true;
|
||||
rotationGizmo->setVisibility(true);
|
||||
rotationGizmo2->setVisibility(true);
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
<widget class="QComboBox" name="changeMode">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Dimension</string>
|
||||
<string notr="true">Angle</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
@@ -139,7 +139,7 @@
|
||||
<double>10.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>60.000000000000000</double>
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -162,6 +162,19 @@ void Workbench::activated()
|
||||
"PartDesign_Body"
|
||||
));
|
||||
|
||||
const char* Vertex1[] = {
|
||||
"PartDesign_Point",
|
||||
"PartDesign_Line",
|
||||
"PartDesign_Plane",
|
||||
"PartDesign_CoordinateSystem",
|
||||
nullptr};
|
||||
Watcher.push_back(new Gui::TaskView::TaskWatcherCommands(
|
||||
"SELECT Part::Feature SUBELEMENT Vertex COUNT 1..",
|
||||
Vertex1,
|
||||
"Datum objects",
|
||||
"PartDesign_CoordinateSystem"
|
||||
));
|
||||
|
||||
const char* Edge[] = {
|
||||
"PartDesign_Fillet",
|
||||
"PartDesign_Chamfer",
|
||||
@@ -177,6 +190,19 @@ void Workbench::activated()
|
||||
"PartDesign_Body"
|
||||
));
|
||||
|
||||
const char* Edge1[] = {
|
||||
"PartDesign_Point",
|
||||
"PartDesign_Line",
|
||||
"PartDesign_Plane",
|
||||
"PartDesign_CoordinateSystem",
|
||||
nullptr};
|
||||
Watcher.push_back(new Gui::TaskView::TaskWatcherCommands(
|
||||
"SELECT Part::Feature SUBELEMENT Edge COUNT 1..",
|
||||
Edge1,
|
||||
"Datum objects",
|
||||
"PartDesign_CoordinateSystem"
|
||||
));
|
||||
|
||||
const char* Face[] = {
|
||||
"PartDesign_NewSketch",
|
||||
"PartDesign_Fillet",
|
||||
@@ -195,6 +221,19 @@ void Workbench::activated()
|
||||
"PartDesign_Body"
|
||||
));
|
||||
|
||||
const char* Face1[] = {
|
||||
"PartDesign_Point",
|
||||
"PartDesign_Line",
|
||||
"PartDesign_Plane",
|
||||
"PartDesign_CoordinateSystem",
|
||||
nullptr};
|
||||
Watcher.push_back(new Gui::TaskView::TaskWatcherCommands(
|
||||
"SELECT Part::Feature SUBELEMENT Face COUNT 1",
|
||||
Face1,
|
||||
"Datum objects",
|
||||
"PartDesign_CoordinateSystem"
|
||||
));
|
||||
|
||||
const char* Body[] = {
|
||||
"PartDesign_NewSketch",
|
||||
nullptr};
|
||||
@@ -228,6 +267,7 @@ void Workbench::activated()
|
||||
"Helper Tools",
|
||||
"PartDesign_Body"
|
||||
));
|
||||
|
||||
const char* Plane2[] = {
|
||||
"PartDesign_NewSketch",
|
||||
"Part_DatumPoint",
|
||||
@@ -242,6 +282,32 @@ void Workbench::activated()
|
||||
"PartDesign_Body"
|
||||
));
|
||||
|
||||
const char* Plane3[] = {
|
||||
"PartDesign_Point",
|
||||
"PartDesign_Line",
|
||||
"PartDesign_Plane",
|
||||
"PartDesign_CoordinateSystem",
|
||||
nullptr};
|
||||
Watcher.push_back(new Gui::TaskView::TaskWatcherCommands(
|
||||
"SELECT App::Plane COUNT 1",
|
||||
Plane3,
|
||||
"Datum objects",
|
||||
"PartDesign_CoordinateSystem"
|
||||
));
|
||||
|
||||
const char* Plane4[] = {
|
||||
"PartDesign_Point",
|
||||
"PartDesign_Line",
|
||||
"PartDesign_Plane",
|
||||
"PartDesign_CoordinateSystem",
|
||||
nullptr};
|
||||
Watcher.push_back(new Gui::TaskView::TaskWatcherCommands(
|
||||
"SELECT PartDesign::Plane COUNT 1",
|
||||
Plane4,
|
||||
"Datum objects",
|
||||
"PartDesign_CoordinateSystem"
|
||||
));
|
||||
|
||||
const char* Line[] = {
|
||||
"Part_DatumPoint",
|
||||
"Part_DatumLine",
|
||||
@@ -254,6 +320,18 @@ void Workbench::activated()
|
||||
"PartDesign_Body"
|
||||
));
|
||||
|
||||
const char* Line1[] = {
|
||||
"PartDesign_Point",
|
||||
"PartDesign_Line",
|
||||
"PartDesign_Plane",
|
||||
nullptr};
|
||||
Watcher.push_back(new Gui::TaskView::TaskWatcherCommands(
|
||||
"SELECT PartDesign::Line COUNT 1",
|
||||
Line1,
|
||||
"Datum objects",
|
||||
"PartDesign_CoordinateSystem"
|
||||
));
|
||||
|
||||
const char* Point[] = {
|
||||
"Part_DatumPoint",
|
||||
"Part_DatumLine",
|
||||
@@ -267,6 +345,19 @@ void Workbench::activated()
|
||||
"PartDesign_Body"
|
||||
));
|
||||
|
||||
const char* Point1[] = {
|
||||
"PartDesign_Point",
|
||||
"PartDesign_Line",
|
||||
"PartDesign_Plane",
|
||||
"PartDesign_CoordinateSystem",
|
||||
nullptr};
|
||||
Watcher.push_back(new Gui::TaskView::TaskWatcherCommands(
|
||||
"SELECT PartDesign::Point COUNT 1",
|
||||
Point1,
|
||||
"Datum objects",
|
||||
"PartDesign_CoordinateSystem"
|
||||
));
|
||||
|
||||
const char* NoSel[] = {
|
||||
"PartDesign_Body",
|
||||
nullptr};
|
||||
@@ -296,10 +387,10 @@ void Workbench::activated()
|
||||
"PartDesign_Hole",
|
||||
"PartDesign_Revolution",
|
||||
"PartDesign_Groove",
|
||||
"PartDesign_AdditivePipe",
|
||||
"PartDesign_SubtractivePipe",
|
||||
"PartDesign_AdditiveLoft",
|
||||
"PartDesign_SubtractiveLoft",
|
||||
"PartDesign_AdditivePipe",
|
||||
"PartDesign_SubtractivePipe",
|
||||
"PartDesign_AdditiveHelix",
|
||||
"PartDesign_SubtractiveHelix",
|
||||
nullptr};
|
||||
@@ -310,6 +401,53 @@ void Workbench::activated()
|
||||
"PartDesign_Body"
|
||||
));
|
||||
|
||||
const char* Sketches[] = {
|
||||
"PartDesign_AdditiveLoft",
|
||||
"PartDesign_SubtractiveLoft",
|
||||
"PartDesign_AdditivePipe",
|
||||
"PartDesign_SubtractivePipe",
|
||||
nullptr};
|
||||
Watcher.push_back(new Gui::TaskView::TaskWatcherCommands(
|
||||
"SELECT Sketcher::SketchObject COUNT 2..",
|
||||
Sketches,
|
||||
"Modeling tools",
|
||||
"PartDesign_Body"
|
||||
));
|
||||
|
||||
const char* ShapeBinder[] = {
|
||||
"PartDesign_Pad",
|
||||
"PartDesign_Pocket",
|
||||
"PartDesign_Revolution",
|
||||
"PartDesign_Groove",
|
||||
"PartDesign_AdditiveLoft",
|
||||
"PartDesign_SubtractiveLoft",
|
||||
"PartDesign_AdditivePipe",
|
||||
"PartDesign_SubtractivePipe",
|
||||
nullptr};
|
||||
Watcher.push_back(new Gui::TaskView::TaskWatcherCommands(
|
||||
"SELECT PartDesign::ShapeBinder COUNT 1",
|
||||
ShapeBinder,
|
||||
"Modeling tools",
|
||||
"PartDesign_Body"
|
||||
));
|
||||
|
||||
const char* SubShapeBinder[] = {
|
||||
"PartDesign_Pad",
|
||||
"PartDesign_Pocket",
|
||||
"PartDesign_Revolution",
|
||||
"PartDesign_Groove",
|
||||
"PartDesign_AdditiveLoft",
|
||||
"PartDesign_SubtractiveLoft",
|
||||
"PartDesign_AdditivePipe",
|
||||
"PartDesign_SubtractivePipe",
|
||||
nullptr};
|
||||
Watcher.push_back(new Gui::TaskView::TaskWatcherCommands(
|
||||
"SELECT PartDesign::SubShapeBinder COUNT 1",
|
||||
SubShapeBinder,
|
||||
"Modeling tools",
|
||||
"PartDesign_Body"
|
||||
));
|
||||
|
||||
const char* Transformed[] = {
|
||||
"PartDesign_Mirrored",
|
||||
"PartDesign_LinearPattern",
|
||||
|
||||
Reference in New Issue
Block a user