diff --git a/src/Mod/Part/Gui/DlgRevolution.cpp b/src/Mod/Part/Gui/DlgRevolution.cpp index 05f7957439b4..4171f39e5148 100644 --- a/src/Mod/Part/Gui/DlgRevolution.cpp +++ b/src/Mod/Part/Gui/DlgRevolution.cpp @@ -32,6 +32,7 @@ # include # include # include +# include #endif #include "ui_DlgRevolution.h" @@ -48,6 +49,7 @@ #include #include #include +#include #include #include @@ -58,8 +60,6 @@ using namespace PartGui; class DlgRevolution::EdgeSelection : public Gui::SelectionFilterGate { public: - gp_Pnt loc; - gp_Dir dir; bool canSelect; EdgeSelection() @@ -82,10 +82,7 @@ class DlgRevolution::EdgeSelection : public Gui::SelectionFilterGate if (!sub.IsNull() && sub.ShapeType() == TopAbs_EDGE) { const TopoDS_Edge& edge = TopoDS::Edge(sub); BRepAdaptor_Curve adapt(edge); - if (adapt.GetType() == GeomAbs_Line) { - gp_Lin line = adapt.Line(); - this->loc = line.Location(); - this->dir = line.Direction(); + if (adapt.GetType() == GeomAbs_Line || adapt.GetType() == GeomAbs_Circle) { this->canSelect = true; return true; } @@ -99,20 +96,36 @@ class DlgRevolution::EdgeSelection : public Gui::SelectionFilterGate }; DlgRevolution::DlgRevolution(QWidget* parent, Qt::WindowFlags fl) - : Gui::LocationDialog(parent, fl), filter(0) + : QDialog(parent, fl), filter(0) { - ui = new Ui_RevolutionComp(this); + ui = new Ui_DlgRevolution(); + + ui->setupUi(this); + ui->xPos->setRange(-DBL_MAX,DBL_MAX); ui->yPos->setRange(-DBL_MAX,DBL_MAX); ui->zPos->setRange(-DBL_MAX,DBL_MAX); ui->xPos->setUnit(Base::Unit::Length); ui->yPos->setUnit(Base::Unit::Length); ui->zPos->setUnit(Base::Unit::Length); + + ui->xDir->setRange(-DBL_MAX,DBL_MAX); + ui->yDir->setRange(-DBL_MAX,DBL_MAX); + ui->zDir->setRange(-DBL_MAX,DBL_MAX); + ui->xDir->setUnit(Base::Unit()); + ui->yDir->setUnit(Base::Unit()); + ui->zDir->setUnit(Base::Unit()); + ui->zDir->setValue(1.0); + ui->angle->setUnit(Base::Unit::Angle); + ui->angle->setValue(360.0); findShapes(); Gui::ItemViewSelection sel(ui->treeWidget); sel.applyFrom(Gui::Selection().getObjectsOfType(Part::Feature::getClassTypeId())); + + connect(ui->txtAxisLink, SIGNAL(textChanged(QString)), this, SLOT(on_txtAxisLink_textChanged(QString))); + } /* @@ -125,20 +138,154 @@ DlgRevolution::~DlgRevolution() delete ui; } -void DlgRevolution::directionActivated(int index) +Base::Vector3d DlgRevolution::getDirection() const { - ui->directionActivated(this, index); + return Base::Vector3d( + ui->xDir->value().getValue(), + ui->yDir->value().getValue(), + ui->zDir->value().getValue()); } -Base::Vector3d DlgRevolution::getDirection() const +Base::Vector3d DlgRevolution::getPosition() const { - return ui->getDirection(); + return Base::Vector3d( + ui->xPos->value().getValueAs(Base::Quantity::MilliMetre), + ui->yPos->value().getValueAs(Base::Quantity::MilliMetre), + ui->zPos->value().getValueAs(Base::Quantity::MilliMetre)); +} + +void DlgRevolution::getAxisLink(App::PropertyLinkSub &lnk) const +{ + QString text = ui->txtAxisLink->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 subs; + subs.push_back(std::string(parts[1].toLatin1().constData())); + lnk.setValue(obj,subs); + } + } + +} + +double DlgRevolution::getAngle() const +{ + return ui->angle->value().getValueAs(Base::Quantity::Degree); +} + +void DlgRevolution::setDirection(Base::Vector3d dir) +{ + ui->xDir->setValue(dir.x); + ui->yDir->setValue(dir.y); + ui->zDir->setValue(dir.z); +} + +void DlgRevolution::setPosition(Base::Vector3d pos) +{ + ui->xPos->setValue(pos.x); + ui->yPos->setValue(pos.y); + ui->zPos->setValue(pos.z); +} + +void DlgRevolution::setAxisLink(const App::PropertyLinkSub& lnk) +{ + if (!lnk.getValue()){ + ui->txtAxisLink->clear(); + return; + } + if (lnk.getSubValues().size() == 1){ + this->setAxisLink(lnk.getValue()->getNameInDocument(), lnk.getSubValues()[0].c_str()); + } else { + this->setAxisLink(lnk.getValue()->getNameInDocument(), ""); + } +} + +void DlgRevolution::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->txtAxisLink->setText(txt); + } else { + ui->txtAxisLink->clear(); + } +} + +bool DlgRevolution::validate() +{ + //check source shapes + if (ui->treeWidget->selectedItems().isEmpty()) { + QMessageBox::critical(this, windowTitle(), + tr("Select a shape for revolution, first.")); + return false; + } + + //check axis link + bool axisLinkIsValid = false; + bool axisLinkHasAngle = false; + try{ + App::PropertyLinkSub lnk; + this->getAxisLink(lnk); + double angle_edge = 1e100; + Base::Vector3d axis, center; + axisLinkIsValid = Part::Revolution::fetchAxisLink(lnk, center, axis, angle_edge); + axisLinkHasAngle = angle_edge != 1e100; + } catch(Base::Exception &err) { + QMessageBox::critical(this, windowTitle(), + tr("Revolution axis link is invalid.\n\n%1").arg(QString::fromUtf8(err.what()))); + ui->txtAxisLink->setFocus(); + return false; + } catch(Standard_Failure &err) { + QMessageBox::critical(this, windowTitle(), + tr("Revolution axis link is invalid.\n\n%1").arg(QString::fromLocal8Bit(err.GetMessageString()))); + ui->txtAxisLink->setFocus(); + return false; + } catch(...) { + QMessageBox::critical(this, windowTitle(), + tr("Revolution axis link is invalid.\n\n%1").arg(QString::fromUtf8("Unknown error"))); + ui->txtAxisLink->setFocus(); + return false; + } + + //check axis dir + if (!axisLinkIsValid){ + if(this->getDirection().Length() < Precision::Confusion()){ + QMessageBox::critical(this, windowTitle(), + tr("Revolution axis direction is zero-length. It must be non-zero.")); + ui->xDir->setFocus(); + return false; + } + } + + //check angle + if (!axisLinkHasAngle){ + if (fabs(this->getAngle() / 180.0 * M_PI) < Precision::Angular()){ + QMessageBox::critical(this, windowTitle(), + tr("Revolution angle span is zero. It must be non-zero.")); + ui->angle->setFocus(); + return false; + } + } + + return true; } void DlgRevolution::changeEvent(QEvent *e) { if (e->type() == QEvent::LanguageChange) { - ui->retranslate(this); + ui->retranslateUi(this); } else { QDialog::changeEvent(e); @@ -173,56 +320,89 @@ void DlgRevolution::findShapes() void DlgRevolution::accept() { - if (ui->treeWidget->selectedItems().isEmpty()) { - QMessageBox::critical(this, windowTitle(), - tr("Select a shape for revolution, first.")); + if (!this->validate()) return; - } - Gui::WaitCursor wc; App::Document* activeDoc = App::GetApplication().getActiveDocument(); activeDoc->openTransaction("Revolve"); - QString shape, type, name, solid; - QList items = ui->treeWidget->selectedItems(); - if (ui->checkSolid->isChecked()) { - solid = QString::fromLatin1("True");} - else { - solid = QString::fromLatin1("False");} - for (QList::iterator it = items.begin(); it != items.end(); ++it) { - shape = (*it)->data(0, Qt::UserRole).toString(); - type = QString::fromLatin1("Part::Revolution"); - name = QString::fromLatin1(activeDoc->getUniqueObjectName("Revolve").c_str()); - Base::Vector3d axis = this->getDirection(); - - QString code = QString::fromLatin1( - "FreeCAD.ActiveDocument.addObject(\"%1\",\"%2\")\n" - "FreeCAD.ActiveDocument.%2.Source = FreeCAD.ActiveDocument.%3\n" - "FreeCAD.ActiveDocument.%2.Axis = (%4,%5,%6)\n" - "FreeCAD.ActiveDocument.%2.Base = (%7,%8,%9)\n" - "FreeCAD.ActiveDocument.%2.Angle = %10\n" - "FreeCAD.ActiveDocument.%2.Solid = %11\n" - "FreeCADGui.ActiveDocument.%3.Visibility = False\n") - .arg(type).arg(name).arg(shape) - .arg(axis.x,0,'f',Base::UnitsApi::getDecimals()) - .arg(axis.y,0,'f',Base::UnitsApi::getDecimals()) - .arg(axis.z,0,'f',Base::UnitsApi::getDecimals()) - .arg(ui->xPos->value().getValue(), 0,'f',Base::UnitsApi::getDecimals()) - .arg(ui->yPos->value().getValue(), 0,'f',Base::UnitsApi::getDecimals()) - .arg(ui->zPos->value().getValue(), 0,'f',Base::UnitsApi::getDecimals()) - .arg(ui->angle->value().getValue(),0,'f',Base::UnitsApi::getDecimals()) - .arg(solid) - ; - 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); + try{ + QString shape, type, name, solid; + QList items = ui->treeWidget->selectedItems(); + if (ui->checkSolid->isChecked()) { + solid = QString::fromLatin1("True");} + else { + solid = QString::fromLatin1("False");} + + App::PropertyLinkSub axisLink; + this->getAxisLink(axisLink); + QString strAxisLink; + if (axisLink.getValue()){ + strAxisLink = QString::fromLatin1("(App.ActiveDocument.%1, %2)") + .arg(QString::fromLatin1(axisLink.getValue()->getNameInDocument())) + .arg(axisLink.getSubValues().size() == 1 ? + QString::fromLatin1("\"%1\"").arg(QString::fromLatin1(axisLink.getSubValues()[0].c_str())) + : QString() ); + } else { + strAxisLink = QString::fromLatin1("None"); + } + + QString symmetric; + if (ui->checkSymmetric->isChecked()) { + symmetric = QString::fromLatin1("True");} + else { + symmetric = QString::fromLatin1("False");} + + for (QList::iterator it = items.begin(); it != items.end(); ++it) { + shape = (*it)->data(0, Qt::UserRole).toString(); + type = QString::fromLatin1("Part::Revolution"); + name = QString::fromLatin1(activeDoc->getUniqueObjectName("Revolve").c_str()); + Base::Vector3d axis = this->getDirection(); + Base::Vector3d pos = this->getPosition(); + + + QString code = QString::fromLatin1( + "FreeCAD.ActiveDocument.addObject(\"%1\",\"%2\")\n" + "FreeCAD.ActiveDocument.%2.Source = FreeCAD.ActiveDocument.%3\n" + "FreeCAD.ActiveDocument.%2.Axis = (%4,%5,%6)\n" + "FreeCAD.ActiveDocument.%2.Base = (%7,%8,%9)\n" + "FreeCAD.ActiveDocument.%2.Angle = %10\n" + "FreeCAD.ActiveDocument.%2.Solid = %11\n" + "FreeCAD.ActiveDocument.%2.AxisLink = %12\n" + "FreeCAD.ActiveDocument.%2.Symmetric = %13\n" + "FreeCADGui.ActiveDocument.%3.Visibility = False\n") + .arg(type).arg(name).arg(shape) //%1, 2, 3 + .arg(axis.x,0,'f',15) //%4 + .arg(axis.y,0,'f',15) //%5 + .arg(axis.z,0,'f',15) //%6 + .arg(pos.x, 0,'f',15) //%7 + .arg(pos.y, 0,'f',15) //%8 + .arg(pos.z, 0,'f',15) //%9 + .arg(getAngle(),0,'f',15) //%10 + .arg(solid) //%11 + .arg(strAxisLink) //%12 + .arg(symmetric) //13 + ; + 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(); + activeDoc->recompute(); + } catch (Base::Exception &err) { + QMessageBox::critical(this, windowTitle(), + tr("Creating Revolve failed.\n\n%1").arg(QString::fromUtf8(err.what()))); + return; + } catch (...){ + QMessageBox::critical(this, windowTitle(), + tr("Creating Revolve failed.\n\n%1").arg(QString::fromUtf8("Unknown error"))); + return; } - activeDoc->commitTransaction(); - activeDoc->recompute(); QDialog::accept(); } @@ -231,15 +411,71 @@ void DlgRevolution::on_selectLine_clicked() if (!filter) { filter = new EdgeSelection(); Gui::Selection().addSelectionGate(filter); + ui->selectLine->setText(tr("Selecting... (line or arc)")); + } else { + Gui::Selection().rmvSelectionGate(); + filter = nullptr; + ui->selectLine->setText(tr("Select reference")); + } +} + +void DlgRevolution::on_btnX_clicked() +{ + setDirection(Base::Vector3d(1,0,0)); + if (!ui->xDir->isEnabled()) + ui->txtAxisLink->clear(); +} + +void DlgRevolution::on_btnY_clicked() +{ + setDirection(Base::Vector3d(0,1,0)); + if (!ui->xDir->isEnabled()) + ui->txtAxisLink->clear(); +} + +void DlgRevolution::on_btnZ_clicked() +{ + setDirection(Base::Vector3d(0,0,1)); + if (!ui->xDir->isEnabled()) + ui->txtAxisLink->clear(); +} + +void DlgRevolution::on_txtAxisLink_textChanged(QString) +{ + bool en = true; + try{ + Base::Vector3d pos, dir; + double angle_edge = 1e100; + App::PropertyLinkSub lnk; this->getAxisLink(lnk); + bool fetched = Part::Revolution::fetchAxisLink(lnk, pos, dir, angle_edge); + if (fetched){ + this->setDirection(dir); + this->setPosition(pos); + if (angle_edge != 1e100){ + ui->angle->setValue(0.0); + } else if (fabs(ui->angle->value().getValue()) < 1e-12) { + ui->angle->setValue(360.0); + } + en = false; + } + } catch (Base::Exception &err){ + + } catch (...){ + } + ui->xDir->setEnabled(en); + ui->yDir->setEnabled(en); + ui->zDir->setEnabled(en); + ui->xPos->setEnabled(en); + ui->yPos->setEnabled(en); + ui->zPos->setEnabled(en); } void DlgRevolution::onSelectionChanged(const Gui::SelectionChanges& msg) { if (msg.Type == Gui::SelectionChanges::AddSelection) { if (filter && filter->canSelect) { - ui->setPosition (Base::convertTo(filter->loc)); - ui->setDirection(Base::convertTo(filter->dir)); + this->setAxisLink(msg.pObjectName, msg.pSubName); } } } diff --git a/src/Mod/Part/Gui/DlgRevolution.h b/src/Mod/Part/Gui/DlgRevolution.h index f88b35210cca..4ae1958f88fa 100644 --- a/src/Mod/Part/Gui/DlgRevolution.h +++ b/src/Mod/Part/Gui/DlgRevolution.h @@ -31,7 +31,7 @@ namespace PartGui { class Ui_DlgRevolution; -class DlgRevolution : public Gui::LocationDialog, public Gui::SelectionObserver +class DlgRevolution : public QDialog, public Gui::SelectionObserver { Q_OBJECT @@ -41,21 +41,34 @@ class DlgRevolution : public Gui::LocationDialog, public Gui::SelectionObserver void accept(); Base::Vector3d getDirection() const; + Base::Vector3d getPosition() const; + void getAxisLink(App::PropertyLinkSub &lnk) const; + double getAngle() const; + + void setDirection(Base::Vector3d dir); + void setPosition(Base::Vector3d dir); + void setAxisLink(const App::PropertyLinkSub &lnk); + void setAxisLink(const char* objname, const char* subname); + + bool validate(); protected: void changeEvent(QEvent *e); private Q_SLOTS: void on_selectLine_clicked(); + void on_btnX_clicked(); + void on_btnY_clicked(); + void on_btnZ_clicked(); + void on_txtAxisLink_textChanged(QString); private: void findShapes(); - void directionActivated(int); void onSelectionChanged(const Gui::SelectionChanges& msg); private: - typedef Gui::LocationInterfaceComp Ui_RevolutionComp; - Ui_RevolutionComp* ui; + //typedef Gui::LocationInterfaceComp Ui_RevolutionComp; + Ui_DlgRevolution* ui; class EdgeSelection; EdgeSelection* filter; }; diff --git a/src/Mod/Part/Gui/DlgRevolution.ui b/src/Mod/Part/Gui/DlgRevolution.ui index e859df4ce29f..8f056f8ef25a 100644 --- a/src/Mod/Part/Gui/DlgRevolution.ui +++ b/src/Mod/Part/Gui/DlgRevolution.ui @@ -6,55 +6,83 @@ 0 0 - 307 - 266 + 320 + 599 + + + 0 + 0 + + Revolve - + + 9 + + + 9 + + + 9 + + 9 6 + + + + If checked, revolving wires will produce solids. If not, revolving a wire yeilds a shell. + + + Create Solid + + + - - - 0 + + + QAbstractItemView::ExtendedSelection + + + 20 + + + false - + + + Shape + + + + + + + 6 - - - - Y: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - X: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - mm - - - + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + @@ -65,90 +93,220 @@ - - - - mm - - - - - - - - - - Z: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Axis: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - mm - - - - + deg - + -360.000000000000000 - + 360.000000000000000 - + 360.000000000000000 - - - - QAbstractItemView::ExtendedSelection + + + + + 0 + 0 + - - 20 + + Revolution axis - - false - - - - Shape - - + + + + + + + Center X: + + + + + + + + 0 + 0 + + + + mm + + + + + + + Center Y: + + + + + + + mm + + + + + + + Center Z: + + + + + + + mm + + + + + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + Click to set this as axis + + + Dir. X: + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + + + + + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + Click to set this as axis + + + Dir. Y: + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + Dir. Z: + + + + + + + + + Select reference + + + + + + + - - - - Select line in 3D view + + + + If checked, revolution will extend forwards and backwards by half the angle. - - - - - Create Solid + Symmetric angle @@ -163,11 +321,12 @@ treeWidget - angle - xPos - yPos - zPos - direction + btnX + btnY + btnZ + selectLine + txtAxisLink + checkSolid