PartGui: Extrude: new task dialog
to account for new functionality of extrusion feature.
This commit is contained in:
parent
98418a4e0c
commit
fa2b70878e
|
@ -23,13 +23,17 @@
|
|||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
# include <BRepAdaptor_Surface.hxx>
|
||||
# include <BRepLProp_SLProps.hxx>
|
||||
# include <BRepGProp_Face.hxx>
|
||||
# include <Precision.hxx>
|
||||
# include <TopoDS.hxx>
|
||||
# include <TopoDS_Face.hxx>
|
||||
# include <BRepAdaptor_Surface.hxx>
|
||||
# include <BRepAdaptor_Curve.hxx>
|
||||
# include <BRepLProp_SLProps.hxx>
|
||||
# include <BRepGProp_Face.hxx>
|
||||
# include <BRep_Tool.hxx>
|
||||
# include <Precision.hxx>
|
||||
# include <TopoDS.hxx>
|
||||
# include <TopoDS_Face.hxx>
|
||||
# include <TopExp_Explorer.hxx>
|
||||
# include <ShapeExtend_Explorer.hxx>
|
||||
# include <TopTools_HSequenceOfShape.hxx>
|
||||
# include <QMessageBox>
|
||||
# include <Inventor/system/inttypes.h>
|
||||
#endif
|
||||
|
@ -39,6 +43,7 @@
|
|||
#include "../App/PartFeature.h"
|
||||
#include <Base/Console.h>
|
||||
#include <Base/UnitsApi.h>
|
||||
#include <Base/Interpreter.h>
|
||||
#include <App/Application.h>
|
||||
#include <App/Document.h>
|
||||
#include <App/DocumentObject.h>
|
||||
|
@ -52,23 +57,71 @@
|
|||
|
||||
using namespace PartGui;
|
||||
|
||||
class DlgExtrusion::EdgeSelection : public Gui::SelectionFilterGate
|
||||
{
|
||||
public:
|
||||
bool canSelect;
|
||||
|
||||
EdgeSelection()
|
||||
: Gui::SelectionFilterGate((Gui::SelectionFilter*)0)
|
||||
{
|
||||
canSelect = false;
|
||||
}
|
||||
bool allow(App::Document* pDoc, App::DocumentObject* pObj, const char* sSubName)
|
||||
{
|
||||
this->canSelect = false;
|
||||
if (!pObj->isDerivedFrom(Part::Feature::getClassTypeId()))
|
||||
return false;
|
||||
if (!sSubName || sSubName[0] == '\0')
|
||||
return false;
|
||||
std::string element(sSubName);
|
||||
if (element.substr(0,4) != "Edge")
|
||||
return false;
|
||||
Part::Feature* fea = static_cast<Part::Feature*>(pObj);
|
||||
try {
|
||||
TopoDS_Shape sub = fea->Shape.getShape().getSubShape(sSubName);
|
||||
if (!sub.IsNull() && sub.ShapeType() == TopAbs_EDGE) {
|
||||
const TopoDS_Edge& edge = TopoDS::Edge(sub);
|
||||
BRepAdaptor_Curve adapt(edge);
|
||||
if (adapt.GetType() == GeomAbs_Line) {
|
||||
this->canSelect = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
DlgExtrusion::DlgExtrusion(QWidget* parent, Qt::WindowFlags fl)
|
||||
: QDialog(parent, fl), ui(new Ui_DlgExtrusion)
|
||||
: QDialog(parent, fl), ui(new Ui_DlgExtrusion), filter(nullptr)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->statusLabel->clear();
|
||||
ui->labelNormal->hide();
|
||||
ui->viewButton->hide();
|
||||
ui->dirX->setDecimals(Base::UnitsApi::getDecimals());
|
||||
ui->dirY->setDecimals(Base::UnitsApi::getDecimals());
|
||||
ui->dirZ->setDecimals(Base::UnitsApi::getDecimals());
|
||||
ui->dirLen->setUnit(Base::Unit::Length);
|
||||
ui->taperAngle->setUnit(Base::Unit::Angle);
|
||||
ui->dirLen->setMinimumWidth(55); // needed to show all digits
|
||||
ui->spinLenFwd->setUnit(Base::Unit::Length);
|
||||
ui->spinLenFwd->setValue(10.0);
|
||||
ui->spinLenRev->setUnit(Base::Unit::Length);
|
||||
ui->spinTaperAngle->setUnit(Base::Unit::Angle);
|
||||
ui->spinTaperAngle->setUnit(Base::Unit::Angle);
|
||||
findShapes();
|
||||
|
||||
Gui::ItemViewSelection sel(ui->treeWidget);
|
||||
sel.applyFrom(Gui::Selection().getObjectsOfType(Part::Feature::getClassTypeId()));
|
||||
|
||||
this->on_DirMode_changed();
|
||||
ui->spinLenFwd->selectAll();
|
||||
// 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
|
||||
// yet visible.
|
||||
QMetaObject::invokeMethod(ui->spinLenFwd, "setFocus", Qt::QueuedConnection);
|
||||
|
||||
this->autoSolid();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -88,6 +141,198 @@ void DlgExtrusion::changeEvent(QEvent *e)
|
|||
QDialog::changeEvent(e);
|
||||
}
|
||||
|
||||
void DlgExtrusion::on_rbDirModeCustom_toggled(bool on)
|
||||
{
|
||||
if(on) //this check prevents dual fire of dirmode changed - on radio buttons, one will come on, and other will come off, causing two events.
|
||||
this->on_DirMode_changed();
|
||||
}
|
||||
|
||||
void DlgExtrusion::on_rbDirModeEdge_toggled(bool on)
|
||||
{
|
||||
if(on)
|
||||
this->on_DirMode_changed();
|
||||
}
|
||||
|
||||
void DlgExtrusion::on_rbDirModeNormal_toggled(bool on)
|
||||
{
|
||||
if(on)
|
||||
this->on_DirMode_changed();
|
||||
}
|
||||
|
||||
void DlgExtrusion::on_btnSelectEdge_clicked()
|
||||
{
|
||||
if (!filter) {
|
||||
filter = new EdgeSelection();
|
||||
Gui::Selection().addSelectionGate(filter);
|
||||
ui->btnSelectEdge->setText(tr("Selecting..."));
|
||||
|
||||
//visibility automation
|
||||
try{
|
||||
QString code = QString::fromLatin1(
|
||||
"import TempoVis\n"
|
||||
"tv = TempoVis.TempoVis(App.ActiveDocument)\n"
|
||||
"tv.hide([%1])"
|
||||
);
|
||||
std::vector<App::DocumentObject*>sources = getShapesToExtrude();
|
||||
QString features_to_hide;
|
||||
for (App::DocumentObject* obj: sources){
|
||||
if (!obj)
|
||||
continue;
|
||||
features_to_hide.append(QString::fromLatin1("App.ActiveDocument."));
|
||||
features_to_hide.append(QString::fromLatin1(obj->getNameInDocument()));
|
||||
features_to_hide.append(QString::fromLatin1(", \n"));
|
||||
}
|
||||
QByteArray code_2 = code.arg(features_to_hide).toLatin1();
|
||||
Base::Interpreter().runString(code_2.constData());
|
||||
} catch (Base::PyException &e){
|
||||
e.ReportException();
|
||||
}
|
||||
} else {
|
||||
Gui::Selection().rmvSelectionGate();
|
||||
filter = nullptr;
|
||||
ui->btnSelectEdge->setText(tr("Select"));
|
||||
|
||||
//visibility automation
|
||||
try{
|
||||
Base::Interpreter().runString("del(tv)");
|
||||
} catch (Base::PyException &e){
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DlgExtrusion::on_btnX_clicked()
|
||||
{
|
||||
Base::Vector3d axis(1.0, 0.0, 0.0);
|
||||
if ((getDir() - axis).Length() < 1e-7)
|
||||
axis = axis * (-1);
|
||||
setDirMode(Part::Extrusion::dmCustom);
|
||||
setDir(axis);
|
||||
}
|
||||
|
||||
void DlgExtrusion::on_btnY_clicked()
|
||||
{
|
||||
Base::Vector3d axis(0.0, 1.0, 0.0);
|
||||
if ((getDir() - axis).Length() < 1e-7)
|
||||
axis = axis * (-1);
|
||||
setDirMode(Part::Extrusion::dmCustom);
|
||||
setDir(axis);
|
||||
}
|
||||
|
||||
void DlgExtrusion::on_btnZ_clicked()
|
||||
{
|
||||
Base::Vector3d axis(0.0, 0.0, 1.0);
|
||||
if ((getDir() - axis).Length() < 1e-7)
|
||||
axis = axis * (-1);
|
||||
setDirMode(Part::Extrusion::dmCustom);
|
||||
setDir(axis);
|
||||
}
|
||||
|
||||
void DlgExtrusion::on_chkSymmetric_toggled(bool on)
|
||||
{
|
||||
ui->spinLenRev->setEnabled(!on);
|
||||
}
|
||||
|
||||
void DlgExtrusion::on_txtLink_textChanged(QString)
|
||||
{
|
||||
this->fetchDir();
|
||||
}
|
||||
|
||||
void DlgExtrusion::on_DirMode_changed()
|
||||
{
|
||||
Part::Extrusion::eDirMode dirMode = this->getDirMode();
|
||||
ui->dirX->setEnabled(dirMode == Part::Extrusion::dmCustom);
|
||||
ui->dirY->setEnabled(dirMode == Part::Extrusion::dmCustom);
|
||||
ui->dirZ->setEnabled(dirMode == Part::Extrusion::dmCustom);
|
||||
ui->txtLink->setEnabled(dirMode == Part::Extrusion::dmEdge);
|
||||
this->fetchDir();
|
||||
}
|
||||
|
||||
void DlgExtrusion::onSelectionChanged(const Gui::SelectionChanges& msg)
|
||||
{
|
||||
if (msg.Type == Gui::SelectionChanges::AddSelection) {
|
||||
if (filter && filter->canSelect) {
|
||||
this->setAxisLink(msg.pObjectName, msg.pSubName);
|
||||
this->setDirMode(Part::Extrusion::dmEdge);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
App::DocumentObject& DlgExtrusion::getShapeToExtrude() const
|
||||
{
|
||||
std::vector<App::DocumentObject*> objs = this->getShapesToExtrude();
|
||||
if (objs.size() == 0)
|
||||
throw Base::Exception("No shapes selected");
|
||||
return *(objs[0]);
|
||||
}
|
||||
|
||||
void DlgExtrusion::fetchDir()
|
||||
{
|
||||
bool lengths_are_at_defaults =
|
||||
(fabs(ui->spinLenFwd->value().getValue() - 10.0) < 1e-7)
|
||||
&& (fabs(ui->spinLenRev->value().getValue() - 0.0) < 1e-7);
|
||||
bool lengths_are_zero =
|
||||
(fabs(ui->spinLenFwd->value().getValue() - 0.0) < 1e-7)
|
||||
&& (fabs(ui->spinLenRev->value().getValue() - 0.0) < 1e-7);
|
||||
|
||||
try{
|
||||
Base::Vector3d pos, dir;
|
||||
bool fetched = false;
|
||||
bool dir_has_valid_magnitude = false;
|
||||
if(this->getDirMode() == Part::Extrusion::dmEdge){
|
||||
App::PropertyLinkSub lnk; this->getAxisLink(lnk);
|
||||
fetched = Part::Extrusion::fetchAxisLink(lnk, pos, dir);
|
||||
dir_has_valid_magnitude = fetched;
|
||||
} else if (this->getDirMode() == Part::Extrusion::dmNormal){
|
||||
App::PropertyLink lnk;
|
||||
lnk.setValue(&this->getShapeToExtrude());
|
||||
dir = Part::Extrusion::calculateShapeNormal(lnk);
|
||||
fetched = true;
|
||||
}
|
||||
if (dir_has_valid_magnitude && lengths_are_at_defaults){
|
||||
ui->spinLenFwd->setValue(0);
|
||||
} else if (!dir_has_valid_magnitude && lengths_are_zero){
|
||||
ui->spinLenFwd->setValue(1.0);
|
||||
}
|
||||
if (fetched){
|
||||
this->setDir(dir);
|
||||
}
|
||||
} catch (Base::Exception &){
|
||||
|
||||
} catch (...){
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void DlgExtrusion::autoSolid()
|
||||
{
|
||||
try{
|
||||
App::DocumentObject &dobj = this->getShapeToExtrude();
|
||||
if (dobj.isDerivedFrom(Part::Feature::getClassTypeId())){
|
||||
Part::Feature &feature = static_cast<Part::Feature&>(dobj);
|
||||
TopoDS_Shape sh = feature.Shape.getValue();
|
||||
if (sh.IsNull())
|
||||
return;
|
||||
ShapeExtend_Explorer xp;
|
||||
Handle_TopTools_HSequenceOfShape leaves = xp.SeqFromCompound(sh, /*recursive= */Standard_True);
|
||||
int cntClosedWires = 0;
|
||||
for(int i = 0 ; i < leaves->Length() ; i++){
|
||||
const TopoDS_Shape &leaf = leaves->Value(i+1);
|
||||
if (leaf.IsNull())
|
||||
return;
|
||||
if (leaf.ShapeType() == TopAbs_WIRE || leaf.ShapeType() == TopAbs_EDGE){
|
||||
if (BRep_Tool::IsClosed(leaf)){
|
||||
cntClosedWires++;
|
||||
}
|
||||
}
|
||||
}
|
||||
ui->chkSolid->setChecked( cntClosedWires == leaves->Length() );
|
||||
}
|
||||
} catch(...){
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void DlgExtrusion::findShapes()
|
||||
{
|
||||
App::Document* activeDoc = App::GetApplication().getActiveDocument();
|
||||
|
@ -139,134 +384,318 @@ bool DlgExtrusion::canExtrude(const TopoDS_Shape& shape) const
|
|||
|
||||
void DlgExtrusion::accept()
|
||||
{
|
||||
apply();
|
||||
QDialog::accept();
|
||||
try{
|
||||
apply();
|
||||
QDialog::accept();
|
||||
} catch (Base::AbortException){
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
void DlgExtrusion::apply()
|
||||
{
|
||||
if (ui->treeWidget->selectedItems().isEmpty()) {
|
||||
QMessageBox::critical(this, windowTitle(),
|
||||
tr("Select a shape for extrusion, first."));
|
||||
return;
|
||||
}
|
||||
try{
|
||||
if (!validate())
|
||||
throw Base::AbortException();
|
||||
|
||||
Gui::WaitCursor wc;
|
||||
App::Document* activeDoc = App::GetApplication().getDocument(this->document.c_str());
|
||||
if (!activeDoc) {
|
||||
QMessageBox::critical(this, windowTitle(),
|
||||
tr("The document '%1' doesn't exist.").arg(QString::fromUtf8(this->label.c_str())));
|
||||
return;
|
||||
}
|
||||
activeDoc->openTransaction("Extrude");
|
||||
if (filter) //if still selecting edge - stop. This is important for visibility automation.
|
||||
this->on_btnSelectEdge_clicked();
|
||||
|
||||
Base::Reference<ParameterGrp> hGrp = App::GetApplication().GetUserParameter()
|
||||
.GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/Part");
|
||||
bool addBaseName = hGrp->GetBool("AddBaseObjectName", false);
|
||||
|
||||
QString shape, type, name, label;
|
||||
QList<QTreeWidgetItem *> items = ui->treeWidget->selectedItems();
|
||||
for (QList<QTreeWidgetItem *>::iterator it = items.begin(); it != items.end(); ++it) {
|
||||
shape = (*it)->data(0, Qt::UserRole).toString();
|
||||
type = QString::fromLatin1("Part::Extrusion");
|
||||
if (addBaseName) {
|
||||
QString baseName = QString::fromLatin1("Extrude_%1").arg(shape);
|
||||
label = QString::fromLatin1("%1_Extrude").arg((*it)->text(0));
|
||||
name = QString::fromLatin1(activeDoc->getUniqueObjectName((const char*)baseName.toLatin1()).c_str());
|
||||
}
|
||||
else {
|
||||
name = QString::fromLatin1(activeDoc->getUniqueObjectName("Extrude").c_str());
|
||||
label = name;
|
||||
Gui::WaitCursor wc;
|
||||
App::Document* activeDoc = App::GetApplication().getDocument(this->document.c_str());
|
||||
if (!activeDoc) {
|
||||
QMessageBox::critical(this, windowTitle(),
|
||||
tr("The document '%1' doesn't exist.").arg(QString::fromUtf8(this->label.c_str())));
|
||||
return;
|
||||
}
|
||||
activeDoc->openTransaction("Extrude");
|
||||
|
||||
double dirX = ui->dirX->value();
|
||||
double dirY = ui->dirY->value();
|
||||
double dirZ = ui->dirZ->value();
|
||||
double len = ui->dirLen->value().getValue();
|
||||
double angle = ui->taperAngle->value().getValue();
|
||||
bool makeSolid = ui->makeSolid->isChecked();
|
||||
Base::Reference<ParameterGrp> hGrp = App::GetApplication().GetUserParameter()
|
||||
.GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/Part");
|
||||
bool addBaseName = hGrp->GetBool("AddBaseObjectName", false);
|
||||
|
||||
// inspect geometry
|
||||
App::DocumentObject* obj = activeDoc->getObject((const char*)shape.toLatin1());
|
||||
if (!obj || !obj->isDerivedFrom(Part::Feature::getClassTypeId())) continue;
|
||||
Part::Feature* fea = static_cast<Part::Feature*>(obj);
|
||||
const TopoDS_Shape& data = fea->Shape.getValue();
|
||||
if (data.IsNull()) continue;
|
||||
std::vector<App::DocumentObject*> objects = this->getShapesToExtrude();
|
||||
for (App::DocumentObject* sourceObj: objects) {
|
||||
assert(sourceObj);
|
||||
|
||||
// check for planes
|
||||
if (ui->checkNormal->isChecked() && data.ShapeType() == TopAbs_FACE) {
|
||||
BRepAdaptor_Surface adapt(TopoDS::Face(data));
|
||||
if (adapt.GetType() == GeomAbs_Plane) {
|
||||
double u = 0.5*(adapt.FirstUParameter() + adapt.LastUParameter());
|
||||
double v = 0.5*(adapt.FirstVParameter() + adapt.LastVParameter());
|
||||
BRepLProp_SLProps prop(adapt,u,v,1,Precision::Confusion());
|
||||
if (prop.IsNormalDefined()) {
|
||||
gp_Pnt pnt; gp_Vec vec;
|
||||
// handles the orientation state of the shape
|
||||
BRepGProp_Face(TopoDS::Face(data)).Normal(u,v,pnt,vec);
|
||||
dirX = vec.X();
|
||||
dirY = vec.Y();
|
||||
dirZ = vec.Z();
|
||||
}
|
||||
if (!sourceObj->isDerivedFrom(Part::Feature::getClassTypeId())){
|
||||
std::stringstream errmsg;
|
||||
errmsg << "Object " << sourceObj->getNameInDocument() << " is not Part object (has no OCC shape). Can't extrude it.\n";
|
||||
Base::Console().Error(errmsg.str().c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string name;
|
||||
name = sourceObj->getDocument()->getUniqueObjectName("Extrude").c_str();
|
||||
if (addBaseName) {
|
||||
//FIXME: implement
|
||||
//QString baseName = QString::fromLatin1("Extrude_%1").arg(sourceObjectName);
|
||||
//label = QString::fromLatin1("%1_Extrude").arg((*it)->text(0));
|
||||
}
|
||||
|
||||
Gui::Command::doCommand(Gui::Command::Doc, "f = FreeCAD.getDocument('%s').addObject('Part::Extrusion', '%s')", sourceObj->getDocument()->getName(), name.c_str());
|
||||
|
||||
this->writeParametersToFeature(*(sourceObj->getDocument()->getObject(name.c_str())), sourceObj);
|
||||
|
||||
std::string sourceObjectName = sourceObj->getNameInDocument();
|
||||
Gui::Command::copyVisual(name.c_str(), "ShapeColor", sourceObjectName.c_str());
|
||||
Gui::Command::copyVisual(name.c_str(), "LineColor", sourceObjectName.c_str());
|
||||
Gui::Command::copyVisual(name.c_str(), "PointColor", sourceObjectName.c_str());
|
||||
|
||||
Gui::Command::doCommand(Gui::Command::Gui,"f.Base.ViewObject.hide()");
|
||||
}
|
||||
|
||||
QString code = QString::fromLatin1(
|
||||
"FreeCAD.getDocument(\"%1\").addObject(\"%2\",\"%3\")\n"
|
||||
"FreeCAD.getDocument(\"%1\").%3.Base = FreeCAD.getDocument(\"%1\").%4\n"
|
||||
"FreeCAD.getDocument(\"%1\").%3.Dir = (%5,%6,%7)\n"
|
||||
"FreeCAD.getDocument(\"%1\").%3.Solid = (%8)\n"
|
||||
"FreeCAD.getDocument(\"%1\").%3.TaperAngle = (%9)\n"
|
||||
"FreeCADGui.getDocument(\"%1\").%4.Visibility = False\n"
|
||||
"FreeCAD.getDocument(\"%1\").%3.Label = '%10'\n")
|
||||
.arg(QString::fromLatin1(this->document.c_str()))
|
||||
.arg(type).arg(name).arg(shape)
|
||||
.arg(dirX*len)
|
||||
.arg(dirY*len)
|
||||
.arg(dirZ*len)
|
||||
.arg(makeSolid ? QLatin1String("True") : QLatin1String("False"))
|
||||
.arg(angle)
|
||||
.arg(label);
|
||||
Gui::Application::Instance->runPythonCode((const char*)code.toLatin1());
|
||||
QByteArray to = name.toLatin1();
|
||||
QByteArray from = shape.toLatin1();
|
||||
Gui::Command::copyVisual(to, "ShapeColor", from);
|
||||
Gui::Command::copyVisual(to, "LineColor", from);
|
||||
Gui::Command::copyVisual(to, "PointColor", from);
|
||||
activeDoc->commitTransaction();
|
||||
Gui::Command::updateActive();
|
||||
}
|
||||
|
||||
activeDoc->commitTransaction();
|
||||
try {
|
||||
ui->statusLabel->clear();
|
||||
activeDoc->recompute();
|
||||
ui->statusLabel->setText(QString::fromLatin1
|
||||
("<span style=\" color:#55aa00;\">%1</span>").arg(tr("Succeeded")));
|
||||
catch (Base::AbortException){
|
||||
throw;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
ui->statusLabel->setText(QString::fromLatin1
|
||||
("<span style=\" color:#ff0000;\">%1</span>").arg(tr("Failed")));
|
||||
Base::Console().Error("%s\n", e.what());
|
||||
catch (Base::Exception &err){
|
||||
QMessageBox::critical(this, windowTitle(),
|
||||
tr("Creating Extrusion failed.\n\n%1").arg(QString::fromUtf8(err.what())));
|
||||
return;
|
||||
}
|
||||
catch (const Base::Exception& e) {
|
||||
ui->statusLabel->setText(QString::fromLatin1
|
||||
("<span style=\" color:#ff0000;\">%1</span>").arg(tr("Failed")));
|
||||
Base::Console().Error("%s\n", e.what());
|
||||
}
|
||||
catch (...) {
|
||||
ui->statusLabel->setText(QString::fromLatin1
|
||||
("<span style=\" color:#ff0000;\">%1</span>").arg(tr("Failed")));
|
||||
Base::Console().Error("General error in extrusion\n");
|
||||
catch(...) {
|
||||
QMessageBox::critical(this, windowTitle(),
|
||||
tr("Creating Extrusion failed.\n\n%1").arg(QString::fromUtf8("Unknown error")));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void DlgExtrusion::on_checkNormal_toggled(bool b)
|
||||
Base::Vector3d DlgExtrusion::getDir() const
|
||||
{
|
||||
//ui->dirX->setDisabled(b);
|
||||
//ui->dirY->setDisabled(b);
|
||||
//ui->dirZ->setDisabled(b);
|
||||
ui->labelNormal->setVisible(b);
|
||||
return Base::Vector3d(
|
||||
ui->dirX->value(),
|
||||
ui->dirY->value(),
|
||||
ui->dirZ->value());
|
||||
}
|
||||
|
||||
void DlgExtrusion::setDir(Base::Vector3d newDir)
|
||||
{
|
||||
ui->dirX->setValue(newDir.x);
|
||||
ui->dirY->setValue(newDir.y);
|
||||
ui->dirZ->setValue(newDir.z);
|
||||
}
|
||||
|
||||
Part::Extrusion::eDirMode DlgExtrusion::getDirMode() const
|
||||
{
|
||||
if(ui->rbDirModeCustom->isChecked())
|
||||
return Part::Extrusion::dmCustom;
|
||||
if(ui->rbDirModeEdge->isChecked())
|
||||
return Part::Extrusion::dmEdge;
|
||||
if(ui->rbDirModeNormal->isChecked())
|
||||
return Part::Extrusion::dmNormal;
|
||||
|
||||
//we shouldn't get here...
|
||||
return Part::Extrusion::dmCustom;
|
||||
}
|
||||
|
||||
void DlgExtrusion::setDirMode(Part::Extrusion::eDirMode newMode)
|
||||
{
|
||||
ui->rbDirModeCustom->blockSignals(true);
|
||||
ui->rbDirModeEdge->blockSignals(true);
|
||||
ui->rbDirModeNormal->blockSignals(true);
|
||||
|
||||
ui->rbDirModeCustom->setChecked(newMode == Part::Extrusion::dmCustom);
|
||||
ui->rbDirModeEdge->setChecked(newMode == Part::Extrusion::dmEdge);
|
||||
ui->rbDirModeNormal->setChecked(newMode == Part::Extrusion::dmNormal);
|
||||
|
||||
ui->rbDirModeCustom->blockSignals(false);
|
||||
ui->rbDirModeEdge->blockSignals(false);
|
||||
ui->rbDirModeNormal->blockSignals(false);
|
||||
this->on_DirMode_changed();
|
||||
}
|
||||
|
||||
void DlgExtrusion::getAxisLink(App::PropertyLinkSub& lnk) const
|
||||
{
|
||||
QString text = ui->txtLink->text();
|
||||
|
||||
if (text.length() == 0) {
|
||||
lnk.setValue(nullptr);
|
||||
} else {
|
||||
QStringList parts = text.split(QChar::fromLatin1(':'));
|
||||
App::DocumentObject* obj = App::GetApplication().getActiveDocument()->getObject(parts[0].toLatin1());
|
||||
if(!obj){
|
||||
throw Base::ValueError(tr("Object not found: %1").arg(parts[0]).toUtf8().constData());
|
||||
}
|
||||
lnk.setValue(obj);
|
||||
if (parts.size() == 1) {
|
||||
return;
|
||||
} else if (parts.size() == 2) {
|
||||
std::vector<std::string> subs;
|
||||
subs.push_back(std::string(parts[1].toLatin1().constData()));
|
||||
lnk.setValue(obj,subs);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void DlgExtrusion::setAxisLink(const App::PropertyLinkSub& lnk)
|
||||
{
|
||||
if (!lnk.getValue()){
|
||||
ui->txtLink->clear();
|
||||
return;
|
||||
}
|
||||
if (lnk.getSubValues().size() == 1){
|
||||
this->setAxisLink(lnk.getValue()->getNameInDocument(), lnk.getSubValues()[0].c_str());
|
||||
} else {
|
||||
this->setAxisLink(lnk.getValue()->getNameInDocument(), "");
|
||||
}
|
||||
}
|
||||
|
||||
void DlgExtrusion::setAxisLink(const char* objname, const char* subname)
|
||||
{
|
||||
if(objname && strlen(objname) > 0){
|
||||
QString txt = QString::fromLatin1(objname);
|
||||
if (subname && strlen(subname) > 0){
|
||||
txt = txt + QString::fromLatin1(":") + QString::fromLatin1(subname);
|
||||
}
|
||||
ui->txtLink->setText(txt);
|
||||
} else {
|
||||
ui->txtLink->clear();
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<App::DocumentObject*> DlgExtrusion::getShapesToExtrude() const
|
||||
{
|
||||
QList<QTreeWidgetItem *> items = ui->treeWidget->selectedItems();
|
||||
App::Document* doc = App::GetApplication().getDocument(this->document.c_str());
|
||||
if (!doc)
|
||||
throw Base::Exception("Document lost");
|
||||
|
||||
std::vector<App::DocumentObject*> objects;
|
||||
for(size_t i = 0 ; i < items.size() ; i++){
|
||||
App::DocumentObject* obj = doc->getObject(items[i]->data(0, Qt::UserRole).toString().toLatin1());
|
||||
if (!obj)
|
||||
throw Base::Exception("Object not found");
|
||||
objects.push_back(obj);
|
||||
}
|
||||
return objects;
|
||||
}
|
||||
|
||||
bool DlgExtrusion::validate()
|
||||
{
|
||||
//check source shapes
|
||||
if (ui->treeWidget->selectedItems().isEmpty()) {
|
||||
QMessageBox::critical(this, windowTitle(),
|
||||
tr("No shapes selected for extrusion. Select some, first."));
|
||||
return false;
|
||||
}
|
||||
|
||||
//check axis link
|
||||
QString errmsg;
|
||||
bool hasValidAxisLink = false;
|
||||
try{
|
||||
App::PropertyLinkSub lnk;
|
||||
this->getAxisLink(lnk);
|
||||
Base::Vector3d dir, base;
|
||||
hasValidAxisLink = Part::Extrusion::fetchAxisLink(lnk, base, dir);
|
||||
} catch(Base::Exception &err) {
|
||||
errmsg = QString::fromUtf8(err.what());
|
||||
} catch(Standard_Failure &err) {
|
||||
errmsg = QString::fromLocal8Bit(err.GetMessageString());
|
||||
} catch(...) {
|
||||
errmsg = QString::fromUtf8("Unknown error");
|
||||
}
|
||||
if (this->getDirMode() == Part::Extrusion::dmEdge && !hasValidAxisLink){
|
||||
if (errmsg.length() > 0)
|
||||
QMessageBox::critical(this, windowTitle(), tr("Revolution axis link is invalid.\n\n%1").arg(errmsg));
|
||||
else
|
||||
QMessageBox::critical(this, windowTitle(), tr("Direction mode is to use an edge, but no edge is linked."));
|
||||
ui->txtLink->setFocus();
|
||||
return false;
|
||||
} else if (this->getDirMode() != Part::Extrusion::dmEdge && !hasValidAxisLink){
|
||||
//axis link is invalid, but it is not required by the mode. We shouldn't complain it's invalid then...
|
||||
ui->txtLink->clear();
|
||||
}
|
||||
|
||||
//check normal
|
||||
if (this->getDirMode() == Part::Extrusion::dmNormal){
|
||||
errmsg.clear();
|
||||
try {
|
||||
App::PropertyLink lnk;
|
||||
lnk.setValue(&this->getShapeToExtrude()); //simplified - check only for the first shape.
|
||||
Part::Extrusion::calculateShapeNormal(lnk);
|
||||
} catch(Base::Exception &err) {
|
||||
errmsg = QString::fromUtf8(err.what());
|
||||
} catch(Standard_Failure &err) {
|
||||
errmsg = QString::fromLocal8Bit(err.GetMessageString());
|
||||
} catch(...) {
|
||||
errmsg = QString::fromUtf8("Unknown error");
|
||||
}
|
||||
if (errmsg.length() > 0){
|
||||
QMessageBox::critical(this, windowTitle(), tr("Can't determine normal vector of shape to be extruded. Please use other mode. \n\n(%1)").arg(errmsg));
|
||||
ui->rbDirModeNormal->setFocus();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//check axis dir
|
||||
if (this->getDirMode() == Part::Extrusion::dmCustom){
|
||||
if(this->getDir().Length() < Precision::Confusion()){
|
||||
QMessageBox::critical(this, windowTitle(),
|
||||
tr("Extrusion direction is zero-length. It must be non-zero."));
|
||||
ui->dirX->setFocus();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//check lengths
|
||||
if (!ui->chkSymmetric->isChecked()
|
||||
&& fabs(ui->spinLenFwd->value().getValue() + ui->spinLenRev->value().getValue()) < Precision::Confusion()
|
||||
&& ! (fabs(ui->spinLenFwd->value().getValue() - ui->spinLenRev->value().getValue()) < Precision::Confusion())){
|
||||
QMessageBox::critical(this, windowTitle(),
|
||||
tr("Total extrusion length is zero (length1 == -length2). It must be nonzero."));
|
||||
ui->spinLenFwd->setFocus();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DlgExtrusion::writeParametersToFeature(App::DocumentObject &feature, App::DocumentObject* base) const
|
||||
{
|
||||
Gui::Command::doCommand(Gui::Command::Doc,"f = App.getDocument('%s').getObject('%s')", feature.getDocument()->getName(), feature.getNameInDocument());
|
||||
|
||||
if (base)
|
||||
Gui::Command::doCommand(Gui::Command::Doc,"f.Base = App.getDocument('%s').getObject('%s')", base->getDocument()->getName(), base->getNameInDocument());
|
||||
|
||||
Part::Extrusion::eDirMode dirMode = this->getDirMode();
|
||||
const char* modestr = Part::Extrusion::eDirModeStrings[dirMode];
|
||||
Gui::Command::doCommand(Gui::Command::Doc,"f.DirMode = \"%s\"", modestr);
|
||||
|
||||
if (dirMode == Part::Extrusion::dmCustom){
|
||||
Base::Vector3d dir = this->getDir();
|
||||
Gui::Command::doCommand(Gui::Command::Doc, "f.Dir = App.Vector(%.15f, %.15f, %.15f)", dir.x, dir.y, dir.z);
|
||||
}
|
||||
|
||||
App::PropertyLinkSub lnk;
|
||||
this->getAxisLink(lnk);
|
||||
std::stringstream linkstr;
|
||||
if(lnk.getValue() == nullptr){
|
||||
linkstr << "None";
|
||||
} else {
|
||||
linkstr << "(App.getDocument(\"" << lnk.getValue()->getDocument()->getName() <<"\")." << lnk.getValue()->getNameInDocument();
|
||||
linkstr << ", [";
|
||||
for (const std::string &str: lnk.getSubValues()){
|
||||
linkstr << "\"" << str << "\"";
|
||||
}
|
||||
linkstr << "])";
|
||||
}
|
||||
Gui::Command::doCommand(Gui::Command::Doc,"f.DirLink = %s", linkstr.str().c_str());
|
||||
|
||||
Gui::Command::doCommand(Gui::Command::Doc,"f.LengthFwd = %.15f", ui->spinLenFwd->value().getValue());
|
||||
Gui::Command::doCommand(Gui::Command::Doc,"f.LengthRev = %.15f", ui->spinLenRev->value().getValue());
|
||||
|
||||
Gui::Command::doCommand(Gui::Command::Doc,"f.Solid = %s", ui->chkSolid->isChecked() ? "True" : "False");
|
||||
Gui::Command::doCommand(Gui::Command::Doc,"f.Reversed = %s", ui->chkReversed->isChecked() ? "True" : "False");
|
||||
Gui::Command::doCommand(Gui::Command::Doc,"f.Symmetric = %s", ui->chkSymmetric->isChecked() ? "True" : "False");
|
||||
Gui::Command::doCommand(Gui::Command::Doc,"f.TaperAngle = %.15f", ui->spinTaperAngle->value().getValue());
|
||||
Gui::Command::doCommand(Gui::Command::Doc,"f.TaperAngleRev = %.15f", ui->spinTaperAngleRev->value().getValue());
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------
|
||||
|
||||
TaskExtrusion::TaskExtrusion()
|
||||
|
@ -298,7 +727,11 @@ bool TaskExtrusion::reject()
|
|||
void TaskExtrusion::clicked(int id)
|
||||
{
|
||||
if (id == QDialogButtonBox::Apply) {
|
||||
widget->apply();
|
||||
try{
|
||||
widget->apply();
|
||||
} catch (Base::AbortException){
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,12 +27,14 @@
|
|||
#include <Gui/TaskView/TaskView.h>
|
||||
#include <string>
|
||||
|
||||
#include <Mod/Part/App/FeatureExtrusion.h>
|
||||
|
||||
class TopoDS_Shape;
|
||||
|
||||
namespace PartGui {
|
||||
|
||||
class Ui_DlgExtrusion;
|
||||
class DlgExtrusion : public QDialog
|
||||
class DlgExtrusion : public QDialog, public Gui::SelectionObserver
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
@ -42,17 +44,55 @@ public:
|
|||
void accept();
|
||||
void apply();
|
||||
|
||||
Base::Vector3d getDir() const;
|
||||
void setDir(Base::Vector3d newDir);
|
||||
|
||||
Part::Extrusion::eDirMode getDirMode() const;
|
||||
void setDirMode(Part::Extrusion::eDirMode newMode);
|
||||
|
||||
void getAxisLink(App::PropertyLinkSub &lnk) const;
|
||||
void setAxisLink(const App::PropertyLinkSub &lnk);
|
||||
void setAxisLink(const char* objname, const char* subname);
|
||||
|
||||
std::vector<App::DocumentObject*> getShapesToExtrude() const;
|
||||
|
||||
bool validate();
|
||||
|
||||
void writeParametersToFeature(App::DocumentObject& feature, App::DocumentObject* base) const;
|
||||
|
||||
protected:
|
||||
void findShapes();
|
||||
bool canExtrude(const TopoDS_Shape&) const;
|
||||
void changeEvent(QEvent *e);
|
||||
|
||||
private Q_SLOTS:
|
||||
void on_checkNormal_toggled(bool);
|
||||
void on_rbDirModeCustom_toggled(bool on);
|
||||
void on_rbDirModeEdge_toggled(bool on);
|
||||
void on_rbDirModeNormal_toggled(bool on);
|
||||
void on_btnSelectEdge_clicked();
|
||||
void on_btnX_clicked();
|
||||
void on_btnY_clicked();
|
||||
void on_btnZ_clicked();
|
||||
void on_chkSymmetric_toggled(bool on);
|
||||
void on_txtLink_textChanged(QString);
|
||||
|
||||
private:
|
||||
///updates enabling of controls
|
||||
void on_DirMode_changed();
|
||||
void onSelectionChanged(const Gui::SelectionChanges& msg);
|
||||
///returns link to any of selected source shapes. Throws if nothing is selected for extrusion.
|
||||
App::DocumentObject& getShapeToExtrude() const;
|
||||
///if dirMode is not custom, it tries to compute the actual extrusion direction. Also, it does some auto-magic manipulation of length value.
|
||||
void fetchDir();
|
||||
|
||||
///automatically checks Solid checkbox depending on input shape
|
||||
void autoSolid();
|
||||
|
||||
private:
|
||||
Ui_DlgExtrusion* ui;
|
||||
std::string document, label;
|
||||
class EdgeSelection;
|
||||
EdgeSelection* filter;
|
||||
};
|
||||
|
||||
class TaskExtrusion : public Gui::TaskView::TaskDialog
|
||||
|
|
|
@ -6,15 +6,15 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>260</width>
|
||||
<height>545</height>
|
||||
<width>343</width>
|
||||
<height>798</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Extrude</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="0" column="0">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
|
@ -26,52 +26,70 @@
|
|||
<string>Direction</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="checkNormal">
|
||||
<item row="4" column="2">
|
||||
<widget class="QCheckBox" name="chkReversed">
|
||||
<property name="toolTip">
|
||||
<string>If checked, direction of extrusion is reversed.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Reversed</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QRadioButton" name="rbDirModeCustom">
|
||||
<property name="toolTip">
|
||||
<string>Specify direction manually using X,Y,Z values.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Custom direction:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QRadioButton" name="rbDirModeNormal">
|
||||
<property name="toolTip">
|
||||
<string>Extrude perpendicularly to plane of input shape.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Along normal</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QPushButton" name="viewButton">
|
||||
<item row="5" column="2">
|
||||
<widget class="QPushButton" name="btnSelectEdge">
|
||||
<property name="toolTip">
|
||||
<string>Click to start selecting an edge in 3d view.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>3D view</string>
|
||||
<string>Select</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>43</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLineEdit" name="txtLink"/>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="3">
|
||||
<widget class="QLabel" name="labelNormal">
|
||||
<item row="4" column="0">
|
||||
<widget class="QRadioButton" name="rbDirModeEdge">
|
||||
<property name="toolTip">
|
||||
<string>Set direction to match a direction of straight edge. Hint: to account for length of the edge too, set both lengths to zero.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Note:This option works for planes only</string>
|
||||
<string>Along edge:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="3">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>X:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0" colspan="3">
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<property name="labelAlignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="formAlignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<item row="0" column="1">
|
||||
<widget class="QDoubleSpinBox" name="dirX">
|
||||
<property name="sizePolicy">
|
||||
|
@ -81,20 +99,10 @@
|
|||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-100.000000000000000</double>
|
||||
<double>-2147480000.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>100.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Y:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
<double>2147480000.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -107,20 +115,10 @@
|
|||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-100.000000000000000</double>
|
||||
<double>-2147480000.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>100.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Z:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
<double>2147480000.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -132,40 +130,11 @@
|
|||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-100.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>100.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Length:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="Gui::QuantitySpinBox" name="dirLen">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="unit" stdset="0">
|
||||
<string notr="true">mm</string>
|
||||
<property name="keyboardTracking">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.001000000000000</double>
|
||||
<double>-2147480000.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>2147480000.000000000000000</double>
|
||||
|
@ -175,46 +144,207 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QPushButton" name="btnX">
|
||||
<property name="toolTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>X:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QPushButton" name="btnY">
|
||||
<property name="text">
|
||||
<string>Y:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QPushButton" name="btnZ">
|
||||
<property name="text">
|
||||
<string>Z:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="makeSolid">
|
||||
<property name="text">
|
||||
<string>Create solid</string>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Length</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout_2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Along</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Against</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="Gui::QuantitySpinBox" name="spinLenFwd" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Length to extrude along direction (can be negative). If both lengths are zero, magnitude of direction is used.</string>
|
||||
</property>
|
||||
<property name="unit" stdset="0">
|
||||
<string notr="true">mm</string>
|
||||
</property>
|
||||
<property name="minimum" stdset="0">
|
||||
<double>-2147480000.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum" stdset="0">
|
||||
<double>2147480000.000000000000000</double>
|
||||
</property>
|
||||
<property name="value" stdset="0">
|
||||
<double>10.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="Gui::QuantitySpinBox" name="spinLenRev" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Length to extrude against direction (can be negative).</string>
|
||||
</property>
|
||||
<property name="unit" stdset="0">
|
||||
<string notr="true">mm</string>
|
||||
</property>
|
||||
<property name="minimum" stdset="0">
|
||||
<double>-2147480000.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum" stdset="0">
|
||||
<double>2147480000.000000000000000</double>
|
||||
</property>
|
||||
<property name="value" stdset="0">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="chkSymmetric">
|
||||
<property name="toolTip">
|
||||
<string>Distribute extrusion length equally to both sides.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Symmetric</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout_3">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Taper outward angle</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Gui::QuantitySpinBox" name="taperAngle">
|
||||
<item row="0" column="1">
|
||||
<widget class="Gui::QuantitySpinBox" name="spinTaperAngle" native="true">
|
||||
<property name="toolTip">
|
||||
<string>Apply slope (draft) to extrusion side faces.</string>
|
||||
</property>
|
||||
<property name="unit" stdset="0">
|
||||
<string notr="true">deg</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-180.000000000000000</double>
|
||||
<property name="minimum" stdset="0">
|
||||
<double>-89.999999000000003</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>180.000000000000000</double>
|
||||
<property name="maximum" stdset="0">
|
||||
<double>89.999999000000003</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<property name="singleStep" stdset="0">
|
||||
<double>5.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="Gui::QuantitySpinBox" name="spinTaperAngleRev" native="true">
|
||||
<property name="toolTip">
|
||||
<string>Apply slope (draft) to extrusion side faces.</string>
|
||||
</property>
|
||||
<property name="unit" stdset="0">
|
||||
<string notr="true">deg</string>
|
||||
</property>
|
||||
<property name="minimum" stdset="0">
|
||||
<double>-89.999999000000003</double>
|
||||
</property>
|
||||
<property name="maximum" stdset="0">
|
||||
<double>89.999999000000003</double>
|
||||
</property>
|
||||
<property name="singleStep" stdset="0">
|
||||
<double>5.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="chkSolid">
|
||||
<property name="toolTip">
|
||||
<string>If checked, extruding closed wires will give solids, not shells.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Create solid</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTreeWidget" name="treeWidget">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
|
@ -238,7 +368,7 @@
|
|||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<item>
|
||||
<widget class="QLabel" name="statusLabel">
|
||||
<property name="text">
|
||||
<string notr="true">StatusLabel</string>
|
||||
|
@ -246,6 +376,12 @@
|
|||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
<zorder>groupBox_2</zorder>
|
||||
<zorder>chkSolid</zorder>
|
||||
<zorder>treeWidget</zorder>
|
||||
<zorder>statusLabel</zorder>
|
||||
<zorder>groupBox</zorder>
|
||||
<zorder>line</zorder>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
|
@ -255,12 +391,25 @@
|
|||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>treeWidget</tabstop>
|
||||
<tabstop>rbDirModeNormal</tabstop>
|
||||
<tabstop>rbDirModeEdge</tabstop>
|
||||
<tabstop>chkReversed</tabstop>
|
||||
<tabstop>txtLink</tabstop>
|
||||
<tabstop>btnSelectEdge</tabstop>
|
||||
<tabstop>rbDirModeCustom</tabstop>
|
||||
<tabstop>btnX</tabstop>
|
||||
<tabstop>dirX</tabstop>
|
||||
<tabstop>btnY</tabstop>
|
||||
<tabstop>dirY</tabstop>
|
||||
<tabstop>btnZ</tabstop>
|
||||
<tabstop>dirZ</tabstop>
|
||||
<tabstop>dirLen</tabstop>
|
||||
<tabstop>checkNormal</tabstop>
|
||||
<tabstop>spinLenFwd</tabstop>
|
||||
<tabstop>spinLenRev</tabstop>
|
||||
<tabstop>chkSymmetric</tabstop>
|
||||
<tabstop>spinTaperAngle</tabstop>
|
||||
<tabstop>spinTaperAngleRev</tabstop>
|
||||
<tabstop>chkSolid</tabstop>
|
||||
<tabstop>treeWidget</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
|
|
Loading…
Reference in New Issue
Block a user