Allow extruding from a datum plane to another face or plane, optionally with an offset

This commit is contained in:
jrheinlaender 2013-07-10 10:15:50 +02:00 committed by Stefan Tröger
parent fa020cf867
commit f1b5a6044d
16 changed files with 230 additions and 42 deletions

View File

@ -39,6 +39,9 @@
# include <Precision.hxx> # include <Precision.hxx>
# include <BRepPrimAPI_MakeHalfSpace.hxx> # include <BRepPrimAPI_MakeHalfSpace.hxx>
# include <BRepAlgoAPI_Common.hxx> # include <BRepAlgoAPI_Common.hxx>
# include <BRepAdaptor_Surface.hxx>
# include <gp_Pln.hxx>
# include <GeomAPI_ProjectPointOnSurf.hxx>
#endif #endif
#include <Base/Exception.h> #include <Base/Exception.h>
@ -64,6 +67,7 @@ Pad::Pad()
ADD_PROPERTY_TYPE(Length,(100.0),"Pad",App::Prop_None,"Pad length"); ADD_PROPERTY_TYPE(Length,(100.0),"Pad",App::Prop_None,"Pad length");
ADD_PROPERTY_TYPE(Length2,(100.0),"Pad",App::Prop_None,"P"); ADD_PROPERTY_TYPE(Length2,(100.0),"Pad",App::Prop_None,"P");
ADD_PROPERTY_TYPE(UpToFace,(0),"Pad",App::Prop_None,"Face where pad will end"); ADD_PROPERTY_TYPE(UpToFace,(0),"Pad",App::Prop_None,"Face where pad will end");
ADD_PROPERTY(Offset,(0.0));
} }
short Pad::mustExecute() const short Pad::mustExecute() const
@ -157,10 +161,7 @@ App::DocumentObjectExecReturn *Pad::execute(void)
TopoDS_Shape prism; TopoDS_Shape prism;
std::string method(Type.getValueAsString()); std::string method(Type.getValueAsString());
if (method == "UpToFirst" || method == "UpToLast" || method == "UpToFace") { if (method == "UpToFirst" || method == "UpToLast" || method == "UpToFace") {
// TODO: Write our own PrismMaker which does not depend on a solid base shape // Note: This will return an unlimited planar face if support is a datum plane
if (base.IsNull())
return new App::DocumentObjectExecReturn("Pad: Extruding up to a face is only possible if the sketch is located on a face");
// Note: This will return an unlimited planar face if support is a datum plane
TopoDS_Face supportface = getSupportFace(); TopoDS_Face supportface = getSupportFace();
supportface.Move(invObjLoc); supportface.Move(invObjLoc);
@ -173,27 +174,57 @@ App::DocumentObjectExecReturn *Pad::execute(void)
getUpToFaceFromLinkSub(upToFace, UpToFace); getUpToFaceFromLinkSub(upToFace, UpToFace);
upToFace.Move(invObjLoc); upToFace.Move(invObjLoc);
} }
getUpToFace(upToFace, base, supportface, sketchshape, method, dir); getUpToFace(upToFace, base, supportface, sketchshape, method, dir, Offset.getValue());
// A support object is always required and we need to use BRepFeat_MakePrism // TODO: Write our own PrismMaker which does not depend on a solid base shape
// Problem: For Pocket/UpToFirst (or an equivalent Pocket/UpToFace) the resulting shape is invalid if (base.IsNull()) {
// because the feature does not add any material. This only happens with the "2" option, though // Workaround because BRepFeat_MakePrism requires the base face located on a solid to be able to extrude up to a face
// Note: It might be possible to pass a shell or a compound containing multiple faces // Handle special case of extruding up to a face or plane parallel to the base face
// as the Until parameter of Perform() BRepAdaptor_Surface adapt(upToFace);
// Note: Multiple independent wires are not supported, we should check for that and if (adapt.GetType() != GeomAbs_Plane)
// warn the user return new App::DocumentObjectExecReturn("Pad: Extruding up to a face or plane is only possible if the sketch is located on a face");
// FIXME: If the support shape is not the previous solid in the tree, then there will be unexpected results
// Check supportface for limits, otherwise Perform() throws an exception
TopExp_Explorer Ex(supportface,TopAbs_WIRE);
if (!Ex.More())
supportface = TopoDS_Face();
BRepFeat_MakePrism PrismMaker;
PrismMaker.Init(base, sketchshape, supportface, dir, 2, 1);
PrismMaker.Perform(upToFace);
if (!PrismMaker.IsDone()) double angle = dir.Angle(adapt.Plane().Axis().Direction());
return new App::DocumentObjectExecReturn("Pad: Up to face: Could not extrude the sketch!"); if (angle > Precision::Confusion())
prism = PrismMaker.Shape(); return new App::DocumentObjectExecReturn("Pad: Extruding up to a face is only possible if the sketch plane is parallel to it");
// Project basepoint of sketch onto the UpToFace to determine distance and direction
gp_Pnt basePoint(SketchPos.getPosition().x, SketchPos.getPosition().y, SketchPos.getPosition().z);
GeomAPI_ProjectPointOnSurf prj(basePoint, adapt.Surface().Surface());
if (prj.NbPoints() != 1)
return new App::DocumentObjectExecReturn("Pad: Extruding up to a face failed to find extrusion direction");
// Distance
double length = prj.Distance(1) + Offset.getValue();
if (length < Precision::Confusion())
return new App::DocumentObjectExecReturn("Pad: Extruding up to a face failed because of zero height");
// Direction (the distance is always positive)
gp_Pnt prjP = prj.NearestPoint();
dir = gp_Dir(gp_Vec(basePoint, prjP));
dir.Transform(invObjLoc.Transformation());
generatePrism(prism, sketchshape, "Length", dir, length, 0.0, false, false);
} else {
// A support object is always required and we need to use BRepFeat_MakePrism
// Problem: For Pocket/UpToFirst (or an equivalent Pocket/UpToFace) the resulting shape is invalid
// because the feature does not add any material. This only happens with the "2" option, though
// Note: It might be possible to pass a shell or a compound containing multiple faces
// as the Until parameter of Perform()
// Note: Multiple independent wires are not supported, we should check for that and
// warn the user
// FIXME: If the support shape is not the previous solid in the tree, then there will be unexpected results
// Check supportface for limits, otherwise Perform() throws an exception
TopExp_Explorer Ex(supportface,TopAbs_WIRE);
if (!Ex.More())
supportface = TopoDS_Face();
BRepFeat_MakePrism PrismMaker;
PrismMaker.Init(base, sketchshape, supportface, dir, 2, 1);
PrismMaker.Perform(upToFace);
if (!PrismMaker.IsDone())
return new App::DocumentObjectExecReturn("Pad: Up to face: Could not extrude the sketch!");
prism = PrismMaker.Shape();
}
} else { } else {
generatePrism(prism, sketchshape, method, dir, L, L2, generatePrism(prism, sketchshape, method, dir, L, L2,
Midplane.getValue(), Reversed.getValue()); Midplane.getValue(), Reversed.getValue());

View File

@ -42,6 +42,7 @@ public:
App::PropertyEnumeration Type; App::PropertyEnumeration Type;
App::PropertyLength Length; App::PropertyLength Length;
App::PropertyLength Length2; App::PropertyLength Length2;
App::PropertyFloat Offset;
/** @name methods override feature */ /** @name methods override feature */
//@{ //@{

View File

@ -62,6 +62,7 @@ Pocket::Pocket()
Type.setEnums(TypeEnums); Type.setEnums(TypeEnums);
ADD_PROPERTY_TYPE(Length,(100.0),"Pocket",App::Prop_None,"Pocket length"); ADD_PROPERTY_TYPE(Length,(100.0),"Pocket",App::Prop_None,"Pocket length");
ADD_PROPERTY_TYPE(UpToFace,(0),"Pocket",App::Prop_None,"Face where pocket will end"); ADD_PROPERTY_TYPE(UpToFace,(0),"Pocket",App::Prop_None,"Face where pocket will end");
ADD_PROPERTY(Offset,(0.0));
} }
short Pocket::mustExecute() const short Pocket::mustExecute() const
@ -150,7 +151,7 @@ App::DocumentObjectExecReturn *Pocket::execute(void)
getUpToFaceFromLinkSub(upToFace, UpToFace); getUpToFaceFromLinkSub(upToFace, UpToFace);
upToFace.Move(invObjLoc); upToFace.Move(invObjLoc);
} }
getUpToFace(upToFace, base, supportface, sketchshape, method, dir); getUpToFace(upToFace, base, supportface, sketchshape, method, dir, Offset.getValue());
// Special treatment because often the created stand-alone prism is invalid (empty) because // Special treatment because often the created stand-alone prism is invalid (empty) because
// BRepFeat_MakePrism(..., 2, 1) is buggy // BRepFeat_MakePrism(..., 2, 1) is buggy

View File

@ -39,6 +39,7 @@ public:
App::PropertyEnumeration Type; App::PropertyEnumeration Type;
App::PropertyLength Length; App::PropertyLength Length;
App::PropertyFloat Offset;
/** @name methods override feature */ /** @name methods override feature */
//@{ //@{

View File

@ -494,7 +494,8 @@ void SketchBased::getUpToFace(TopoDS_Face& upToFace,
const TopoDS_Face& supportface, const TopoDS_Face& supportface,
const TopoDS_Shape& sketchshape, const TopoDS_Shape& sketchshape,
const std::string& method, const std::string& method,
const gp_Dir& dir) const gp_Dir& dir,
const double offset)
{ {
if ((method == "UpToLast") || (method == "UpToFirst")) { if ((method == "UpToLast") || (method == "UpToFirst")) {
// Check for valid support object // Check for valid support object
@ -564,6 +565,18 @@ void SketchBased::getUpToFace(TopoDS_Face& upToFace,
if (distSS.Value() < Precision::Confusion()) if (distSS.Value() < Precision::Confusion())
throw Base::Exception("SketchBased: Up to face: Must not intersect sketch!"); throw Base::Exception("SketchBased: Up to face: Must not intersect sketch!");
// Move the face in the extrusion direction
// TODO: For non-planar faces, we could consider offsetting the surface
if (fabs(offset) > Precision::Confusion()) {
if (adapt2.GetType() == GeomAbs_Plane) {
gp_Trsf mov;
mov.SetTranslation(offset * gp_Vec(dir));
TopLoc_Location loc(mov);
upToFace.Move(loc);
} else {
throw Base::Exception("SketchBased: Up to Face: Offset not supported yet for non-planar faces");
}
}
} }
void SketchBased::generatePrism(TopoDS_Shape& prism, void SketchBased::generatePrism(TopoDS_Shape& prism,

View File

@ -101,7 +101,8 @@ protected:
const TopoDS_Face& supportface, const TopoDS_Face& supportface,
const TopoDS_Shape& sketchshape, const TopoDS_Shape& sketchshape,
const std::string& method, const std::string& method,
const gp_Dir& dir); const gp_Dir& dir,
const double offset);
/** /**
* Generate a linear prism * Generate a linear prism
* It will be a stand-alone solid created with BRepPrimAPI_MakePrism * It will be a stand-alone solid created with BRepPrimAPI_MakePrism

View File

@ -68,13 +68,13 @@ const QString makeRefString(const App::DocumentObject* obj, const std::string& s
if ((sub.size() > 4) && (sub.substr(0,4) == "Face")) { if ((sub.size() > 4) && (sub.substr(0,4) == "Face")) {
int subId = std::atoi(&sub[4]); int subId = std::atoi(&sub[4]);
return QString::fromAscii(obj->getNameInDocument()) + QObject::tr(":Face") + QString::number(subId); return QString::fromAscii(obj->getNameInDocument()) + QString::fromAscii(":") + QObject::tr("Face") + QString::number(subId);
} else if ((sub.size() > 4) && (sub.substr(0,4) == "Edge")) { } else if ((sub.size() > 4) && (sub.substr(0,4) == "Edge")) {
int subId = std::atoi(&sub[4]); int subId = std::atoi(&sub[4]);
return QString::fromAscii(obj->getNameInDocument()) + QObject::tr(":Edge") + QString::number(subId); return QString::fromAscii(obj->getNameInDocument()) + QString::fromAscii(":") + QObject::tr("Edge") + QString::number(subId);
} if ((sub.size() > 6) && (sub.substr(0,6) == "Vertex")) { } if ((sub.size() > 6) && (sub.substr(0,6) == "Vertex")) {
int subId = std::atoi(&sub[6]); int subId = std::atoi(&sub[6]);
return QString::fromAscii(obj->getNameInDocument()) + QObject::tr(":Vertex") + QString::number(subId); return QString::fromAscii(obj->getNameInDocument()) + QString::fromAscii(":") + QObject::tr("Vertex") + QString::number(subId);
} }
return QObject::tr("No reference selected"); return QObject::tr("No reference selected");

View File

@ -331,7 +331,7 @@ void TaskGrooveParameters::apply()
ui->grooveAngle->apply(); ui->grooveAngle->apply();
std::vector<std::string> sub; std::vector<std::string> sub;
App::DocumentObject* obj; App::DocumentObject* obj;
parameter->getReferenceAxis(obj, sub); getReferenceAxis(obj, sub);
std::string axis = getPythonStr(obj, sub); std::string axis = getPythonStr(obj, sub);
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.ReferenceAxis = %s",name.c_str(),axis.c_str()); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.ReferenceAxis = %s",name.c_str(),axis.c_str());
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Midplane = %i",name.c_str(), getMidplane() ? 1 : 0); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Midplane = %i",name.c_str(), getMidplane() ? 1 : 0);

View File

@ -72,6 +72,8 @@ TaskPadParameters::TaskPadParameters(ViewProviderPad *PadView,bool newObj, QWidg
this, SLOT(onReversed(bool))); this, SLOT(onReversed(bool)));
connect(ui->lengthEdit2, SIGNAL(valueChanged(double)), connect(ui->lengthEdit2, SIGNAL(valueChanged(double)),
this, SLOT(onLength2Changed(double))); this, SLOT(onLength2Changed(double)));
connect(ui->spinOffset, SIGNAL(valueChanged(double)),
this, SLOT(onOffsetChanged(double)));
connect(ui->changeMode, SIGNAL(currentIndexChanged(int)), connect(ui->changeMode, SIGNAL(currentIndexChanged(int)),
this, SLOT(onModeChanged(int))); this, SLOT(onModeChanged(int)));
connect(ui->buttonFace, SIGNAL(clicked()), connect(ui->buttonFace, SIGNAL(clicked()),
@ -86,6 +88,7 @@ TaskPadParameters::TaskPadParameters(ViewProviderPad *PadView,bool newObj, QWidg
// Temporarily prevent unnecessary feature recomputes // Temporarily prevent unnecessary feature recomputes
ui->lengthEdit->blockSignals(true); ui->lengthEdit->blockSignals(true);
ui->lengthEdit2->blockSignals(true); ui->lengthEdit2->blockSignals(true);
ui->spinOffset->blockSignals(true);
ui->checkBoxMidplane->blockSignals(true); ui->checkBoxMidplane->blockSignals(true);
ui->checkBoxReversed->blockSignals(true); ui->checkBoxReversed->blockSignals(true);
ui->buttonFace->blockSignals(true); ui->buttonFace->blockSignals(true);
@ -102,6 +105,7 @@ TaskPadParameters::TaskPadParameters(ViewProviderPad *PadView,bool newObj, QWidg
bool midplane = pcPad->Midplane.getValue(); bool midplane = pcPad->Midplane.getValue();
bool reversed = pcPad->Reversed.getValue(); bool reversed = pcPad->Reversed.getValue();
Base::Quantity l2 = pcPad->Length2.getQuantityValue(); Base::Quantity l2 = pcPad->Length2.getQuantityValue();
double off = pcPad->Offset.getValue();
int index = pcPad->Type.getValue(); // must extract value here, clear() kills it! int index = pcPad->Type.getValue(); // must extract value here, clear() kills it!
App::DocumentObject* obj = pcPad->UpToFace.getValue(); App::DocumentObject* obj = pcPad->UpToFace.getValue();
std::vector<std::string> subStrings = pcPad->UpToFace.getSubValues(); std::vector<std::string> subStrings = pcPad->UpToFace.getSubValues();
@ -120,11 +124,13 @@ TaskPadParameters::TaskPadParameters(ViewProviderPad *PadView,bool newObj, QWidg
ui->lengthEdit2->setMinimum(0); ui->lengthEdit2->setMinimum(0);
ui->lengthEdit2->setMaximum(INT_MAX); ui->lengthEdit2->setMaximum(INT_MAX);
ui->lengthEdit2->setValue(l2); ui->lengthEdit2->setValue(l2);
ui->spinOffset->setMaximum(INT_MAX);
ui->spinOffset->setMinimum(-INT_MAX);
ui->spinOffset->setValue(off);
// Bind input fields to properties // Bind input fields to properties
ui->lengthEdit->bind(pcPad->Length); ui->lengthEdit->bind(pcPad->Length);
ui->lengthEdit2->bind(pcPad->Length2); ui->lengthEdit2->bind(pcPad->Length2);
ui->checkBoxMidplane->setChecked(midplane); ui->checkBoxMidplane->setChecked(midplane);
// According to bug #0000521 the reversed option // According to bug #0000521 the reversed option
// shouldn't be de-activated if the pad has a support face // shouldn't be de-activated if the pad has a support face
@ -132,7 +138,7 @@ TaskPadParameters::TaskPadParameters(ViewProviderPad *PadView,bool newObj, QWidg
if ((obj != NULL) && PartDesign::Feature::isDatum(obj)) if ((obj != NULL) && PartDesign::Feature::isDatum(obj))
ui->lineFaceName->setText(QString::fromAscii(obj->getNameInDocument())); ui->lineFaceName->setText(QString::fromAscii(obj->getNameInDocument()));
else if (faceId >= 0) else if (faceId >= 0)
ui->lineFaceName->setText(QString::fromAscii(obj->getNameInDocument()) + tr("Face") + ui->lineFaceName->setText(QString::fromAscii(obj->getNameInDocument()) + QString::fromAscii(":") + tr("Face") +
QString::number(faceId)); QString::number(faceId));
else else
ui->lineFaceName->setText(tr("No face selected")); ui->lineFaceName->setText(tr("No face selected"));
@ -148,6 +154,7 @@ TaskPadParameters::TaskPadParameters(ViewProviderPad *PadView,bool newObj, QWidg
// activate and de-activate dialog elements as appropriate // activate and de-activate dialog elements as appropriate
ui->lengthEdit->blockSignals(false); ui->lengthEdit->blockSignals(false);
ui->lengthEdit2->blockSignals(false); ui->lengthEdit2->blockSignals(false);
ui->spinOffset->blockSignals(false);
ui->checkBoxMidplane->blockSignals(false); ui->checkBoxMidplane->blockSignals(false);
ui->checkBoxReversed->blockSignals(false); ui->checkBoxReversed->blockSignals(false);
ui->buttonFace->blockSignals(false); ui->buttonFace->blockSignals(false);
@ -167,8 +174,13 @@ TaskPadParameters::TaskPadParameters(ViewProviderPad *PadView,bool newObj, QWidg
void TaskPadParameters::updateUI(int index) void TaskPadParameters::updateUI(int index)
{ {
if (index == 0) { // dimension if (index == 0) { // dimension
ui->lengthEdit->setVisible(true);
ui->lengthEdit->setEnabled(true); ui->lengthEdit->setEnabled(true);
ui->lengthEdit->selectNumber(); ui->lengthEdit->selectNumber();
ui->labelLength->setVisible(true);
ui->spinOffset->setVisible(false);
ui->spinOffset->setEnabled(false);
ui->labelOffset->setVisible(false);
// Make sure that the spin box has the focus to get key events // Make sure that the spin box has the focus to get key events
// Calling setFocus() directly doesn't work because the spin box is not // Calling setFocus() directly doesn't work because the spin box is not
// yet visible. // yet visible.
@ -176,22 +188,38 @@ void TaskPadParameters::updateUI(int index)
ui->checkBoxMidplane->setEnabled(true); ui->checkBoxMidplane->setEnabled(true);
// Reverse only makes sense if Midplane is not true // Reverse only makes sense if Midplane is not true
ui->checkBoxReversed->setEnabled(!ui->checkBoxMidplane->isChecked()); ui->checkBoxReversed->setEnabled(!ui->checkBoxMidplane->isChecked());
ui->labelLength2->setVisible(false);
ui->lengthEdit2->setVisible(false);
ui->lengthEdit2->setEnabled(false); ui->lengthEdit2->setEnabled(false);
ui->buttonFace->setEnabled(false); ui->buttonFace->setEnabled(false);
ui->lineFaceName->setEnabled(false); ui->lineFaceName->setEnabled(false);
onButtonFace(false); onButtonFace(false);
} else if (index == 1 || index == 2) { // up to first/last } else if (index == 1 || index == 2) { // up to first/last
ui->lengthEdit->setVisible(false);
ui->lengthEdit->setEnabled(false); ui->lengthEdit->setEnabled(false);
ui->labelLength->setVisible(false);
ui->spinOffset->setVisible(true);
ui->spinOffset->setEnabled(true);
ui->labelOffset->setVisible(true);
ui->checkBoxMidplane->setEnabled(false); ui->checkBoxMidplane->setEnabled(false);
ui->checkBoxReversed->setEnabled(true); ui->checkBoxReversed->setEnabled(true);
ui->labelLength2->setVisible(false);
ui->lengthEdit2->setVisible(false);
ui->lengthEdit2->setEnabled(false); ui->lengthEdit2->setEnabled(false);
ui->buttonFace->setEnabled(false); ui->buttonFace->setEnabled(false);
ui->lineFaceName->setEnabled(false); ui->lineFaceName->setEnabled(false);
onButtonFace(false); onButtonFace(false);
} else if (index == 3) { // up to face } else if (index == 3) { // up to face
ui->lengthEdit->setVisible(false);
ui->lengthEdit->setEnabled(false); ui->lengthEdit->setEnabled(false);
ui->labelLength->setVisible(false);
ui->spinOffset->setVisible(true);
ui->spinOffset->setEnabled(true);
ui->labelOffset->setVisible(true);
ui->checkBoxMidplane->setEnabled(false); ui->checkBoxMidplane->setEnabled(false);
ui->checkBoxReversed->setEnabled(false); ui->checkBoxReversed->setEnabled(false);
ui->labelLength2->setVisible(false);
ui->lengthEdit2->setVisible(false);
ui->lengthEdit2->setEnabled(false); ui->lengthEdit2->setEnabled(false);
ui->buttonFace->setEnabled(true); ui->buttonFace->setEnabled(true);
ui->lineFaceName->setEnabled(true); ui->lineFaceName->setEnabled(true);
@ -201,10 +229,17 @@ void TaskPadParameters::updateUI(int index)
onButtonFace(true); onButtonFace(true);
} else { // two dimensions } else { // two dimensions
ui->lengthEdit->setEnabled(true); ui->lengthEdit->setEnabled(true);
ui->lengthEdit->setVisible(true);
ui->lengthEdit->selectNumber(); ui->lengthEdit->selectNumber();
QMetaObject::invokeMethod(ui->lengthEdit, "setFocus", Qt::QueuedConnection); QMetaObject::invokeMethod(ui->lengthEdit, "setFocus", Qt::QueuedConnection);
ui->labelLength->setVisible(true);
ui->spinOffset->setVisible(false);
ui->spinOffset->setEnabled(false);
ui->labelOffset->setVisible(false);
ui->checkBoxMidplane->setEnabled(false); ui->checkBoxMidplane->setEnabled(false);
ui->checkBoxReversed->setEnabled(false); ui->checkBoxReversed->setEnabled(false);
ui->labelLength2->setVisible(true);
ui->lengthEdit2->setVisible(true);
ui->lengthEdit2->setEnabled(true); ui->lengthEdit2->setEnabled(true);
ui->buttonFace->setEnabled(false); ui->buttonFace->setEnabled(false);
ui->lineFaceName->setEnabled(false); ui->lineFaceName->setEnabled(false);
@ -268,6 +303,13 @@ void TaskPadParameters::onLength2Changed(double len)
recomputeFeature(); recomputeFeature();
} }
void TaskPadParameters::onOffsetChanged(double len)
{
PartDesign::Pad* pcPad = static_cast<PartDesign::Pad*>(vp->getObject());
pcPad->Offset.setValue(len);
recomputeFeature();
}
void TaskPadParameters::onModeChanged(int index) void TaskPadParameters::onModeChanged(int index)
{ {
PartDesign::Pad* pcPad = static_cast<PartDesign::Pad*>(vp->getObject()); PartDesign::Pad* pcPad = static_cast<PartDesign::Pad*>(vp->getObject());
@ -322,6 +364,11 @@ double TaskPadParameters::getLength2(void) const
return ui->lengthEdit2->value().getValue(); return ui->lengthEdit2->value().getValue();
} }
double TaskPadParameters::getOffset(void) const
{
return ui->spinOffset->value();
}
int TaskPadParameters::getMode(void) const int TaskPadParameters::getMode(void) const
{ {
return ui->changeMode->currentIndex(); return ui->changeMode->currentIndex();
@ -346,6 +393,7 @@ void TaskPadParameters::changeEvent(QEvent *e)
if (e->type() == QEvent::LanguageChange) { if (e->type() == QEvent::LanguageChange) {
ui->lengthEdit->blockSignals(true); ui->lengthEdit->blockSignals(true);
ui->lengthEdit2->blockSignals(true); ui->lengthEdit2->blockSignals(true);
ui->spinOffset->blockSignals(true);
ui->lineFaceName->blockSignals(true); ui->lineFaceName->blockSignals(true);
ui->changeMode->blockSignals(true); ui->changeMode->blockSignals(true);
int index = ui->changeMode->currentIndex(); int index = ui->changeMode->currentIndex();
@ -369,10 +417,11 @@ void TaskPadParameters::changeEvent(QEvent *e)
ui->lineFaceName->setPlaceholderText(tr("No face selected")); ui->lineFaceName->setPlaceholderText(tr("No face selected"));
#endif #endif
ui->lineFaceName->setText(ok ? ui->lineFaceName->setText(ok ?
parts[0] + tr(":Face") + QString::number(faceId) : parts[0] + QString::fromAscii(":") + tr("Face") + QString::number(faceId) :
QString()); QString());
ui->lengthEdit->blockSignals(false); ui->lengthEdit->blockSignals(false);
ui->lengthEdit2->blockSignals(false); ui->lengthEdit2->blockSignals(false);
ui->spinOffset->blockSignals(false);
ui->lineFaceName->blockSignals(false); ui->lineFaceName->blockSignals(false);
ui->changeMode->blockSignals(false); ui->changeMode->blockSignals(false);
} }
@ -404,6 +453,7 @@ void TaskPadParameters::apply()
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.UpToFace = %s", name.c_str(), facename.c_str()); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.UpToFace = %s", name.c_str(), facename.c_str());
} else } else
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.UpToFace = None", cname); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.UpToFace = None", cname);
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Offset = %f", name.c_str(), getOffset());
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()");
if (!vp->getObject()->isValid()) if (!vp->getObject()->isValid())
throw Base::Exception(vp->getObject()->getStatusString()); throw Base::Exception(vp->getObject()->getStatusString());

View File

@ -53,6 +53,7 @@ public:
TaskPadParameters(ViewProviderPad *PadView,bool newObj=false,QWidget *parent = 0); TaskPadParameters(ViewProviderPad *PadView,bool newObj=false,QWidget *parent = 0);
~TaskPadParameters(); ~TaskPadParameters();
double getOffset(void) const;
void saveHistory(void); void saveHistory(void);
void apply(); void apply();
@ -61,6 +62,7 @@ private Q_SLOTS:
void onMidplane(bool); void onMidplane(bool);
void onReversed(bool); void onReversed(bool);
void onLength2Changed(double); void onLength2Changed(double);
void onOffsetChanged(double);
void onModeChanged(int); void onModeChanged(int);
void onButtonFace(const bool pressed = true); void onButtonFace(const bool pressed = true);
void onFaceName(const QString& text); void onFaceName(const QString& text);

View File

@ -37,7 +37,7 @@
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_2"> <layout class="QHBoxLayout" name="horizontalLayout_2">
<item> <item>
<widget class="QLabel" name="label"> <widget class="QLabel" name="labelLength">
<property name="text"> <property name="text">
<string>Length</string> <string>Length</string>
</property> </property>
@ -61,6 +61,33 @@
</item> </item>
</layout> </layout>
</item> </item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QLabel" name="labelOffset">
<property name="text">
<string>Offset</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="spinOffset">
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>999999999.000000000000000</double>
</property>
<property name="singleStep">
<double>5.000000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item> <item>
<widget class="QCheckBox" name="checkBoxMidplane"> <widget class="QCheckBox" name="checkBoxMidplane">
<property name="enabled"> <property name="enabled">
@ -81,7 +108,7 @@
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_4"> <layout class="QHBoxLayout" name="horizontalLayout_4">
<item> <item>
<widget class="QLabel" name="label_2"> <widget class="QLabel" name="labelLength2">
<property name="text"> <property name="text">
<string>2nd length</string> <string>2nd length</string>
</property> </property>

View File

@ -67,6 +67,8 @@ TaskPocketParameters::TaskPocketParameters(ViewProviderPocket *PocketView,QWidge
connect(ui->pocketLength, SIGNAL(valueChanged(double)), connect(ui->pocketLength, SIGNAL(valueChanged(double)),
this, SLOT(onLengthChanged(double))); this, SLOT(onLengthChanged(double)));
connect(ui->spinOffset, SIGNAL(valueChanged(double)),
this, SLOT(onOffsetChanged(double)));
connect(ui->checkBoxMidplane, SIGNAL(toggled(bool)), connect(ui->checkBoxMidplane, SIGNAL(toggled(bool)),
this, SLOT(onMidplaneChanged(bool))); this, SLOT(onMidplaneChanged(bool)));
connect(ui->checkBoxReversed, SIGNAL(toggled(bool)), connect(ui->checkBoxReversed, SIGNAL(toggled(bool)),
@ -84,6 +86,7 @@ TaskPocketParameters::TaskPocketParameters(ViewProviderPocket *PocketView,QWidge
// Temporarily prevent unnecessary feature recomputes // Temporarily prevent unnecessary feature recomputes
ui->pocketLength->blockSignals(true); ui->pocketLength->blockSignals(true);
ui->spinOffset->blockSignals(true);
ui->checkBoxMidplane->blockSignals(true); ui->checkBoxMidplane->blockSignals(true);
ui->checkBoxReversed->blockSignals(true); ui->checkBoxReversed->blockSignals(true);
ui->buttonFace->blockSignals(true); ui->buttonFace->blockSignals(true);
@ -93,6 +96,7 @@ TaskPocketParameters::TaskPocketParameters(ViewProviderPocket *PocketView,QWidge
// Get the feature data // Get the feature data
PartDesign::Pocket* pcPocket = static_cast<PartDesign::Pocket*>(vp->getObject()); PartDesign::Pocket* pcPocket = static_cast<PartDesign::Pocket*>(vp->getObject());
double l = pcPocket->Length.getValue(); double l = pcPocket->Length.getValue();
double off = pcPocket->Offset.getValue();
bool midplane = pcPocket->Midplane.getValue(); bool midplane = pcPocket->Midplane.getValue();
bool reversed = pcPocket->Reversed.getValue(); bool reversed = pcPocket->Reversed.getValue();
int index = pcPocket->Type.getValue(); // must extract value here, clear() kills it! int index = pcPocket->Type.getValue(); // must extract value here, clear() kills it!
@ -110,12 +114,15 @@ TaskPocketParameters::TaskPocketParameters(ViewProviderPocket *PocketView,QWidge
ui->pocketLength->setMinimum(0); ui->pocketLength->setMinimum(0);
ui->pocketLength->setMaximum(INT_MAX); ui->pocketLength->setMaximum(INT_MAX);
ui->pocketLength->setValue(l); ui->pocketLength->setValue(l);
ui->spinOffset->setMinimum(-INT_MAX);
ui->spinOffset->setMaximum(INT_MAX);
ui->spinOffset->setValue(off);
ui->checkBoxMidplane->setChecked(midplane); ui->checkBoxMidplane->setChecked(midplane);
ui->checkBoxReversed->setChecked(reversed); ui->checkBoxReversed->setChecked(reversed);
if ((obj != NULL) && PartDesign::Feature::isDatum(obj)) if ((obj != NULL) && PartDesign::Feature::isDatum(obj))
ui->lineFaceName->setText(QString::fromAscii(obj->getNameInDocument())); ui->lineFaceName->setText(QString::fromAscii(obj->getNameInDocument()));
else if (faceId >= 0) else if (faceId >= 0)
ui->lineFaceName->setText(QString::fromAscii(obj->getNameInDocument()) + tr("Face") + ui->lineFaceName->setText(QString::fromAscii(obj->getNameInDocument()) + QString::fromAscii(":") + tr("Face") +
QString::number(faceId)); QString::number(faceId));
else else
ui->lineFaceName->setText(tr("No face selected")); ui->lineFaceName->setText(tr("No face selected"));
@ -131,6 +138,7 @@ TaskPocketParameters::TaskPocketParameters(ViewProviderPocket *PocketView,QWidge
ui->pocketLength->bind(pcPocket->Length); ui->pocketLength->bind(pcPocket->Length);
ui->pocketLength->blockSignals(false); ui->pocketLength->blockSignals(false);
ui->spinOffset->blockSignals(false);
ui->checkBoxMidplane->blockSignals(false); ui->checkBoxMidplane->blockSignals(false);
ui->checkBoxReversed->blockSignals(false); ui->checkBoxReversed->blockSignals(false);
ui->buttonFace->blockSignals(false); ui->buttonFace->blockSignals(false);
@ -157,9 +165,13 @@ TaskPocketParameters::TaskPocketParameters(ViewProviderPocket *PocketView,QWidge
void TaskPocketParameters::updateUI(int index) void TaskPocketParameters::updateUI(int index)
{ {
if (index == 0) { // Only this option requires a numeric value // Dimension if (index == 0) { // Only this option requires a numeric value // Dimension
ui->pocketLength->setVisible(true);
ui->pocketLength->setEnabled(true); ui->pocketLength->setEnabled(true);
ui->pocketLength->selectAll(); ui->pocketLength->selectAll();
QMetaObject::invokeMethod(ui->pocketLength, "setFocus", Qt::QueuedConnection); QMetaObject::invokeMethod(ui->pocketLength, "setFocus", Qt::QueuedConnection);
ui->spinOffset->setVisible(false);
ui->spinOffset->setEnabled(false);
ui->spinOffset->setEnabled(false);
ui->checkBoxMidplane->setEnabled(true); ui->checkBoxMidplane->setEnabled(true);
// Reverse only makes sense if Midplane is not true // Reverse only makes sense if Midplane is not true
ui->checkBoxReversed->setEnabled(!ui->checkBoxMidplane->isChecked()); // Will flip direction of dimension ui->checkBoxReversed->setEnabled(!ui->checkBoxMidplane->isChecked()); // Will flip direction of dimension
@ -169,21 +181,35 @@ void TaskPocketParameters::updateUI(int index)
} else if (index == 1) { // Through all } else if (index == 1) { // Through all
ui->checkBoxMidplane->setEnabled(true); ui->checkBoxMidplane->setEnabled(true);
ui->checkBoxReversed->setEnabled(!ui->checkBoxMidplane->isChecked()); // Will flip direction of through all ui->checkBoxReversed->setEnabled(!ui->checkBoxMidplane->isChecked()); // Will flip direction of through all
ui->pocketLength->setVisible(false);
ui->pocketLength->setEnabled(false); ui->pocketLength->setEnabled(false);
ui->spinOffset->setVisible(false);
ui->spinOffset->setVisible(false);
ui->spinOffset->setEnabled(false);
ui->buttonFace->setEnabled(false); ui->buttonFace->setEnabled(false);
ui->lineFaceName->setEnabled(false); ui->lineFaceName->setEnabled(false);
onButtonFace(false); onButtonFace(false);
} else if (index == 2) { // Neither value nor face required // To First } else if (index == 2) { // Neither value nor face required // To First
ui->pocketLength->setEnabled(false); ui->pocketLength->setEnabled(false);
ui->pocketLength->setVisible(false);
ui->checkBoxMidplane->setEnabled(false); // Can't have a midplane to a single face ui->checkBoxMidplane->setEnabled(false); // Can't have a midplane to a single face
ui->checkBoxReversed->setEnabled(false); // Will change the direction it seeks for its first face? ui->checkBoxReversed->setEnabled(false); // Will change the direction it seeks for its first face?
// Doesnt work so is currently disabled. Fix probably lies // Doesnt work so is currently disabled. Fix probably lies
// somwhere in IF block on line 125 of FeaturePocket.cpp // somwhere in IF block on line 125 of FeaturePocket.cpp
ui->labelLength->setVisible(false);
ui->spinOffset->setVisible(true);
ui->spinOffset->setEnabled(true);
ui->labelOffset->setVisible(true);
ui->buttonFace->setEnabled(false); ui->buttonFace->setEnabled(false);
ui->lineFaceName->setEnabled(false); ui->lineFaceName->setEnabled(false);
onButtonFace(false); onButtonFace(false);
} else if (index == 3) { // Only this option requires to select a face // Up to face } else if (index == 3) { // Only this option requires to select a face // Up to face
ui->pocketLength->setEnabled(false); ui->pocketLength->setEnabled(false);
ui->pocketLength->setVisible(false);
ui->labelLength->setVisible(false);
ui->spinOffset->setVisible(true);
ui->spinOffset->setEnabled(true);
ui->labelOffset->setVisible(true);
ui->checkBoxMidplane->setEnabled(false); ui->checkBoxMidplane->setEnabled(false);
ui->checkBoxReversed->setEnabled(false); // No need for reverse since user-chosen face will dtermine direction ui->checkBoxReversed->setEnabled(false); // No need for reverse since user-chosen face will dtermine direction
ui->buttonFace->setEnabled(true); ui->buttonFace->setEnabled(true);
@ -228,6 +254,13 @@ void TaskPocketParameters::onLengthChanged(double len)
recomputeFeature(); recomputeFeature();
} }
void TaskPocketParameters::onOffsetChanged(double len)
{
PartDesign::Pocket* pcPocket = static_cast<PartDesign::Pocket*>(vp->getObject());
pcPocket->Offset.setValue(len);
recomputeFeature();
}
void TaskPocketParameters::onMidplaneChanged(bool on) void TaskPocketParameters::onMidplaneChanged(bool on)
{ {
PartDesign::Pocket* pcPocket = static_cast<PartDesign::Pocket*>(vp->getObject()); PartDesign::Pocket* pcPocket = static_cast<PartDesign::Pocket*>(vp->getObject());
@ -297,6 +330,11 @@ double TaskPocketParameters::getLength(void) const
return ui->pocketLength->value().getValue(); return ui->pocketLength->value().getValue();
} }
double TaskPocketParameters::getOffset(void) const
{
return ui->spinOffset->value();
}
bool TaskPocketParameters::getReversed(void) const bool TaskPocketParameters::getReversed(void) const
{ {
return ui->checkBoxReversed->isChecked(); return ui->checkBoxReversed->isChecked();
@ -325,6 +363,7 @@ void TaskPocketParameters::changeEvent(QEvent *e)
TaskBox::changeEvent(e); TaskBox::changeEvent(e);
if (e->type() == QEvent::LanguageChange) { if (e->type() == QEvent::LanguageChange) {
ui->pocketLength->blockSignals(true); ui->pocketLength->blockSignals(true);
ui->spinOffset->blockSignals(true);
ui->lineFaceName->blockSignals(true); ui->lineFaceName->blockSignals(true);
ui->changeMode->blockSignals(true); ui->changeMode->blockSignals(true);
int index = ui->changeMode->currentIndex(); int index = ui->changeMode->currentIndex();
@ -344,9 +383,10 @@ void TaskPocketParameters::changeEvent(QEvent *e)
faceId = upToFace.remove(0,4).toInt(&ok); faceId = upToFace.remove(0,4).toInt(&ok);
} }
ui->lineFaceName->setText(ok ? ui->lineFaceName->setText(ok ?
parts[0] + tr(":Face") + QString::number(faceId) : parts[0] + QString::fromAscii(":") + tr("Face") + QString::number(faceId) :
tr("No face selected")); tr("No face selected"));
ui->pocketLength->blockSignals(false); ui->pocketLength->blockSignals(false);
ui->spinOffset->blockSignals(false);
ui->lineFaceName->blockSignals(false); ui->lineFaceName->blockSignals(false);
ui->changeMode->blockSignals(false); ui->changeMode->blockSignals(false);
} }
@ -366,6 +406,7 @@ void TaskPocketParameters::apply()
} else } else
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.UpToFace = None", name.c_str()); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.UpToFace = None", name.c_str());
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %i", name.c_str(), getReversed()?1:0); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %i", name.c_str(), getReversed()?1:0);
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Offset = %f", name.c_str(), getOffset());
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()");
if (!vp->getObject()->isValid()) if (!vp->getObject()->isValid())
throw Base::Exception(vp->getObject()->getStatusString()); throw Base::Exception(vp->getObject()->getStatusString());

View File

@ -53,12 +53,14 @@ public:
TaskPocketParameters(ViewProviderPocket *PocketView,QWidget *parent = 0); TaskPocketParameters(ViewProviderPocket *PocketView,QWidget *parent = 0);
~TaskPocketParameters(); ~TaskPocketParameters();
double getOffset(void) const;
bool getReversed(void) const; bool getReversed(void) const;
QByteArray getFaceName(void) const; QByteArray getFaceName(void) const;
void apply(); void apply();
private Q_SLOTS: private Q_SLOTS:
void onLengthChanged(double); void onLengthChanged(double);
void onOffsetChanged(double);
void onMidplaneChanged(bool); void onMidplaneChanged(bool);
void onReversedChanged(bool); void onReversedChanged(bool);
void onModeChanged(int); void onModeChanged(int);

View File

@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>241</width> <width>241</width>
<height>188</height> <height>233</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
@ -49,7 +49,7 @@
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_2"> <layout class="QHBoxLayout" name="horizontalLayout_2">
<item> <item>
<widget class="QLabel" name="label"> <widget class="QLabel" name="labelLength">
<property name="text"> <property name="text">
<string>Length</string> <string>Length</string>
</property> </property>
@ -67,6 +67,24 @@
</item> </item>
</layout> </layout>
</item> </item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="labelOffset">
<property name="text">
<string>Offset</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="spinOffset">
<property name="maximum">
<double>999999999.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item> <item>
<widget class="QCheckBox" name="checkBoxMidplane"> <widget class="QCheckBox" name="checkBoxMidplane">
<property name="enabled"> <property name="enabled">

View File

@ -332,7 +332,7 @@ void TaskRevolutionParameters::apply()
ui->revolveAngle->apply(); ui->revolveAngle->apply();
std::vector<std::string> sub; std::vector<std::string> sub;
App::DocumentObject* obj; App::DocumentObject* obj;
parameter->getReferenceAxis(obj, sub); getReferenceAxis(obj, sub);
std::string axis = getPythonStr(obj, sub); std::string axis = getPythonStr(obj, sub);
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.ReferenceAxis = %s",name.c_str(),axis.c_str()); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.ReferenceAxis = %s",name.c_str(),axis.c_str());
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Midplane = %i",name.c_str(), getMidplane() ? 1 : 0); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Midplane = %i",name.c_str(), getMidplane() ? 1 : 0);

View File

@ -79,7 +79,7 @@ const QString TaskSketchBasedParameters::onAddSelection(const Gui::SelectionChan
refStr = QString::fromAscii(selObj->getNameInDocument()); refStr = QString::fromAscii(selObj->getNameInDocument());
} else { } else {
int faceId = std::atoi(&subname[4]); int faceId = std::atoi(&subname[4]);
refStr = QString::fromAscii(selObj->getNameInDocument()) + QObject::tr(":Face") + QString::number(faceId); refStr = QString::fromAscii(selObj->getNameInDocument()) + QString::fromAscii(":") + QObject::tr("Face") + QString::number(faceId);
} }
std::vector<std::string> upToFaces(1,subname); std::vector<std::string> upToFaces(1,subname);