Download src/Mod/Part/Gui/DlgExtrusion.cpp from AbdulElahGwaith/FreeCAD: direct link, hf CLI and curl.
- Browser
- Download file 29.9 kB
-
https://huggingface.co/AbdulElahGwaith/FreeCAD/resolve/main/src/Mod/Part/Gui/DlgExtrusion.cpp
- Command line
-
hf download hf://AbdulElahGwaith/FreeCAD/src/Mod/Part/Gui/DlgExtrusion.cpp
-
curl -L -o DlgExtrusion.cpp https://huggingface.co/AbdulElahGwaith/FreeCAD/resolve/main/src/Mod/Part/Gui/DlgExtrusion.cpp
29.9 kB
| // SPDX-License-Identifier: LGPL-2.1-or-later | |
| /*************************************************************************** | |
| * Copyright (c) 2008 Werner Mayer <wmayer[at]users.sourceforge.net> * | |
| * * | |
| * This file is part of the FreeCAD CAx development system. * | |
| * * | |
| * This library is free software; you can redistribute it and/or * | |
| * modify it under the terms of the GNU Library General Public * | |
| * License as published by the Free Software Foundation; either * | |
| * version 2 of the License, or (at your option) any later version. * | |
| * * | |
| * This library is distributed in the hope that it will be useful, * | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of * | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | |
| * GNU Library General Public License for more details. * | |
| * * | |
| * You should have received a copy of the GNU Library General Public * | |
| * License along with this library; see the file COPYING.LIB. If not, * | |
| * write to the Free Software Foundation, Inc., 59 Temple Place, * | |
| * Suite 330, Boston, MA 02111-1307, USA * | |
| * * | |
| ***************************************************************************/ | |
| FC_LOG_LEVEL_INIT("Part", true, true) | |
| using namespace PartGui; | |
| class DlgExtrusion::EdgeSelection: public Gui::SelectionFilterGate | |
| { | |
| public: | |
| bool canSelect; | |
| EdgeSelection() | |
| : Gui::SelectionFilterGate(nullPointer()) | |
| { | |
| canSelect = false; | |
| } | |
| bool allow(App::Document* /*pDoc*/, App::DocumentObject* pObj, const char* sSubName) override | |
| { | |
| this->canSelect = false; | |
| if (Base::Tools::isNullOrEmpty(sSubName)) { | |
| return false; | |
| } | |
| std::string element(sSubName); | |
| if (element.substr(0, 4) != "Edge") { | |
| return false; | |
| } | |
| Part::TopoShape part = Part::Feature::getTopoShape( | |
| pObj, | |
| Part::ShapeOption::ResolveLink | Part::ShapeOption::Transform | |
| ); | |
| if (part.isNull()) { | |
| return false; | |
| } | |
| try { | |
| TopoDS_Shape sub = Part::Feature::getTopoShape( | |
| pObj, | |
| Part::ShapeOption::NeedSubElement | Part::ShapeOption::ResolveLink | |
| | Part::ShapeOption::Transform, | |
| sSubName | |
| ) | |
| .getShape(); | |
| 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) | |
| , filter(nullptr) | |
| { | |
| ui->setupUi(this); | |
| setupConnections(); | |
| ui->statusLabel->clear(); | |
| ui->dirX->setDecimals(Base::UnitsApi::getDecimals()); | |
| ui->dirY->setDecimals(Base::UnitsApi::getDecimals()); | |
| ui->dirZ->setDecimals(Base::UnitsApi::getDecimals()); | |
| 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())); | |
| sel.applyFrom(Gui::Selection().getObjectsOfType(App::Link::getClassTypeId())); | |
| sel.applyFrom(Gui::Selection().getObjectsOfType(App::Part::getClassTypeId())); | |
| this->onDirModeChanged(); | |
| 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(); | |
| } | |
| /* | |
| * Destroys the object and frees any allocated resources | |
| */ | |
| DlgExtrusion::~DlgExtrusion() | |
| { | |
| if (filter) { | |
| Gui::Selection().rmvSelectionGate(); | |
| filter = nullptr; | |
| } | |
| // no need to delete child widgets, Qt does it all for us | |
| } | |
| void DlgExtrusion::setupConnections() | |
| { | |
| // clang-format off | |
| connect(ui->rbDirModeCustom, &QRadioButton::toggled, | |
| this, &DlgExtrusion::onDirModeCustomToggled); | |
| connect(ui->rbDirModeEdge, &QRadioButton::toggled, | |
| this, &DlgExtrusion::onDirModeEdgeToggled); | |
| connect(ui->rbDirModeNormal, &QRadioButton::toggled, | |
| this, &DlgExtrusion::onDirModeNormalToggled); | |
| connect(ui->btnSelectEdge, &QPushButton::clicked, | |
| this, &DlgExtrusion::onSelectEdgeClicked); | |
| connect(ui->btnX, &QPushButton::clicked, | |
| this, &DlgExtrusion::onButtnoXClicked); | |
| connect(ui->btnY, &QPushButton::clicked, | |
| this, &DlgExtrusion::onButtonYClicked); | |
| connect(ui->btnZ, &QPushButton::clicked, | |
| this, &DlgExtrusion::onButtonZClicked); | |
| connect(ui->chkSymmetric, &QCheckBox::toggled, | |
| this, &DlgExtrusion::onCheckSymmetricToggled); | |
| connect(ui->txtLink, &QLineEdit::textChanged, | |
| this, &DlgExtrusion::onTextLinkTextChanged); | |
| // clang-format on | |
| } | |
| void DlgExtrusion::changeEvent(QEvent* e) | |
| { | |
| if (e->type() == QEvent::LanguageChange) { | |
| ui->retranslateUi(this); | |
| } | |
| QDialog::changeEvent(e); | |
| } | |
| void DlgExtrusion::keyPressEvent(QKeyEvent* ke) | |
| { | |
| // The extrusion dialog is embedded into a task panel | |
| // which is a parent widget and will handle the event | |
| ke->ignore(); | |
| } | |
| void DlgExtrusion::onDirModeCustomToggled(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->onDirModeChanged(); | |
| } | |
| } | |
| void DlgExtrusion::onDirModeEdgeToggled(bool on) | |
| { | |
| if (on) { | |
| this->onDirModeChanged(); | |
| } | |
| } | |
| void DlgExtrusion::onDirModeNormalToggled(bool on) | |
| { | |
| if (on) { | |
| this->onDirModeChanged(); | |
| } | |
| } | |
| void DlgExtrusion::onSelectEdgeClicked() | |
| { | |
| if (!filter) { | |
| filter = new EdgeSelection(); | |
| Gui::Selection().addSelectionGate(filter); | |
| ui->btnSelectEdge->setText(tr("Selecting…")); | |
| // visibility automation | |
| try { | |
| QString code = QStringLiteral( | |
| "import Show\n" | |
| "tv = Show.TempoVis(App.ActiveDocument, tag= 'PartGui::DlgExtrusion')\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(QStringLiteral("App.ActiveDocument.")); | |
| features_to_hide.append(QString::fromLatin1(obj->getNameInDocument())); | |
| features_to_hide.append(QStringLiteral(", \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::onButtnoXClicked() | |
| { | |
| 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::onButtonYClicked() | |
| { | |
| 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::onButtonZClicked() | |
| { | |
| 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::onCheckSymmetricToggled(bool on) | |
| { | |
| ui->spinLenRev->setEnabled(!on); | |
| } | |
| void DlgExtrusion::onTextLinkTextChanged(QString) | |
| { | |
| this->fetchDir(); | |
| } | |
| void DlgExtrusion::onDirModeChanged() | |
| { | |
| 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.empty()) { | |
| throw Base::ValueError("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(); | |
| Part::TopoShape shape = Part::Feature::getTopoShape( | |
| dobj, | |
| Part::ShapeOption::ResolveLink | Part::ShapeOption::Transform | |
| ); | |
| if (shape.isNull()) { | |
| return; | |
| } | |
| TopoDS_Shape sh = shape.getShape(); | |
| 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(); | |
| if (!activeDoc) { | |
| return; | |
| } | |
| Gui::Document* activeGui = Gui::Application::Instance->getDocument(activeDoc); | |
| this->document = activeDoc->getName(); | |
| this->label = activeDoc->Label.getValue(); | |
| std::vector<App::DocumentObject*> objs = activeDoc->getObjectsOfType<App::DocumentObject>(); | |
| for (auto obj : objs) { | |
| Part::TopoShape topoShape = Part::Feature::getTopoShape( | |
| obj, | |
| Part::ShapeOption::ResolveLink | Part::ShapeOption::Transform | |
| ); | |
| if (topoShape.isNull()) { | |
| continue; | |
| } | |
| TopoDS_Shape shape = topoShape.getShape(); | |
| if (shape.IsNull()) { | |
| continue; | |
| } | |
| if (canExtrude(shape)) { | |
| QTreeWidgetItem* item = new QTreeWidgetItem(ui->treeWidget); | |
| item->setText(0, QString::fromUtf8(obj->Label.getValue())); | |
| item->setData(0, Qt::UserRole, QString::fromLatin1(obj->getNameInDocument())); | |
| Gui::ViewProvider* vp = activeGui->getViewProvider(obj); | |
| if (vp) { | |
| item->setIcon(0, vp->getIcon()); | |
| } | |
| } | |
| } | |
| } | |
| bool DlgExtrusion::canExtrude(const TopoDS_Shape& shape) const | |
| { | |
| if (shape.IsNull()) { | |
| return false; | |
| } | |
| TopAbs_ShapeEnum type = shape.ShapeType(); | |
| if (type == TopAbs_VERTEX || type == TopAbs_EDGE || type == TopAbs_WIRE || type == TopAbs_FACE | |
| || type == TopAbs_SHELL) { | |
| return true; | |
| } | |
| if (type == TopAbs_COMPOUND) { | |
| TopExp_Explorer xp; | |
| xp.Init(shape, TopAbs_SOLID); | |
| while (xp.More()) { | |
| return false; | |
| } | |
| xp.Init(shape, TopAbs_COMPSOLID); | |
| while (xp.More()) { | |
| return false; | |
| } | |
| return true; | |
| } | |
| return false; | |
| } | |
| void DlgExtrusion::accept() | |
| { | |
| try { | |
| apply(); | |
| QDialog::accept(); | |
| } | |
| catch (Base::AbortException&) { | |
| }; | |
| } | |
| void DlgExtrusion::apply() | |
| { | |
| try { | |
| if (!validate()) { | |
| throw Base::AbortException(); | |
| } | |
| if (filter) { // if still selecting edge - stop. This is important for visibility automation. | |
| this->onSelectEdgeClicked(); | |
| } | |
| 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"); | |
| Base::Reference<ParameterGrp> hGrp = App::GetApplication() | |
| .GetUserParameter() | |
| .GetGroup("BaseApp") | |
| ->GetGroup("Preferences") | |
| ->GetGroup("Mod/Part"); | |
| bool addBaseName = hGrp->GetBool("AddBaseObjectName", false); | |
| std::vector<App::DocumentObject*> objects = this->getShapesToExtrude(); | |
| for (App::DocumentObject* sourceObj : objects) { | |
| assert(sourceObj); | |
| if (Part::Feature::getTopoShape( | |
| sourceObj, | |
| Part::ShapeOption::ResolveLink | Part::ShapeOption::Transform | |
| ) | |
| .isNull()) { | |
| FC_ERR( | |
| "Object " << sourceObj->getFullName() << " is not a Part object because it has no OCC shape. Extrusion is not possible." | |
| ); | |
| continue; | |
| } | |
| std::string name; | |
| name = sourceObj->getDocument()->getUniqueObjectName("Extrude").c_str(); | |
| if (addBaseName) { | |
| // FIXME: implement | |
| // QString baseName = QStringLiteral("Extrude_%1").arg(sourceObjectName); | |
| // label = QStringLiteral("%1_Extrude").arg((*it)->text(0)); | |
| } | |
| FCMD_OBJ_DOC_CMD(sourceObj, "addObject('Part::Extrusion','" << name << "')"); | |
| auto newObj = sourceObj->getDocument()->getObject(name.c_str()); | |
| this->writeParametersToFeature(*newObj, sourceObj); | |
| if (!sourceObj->isDerivedFrom<Part::Part2DObject>()) { | |
| Gui::Command::copyVisual(newObj, "ShapeAppearance", sourceObj); | |
| Gui::Command::copyVisual(newObj, "LineColor", sourceObj); | |
| Gui::Command::copyVisual(newObj, "PointColor", sourceObj); | |
| } | |
| FCMD_OBJ_HIDE(sourceObj); | |
| } | |
| activeDoc->commitTransaction(); | |
| Gui::Command::updateActive(); | |
| } | |
| catch (Base::AbortException&) { | |
| throw; | |
| } | |
| catch (Base::Exception& err) { | |
| QMessageBox::critical( | |
| this, | |
| windowTitle(), | |
| tr("Creating extrusion failed.\n%1").arg(QCoreApplication::translate("Exception", err.what())) | |
| ); | |
| return; | |
| } | |
| catch (...) { | |
| QMessageBox::critical( | |
| this, | |
| windowTitle(), | |
| tr("Creating Extrusion failed.\n%1").arg(QStringLiteral("Unknown error")) | |
| ); | |
| return; | |
| } | |
| } | |
| void DlgExtrusion::reject() | |
| { | |
| if (filter) { // if still selecting edge - stop. | |
| this->onSelectEdgeClicked(); | |
| } | |
| QDialog::reject(); | |
| } | |
| Base::Vector3d DlgExtrusion::getDir() const | |
| { | |
| 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->onDirModeChanged(); | |
| } | |
| 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.emplace_back(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 + QStringLiteral(":") + 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::RuntimeError("Document lost"); | |
| } | |
| std::vector<App::DocumentObject*> objects; | |
| for (auto item : items) { | |
| App::DocumentObject* obj = doc->getObject(item->data(0, Qt::UserRole).toString().toLatin1()); | |
| if (!obj) { | |
| throw Base::RuntimeError("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.")); | |
| 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 = QCoreApplication::translate("Exception", err.what()); | |
| } | |
| catch (Standard_Failure& err) { | |
| errmsg = QString::fromLocal8Bit(err.GetMessageString()); | |
| } | |
| catch (...) { | |
| errmsg = tr("Unknown error"); | |
| } | |
| if (this->getDirMode() == Part::Extrusion::dmEdge && !hasValidAxisLink) { | |
| if (errmsg.length() > 0) { | |
| QMessageBox::critical( | |
| this, | |
| windowTitle(), | |
| tr("Extrusion direction 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 = QCoreApplication::translate("Exception", err.what()); | |
| } | |
| catch (Standard_Failure& err) { | |
| errmsg = QString::fromLocal8Bit(err.GetMessageString()); | |
| } | |
| catch (...) { | |
| errmsg = QStringLiteral("Unknown error"); | |
| } | |
| if (errmsg.length() > 0) { | |
| QMessageBox::critical( | |
| this, | |
| windowTitle(), | |
| tr("Cannot determine normal vector of shape to be extruded. 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 vector 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()) { | |
| 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() | |
| { | |
| widget = new DlgExtrusion(); | |
| addTaskBox(Gui::BitmapFactory().pixmap("Part_Extrude"), widget); | |
| } | |
| bool TaskExtrusion::accept() | |
| { | |
| widget->accept(); | |
| return (widget->result() == QDialog::Accepted); | |
| } | |
| bool TaskExtrusion::reject() | |
| { | |
| widget->reject(); | |
| return true; | |
| } | |
| void TaskExtrusion::clicked(int id) | |
| { | |
| if (id == QDialogButtonBox::Apply) { | |
| try { | |
| widget->apply(); | |
| } | |
| catch (Base::AbortException&) { | |
| }; | |
| } | |
| } | |