PD: Improve revolution feature

* Allow a minimum angle of 0.0 as this is needed in 'Two Angles' mode
* Set the default value of Angle2 to 0.0
* Check for valid input in 'Angle' and 'Two Angles' mode
* Replace the confusing enum labels 'Dimension' and 'TwoDimensions'
This commit is contained in:
wmayer
2025-02-17 12:15:31 +01:00
committed by Ladislav Michl
parent 5a3fafcc55
commit 4d80f3ec28
4 changed files with 45 additions and 37 deletions

View File

@@ -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;

View File

@@ -69,12 +69,12 @@ public:
bool suggestReversed();
enum class RevolMethod {
Dimension,
Angle,
ThroughAll,
ToLast = ThroughAll,
ToFirst,
ToFace,
TwoDimensions
TwoAngles
};
protected:

View File

@@ -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);

View File

@@ -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>