diff --git a/src/App/Property.cpp b/src/App/Property.cpp index 35590a20a66e..a53e4c95c0c2 100644 --- a/src/App/Property.cpp +++ b/src/App/Property.cpp @@ -32,6 +32,7 @@ #include "ObjectIdentifier.h" #include "PropertyContainer.h" #include +#include "Application.h" using namespace App; @@ -110,6 +111,14 @@ void Property::touch() StatusBits.set(0); } +void Property::setReadOnly(bool readOnly) +{ + unsigned long status = this->getStatus(); + this->setStatus(App::Property::ReadOnly, readOnly); + if (status != this->getStatus()) + App::GetApplication().signalChangePropertyEditor(*this); +} + void Property::hasSetValue(void) { if (father) diff --git a/src/App/Property.h b/src/App/Property.h index 79a1e21f7da0..43a1bbe912b6 100644 --- a/src/App/Property.h +++ b/src/App/Property.h @@ -27,11 +27,11 @@ // Std. configurations #include -#ifndef BOOST_105400 -#include -#else -#include -#endif +#ifndef BOOST_105400 +#include +#else +#include +#endif #include #include @@ -138,6 +138,11 @@ class AppExport Property : public Base::Persistence inline void setStatus(Status pos, bool on) { StatusBits.set(static_cast(pos), on); } + ///Sets property editable/grayed out in property editor + void setReadOnly(bool readOnly); + inline bool isReadOnly() const { + return testStatus(App::Property::ReadOnly); + } //@} /// Returns a new copy of the property (mainly for Undo/Redo and transactions) @@ -248,4 +253,4 @@ template class AtomicPropertyChangeInterface { } // namespace App -#endif // APP_PROPERTY_H +#endif // APP_PROPERTY_H diff --git a/src/Mod/Part/App/AttachableObject.cpp b/src/Mod/Part/App/AttachableObject.cpp index 860a19f9406f..972915507a45 100644 --- a/src/Mod/Part/App/AttachableObject.cpp +++ b/src/Mod/Part/App/AttachableObject.cpp @@ -140,16 +140,6 @@ App::DocumentObjectExecReturn *AttachableObject::execute() return Part::Feature::execute(); } -namespace Attacher { - void setReadonlyness(App::Property &prop, bool on) - { - unsigned long status = prop.getStatus(); - prop.setStatus(App::Property::ReadOnly, on); - if (status != prop.getStatus()) - App::GetApplication().signalChangePropertyEditor(prop); - } -} - void AttachableObject::onChanged(const App::Property* prop) { if(! this->isRestoring()){ @@ -172,8 +162,8 @@ void AttachableObject::onChanged(const App::Property* prop) } eMapMode mmode = eMapMode(this->MapMode.getValue()); - setReadonlyness(this->superPlacement, !bAttached); - setReadonlyness(this->Placement, bAttached && mmode != mmTranslate); //for mmTranslate, orientation should remain editable even when attached. + this->superPlacement.setReadOnly(!bAttached); + this->Placement.setReadOnly(bAttached && mmode != mmTranslate); //for mmTranslate, orientation should remain editable even when attached. } } diff --git a/src/Mod/Part/App/FeatureRevolution.cpp b/src/Mod/Part/App/FeatureRevolution.cpp index cd2250d17da6..66408b10dc8e 100644 --- a/src/Mod/Part/App/FeatureRevolution.cpp +++ b/src/Mod/Part/App/FeatureRevolution.cpp @@ -24,11 +24,17 @@ #include "PreCompiled.h" #ifndef _PreComp_ # include +# include +# include +# include +# include #endif #include "FeatureRevolution.h" #include +#include +#include using namespace Part; @@ -38,13 +44,14 @@ PROPERTY_SOURCE(Part::Revolution, Part::Feature) Revolution::Revolution() { - //*** why not ADD_PROPERTY_TYPE?? - ADD_PROPERTY(Source,(0)); - ADD_PROPERTY(Base,(Base::Vector3d(0.0,0.0,0.0))); - ADD_PROPERTY(Axis,(Base::Vector3d(0.0,0.0,1.0))); - ADD_PROPERTY(Angle,(360.0)); - ADD_PROPERTY_TYPE(Solid,(false),"Base",App::Prop_None,"Make revolution a solid if possible"); + ADD_PROPERTY_TYPE(Source,(0), "Revolve", App::Prop_None, "Shape to revolve"); + ADD_PROPERTY_TYPE(Base,(Base::Vector3d(0.0,0.0,0.0)), "Revolve", App::Prop_None, "Base point of revolution axis"); + ADD_PROPERTY_TYPE(Axis,(Base::Vector3d(0.0,0.0,1.0)), "Revolve", App::Prop_None, "Direction of revolution axis"); + ADD_PROPERTY_TYPE(AxisLink,(0),"Revolve",App::Prop_None,"Link to edge to use as revolution axis."); + ADD_PROPERTY_TYPE(Angle,(360.0), "Revolve", App::Prop_None, "Angle span of revolution. If angle is zero, and an arc is used for axis link, angle span of arc will be used."); Angle.setConstraints(&angleRangeU); + ADD_PROPERTY_TYPE(Symmetric,(false),"Revolve",App::Prop_None,"Extend revolution symmetrically from the profile."); + ADD_PROPERTY_TYPE(Solid,(false),"Revolve",App::Prop_None,"Make revolution a solid if possible"); } short Revolution::mustExecute() const @@ -53,11 +60,67 @@ short Revolution::mustExecute() const Axis.isTouched() || Angle.isTouched() || Source.isTouched() || - Solid.isTouched()) + Solid.isTouched() || + AxisLink.isTouched() || + Symmetric.isTouched()) return 1; return 0; } +void Revolution::onChanged(const App::Property* prop) +{ + if(! this->isRestoring()){ + if(prop == &AxisLink){ + Base.setReadOnly(AxisLink.getValue() != nullptr); + Axis.setReadOnly(AxisLink.getValue() != nullptr); + } + } + Part::Feature::onChanged(prop); +} + +bool Revolution::fetchAxisLink(const App::PropertyLinkSub &axisLink, + Base::Vector3d& center, + Base::Vector3d& dir, + double& angle) +{ + if (!axisLink.getValue()) + return false; + + if (!axisLink.getValue()->isDerivedFrom(Part::Feature::getClassTypeId())) + throw Base::TypeError("AxisLink has no OCC shape"); + + Part::Feature* linked = static_cast(axisLink.getValue()); + + TopoDS_Shape axEdge; + if (axisLink.getSubValues().size() > 0 && axisLink.getSubValues()[0].length() > 0){ + axEdge = linked->Shape.getShape().getSubShape(axisLink.getSubValues()[0].c_str()); + } else { + axEdge = linked->Shape.getValue(); + } + + if (axEdge.IsNull()) + throw Base::ValueError("AxisLink shape is null"); + if (axEdge.ShapeType() != TopAbs_EDGE) + throw Base::TypeError("AxisLink shape is not an edge"); + + BRepAdaptor_Curve crv(TopoDS::Edge(axEdge)); + gp_Pnt base; + gp_Dir occdir; + if (crv.GetType() == GeomAbs_Line){ + base = crv.Value(crv.FirstParameter()); + occdir = crv.Line().Direction(); + } else if (crv.GetType() == GeomAbs_Circle) { + base = crv.Circle().Axis().Location(); + occdir = crv.Circle().Axis().Direction(); + angle = crv.LastParameter() - crv.FirstParameter(); + } else { + throw Base::TypeError("AxisLink edge is neither line nor arc of circle."); + } + center.Set(base.X(), base.Y(),base.Z()); + dir.Set(occdir.X(), occdir.Y(), occdir.Z()); + return true; +} + App::DocumentObjectExecReturn *Revolution::execute(void) { App::DocumentObject* link = Source.getValue(); @@ -67,18 +130,40 @@ App::DocumentObjectExecReturn *Revolution::execute(void) return new App::DocumentObjectExecReturn("Linked object is not a Part object"); Part::Feature *base = static_cast(Source.getValue()); - Base::Vector3d b = Base.getValue(); - Base::Vector3d v = Axis.getValue(); - gp_Pnt pnt(b.x,b.y,b.z); - gp_Dir dir(v.x,v.y,v.z); - Standard_Boolean isSolid = Solid.getValue() ? Standard_True : Standard_False; - try { - // Now, let's get the TopoDS_Shape - //TopoDS_Shape revolve = base->Shape.getShape().revolve(gp_Ax1(pnt, dir), - // Angle.getValue()/180.0f*M_PI); - TopoDS_Shape revolve = base->Shape.getShape().revolve(gp_Ax1(pnt, dir), - Angle.getValue()/180.0f*M_PI,isSolid); + //read out axis link + double angle_edge = 0; + Base::Vector3d b = Base.getValue(); + Base::Vector3d v = Axis.getValue(); + bool linkFetched = this->fetchAxisLink(this->AxisLink, b, v, angle_edge); + if (linkFetched){ + this->Base.setValue(b); + this->Axis.setValue(v); + } + + gp_Pnt pnt(b.x,b.y,b.z); + gp_Dir dir(v.x,v.y,v.z); + gp_Ax1 revAx(pnt, dir); + + //read out revolution angle + double angle = Angle.getValue()/180.0f*M_PI; + if (fabs(angle) < Precision::Angular()) + angle = angle_edge; + + //apply "midplane" symmetry + TopoShape sourceShape = base->Shape.getShape(); + if (Symmetric.getValue()) { + //rotate source shape backwards by half angle, to make resulting revolution symmetric to the profile + gp_Trsf mov; + mov.SetRotation(revAx, angle * (-0.5)); + TopLoc_Location loc(mov); + sourceShape.setShape(sourceShape.getShape().Moved(loc)); + } + + //do it! + Standard_Boolean makeSolid = Solid.getValue() ? Standard_True : Standard_False; + TopoDS_Shape revolve = sourceShape.revolve(revAx, angle, makeSolid); + if (revolve.IsNull()) return new App::DocumentObjectExecReturn("Resulting shape is null"); this->Shape.setValue(revolve); diff --git a/src/Mod/Part/App/FeatureRevolution.h b/src/Mod/Part/App/FeatureRevolution.h index 545420c984e5..4fa6d60558dd 100644 --- a/src/Mod/Part/App/FeatureRevolution.h +++ b/src/Mod/Part/App/FeatureRevolution.h @@ -26,11 +26,12 @@ #include #include "PartFeature.h" +#include namespace Part { -class Revolution : public Part::Feature +class PartExport Revolution : public Part::Feature { PROPERTY_HEADER(Part::Revolution); @@ -40,7 +41,9 @@ class Revolution : public Part::Feature App::PropertyLink Source; App::PropertyVector Base; App::PropertyVector Axis; + App::PropertyLinkSub AxisLink; App::PropertyFloatConstraint Angle; + App::PropertyBool Symmetric; //like "Midplane" in PartDesign App::PropertyBool Solid; /** @name methods override feature */ @@ -48,12 +51,32 @@ class Revolution : public Part::Feature /// recalculate the feature App::DocumentObjectExecReturn *execute(void); short mustExecute() const; + + void onChanged(const App::Property* prop) override; + /// returns the type name of the view provider const char* getViewProviderName(void) const { return "PartGui::ViewProviderRevolution"; } //@} + /** + * @brief fetchAxisLink: read AxisLink to obtain the axis parameters and + * angle span. Note: this routine is re-used in Revolve dialog, hence it + * is static. + * @param axisLink (input): the link + * @param center (output): base point of axis + * @param dir (output): direction of axis + * @param angle (output): if edge is an arc of circle, this argument is + * used to return the angle span of the arc. + * @return true if link was fetched. false if link was empty. Throws if the + * link is wrong. + */ + static bool fetchAxisLink(const App::PropertyLinkSub& axisLink, + Base::Vector3d ¢er, + Base::Vector3d &dir, + double &angle); + private: static App::PropertyFloatConstraint::Constraints angleRangeU; }; 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