// SPDX-License-Identifier: LGPL-2.1-or-later /*************************************************************************** * Copyright (c) 2002 Jürgen Riegel * * * * 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 * * * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include "DlgPartCylinderImp.h" #include "ShapeFromMesh.h" #include //=========================================================================== // Part_SimpleCylinder //=========================================================================== DEF_STD_CMD_A(CmdPartSimpleCylinder) CmdPartSimpleCylinder::CmdPartSimpleCylinder() : Command("Part_SimpleCylinder") { sAppModule = "Part"; sGroup = QT_TR_NOOP("Part"); sMenuText = QT_TR_NOOP("Cylinder"); sToolTipText = QT_TR_NOOP("Creates a solid cylinder"); sWhatsThis = "Part_SimpleCylinder"; sStatusTip = sToolTipText; sPixmap = "Part_Cylinder_Parametric"; } void CmdPartSimpleCylinder::activated(int iMsg) { Q_UNUSED(iMsg); PartGui::DlgPartCylinderImp dlg(Gui::getMainWindow()); if (dlg.exec() == QDialog::Accepted) { Base::Vector3d dir = dlg.getDirection(); Base::Vector3d pos = dlg.getPosition(); openCommand(QT_TRANSLATE_NOOP("Command", "Create Cylinder")); doCommand(Doc, "from FreeCAD import Base"); doCommand(Doc, "import Part"); doCommand( Doc, "App.ActiveDocument.addObject(\"Part::Feature\",\"Cylinder\")" ".Shape=Part.makeCylinder(%f,%f," "Base.Vector(%f,%f,%f)," "Base.Vector(%f,%f,%f))", dlg.getRadius(), dlg.getLength(), pos.x, pos.y, pos.z, dir.x, dir.y, dir.z ); commitCommand(); updateActive(); doCommand(Gui, "Gui.SendMsgToActiveView(\"ViewFit\")"); } } bool CmdPartSimpleCylinder::isActive() { if (getActiveGuiDocument()) { return true; } else { return false; } } //=========================================================================== // Part_ShapeFromMesh //=========================================================================== DEF_STD_CMD_A(CmdPartShapeFromMesh) CmdPartShapeFromMesh::CmdPartShapeFromMesh() : Command("Part_ShapeFromMesh") { sAppModule = "Part"; sGroup = QT_TR_NOOP("Part"); sMenuText = QT_TR_NOOP("Shape From Mesh"); sToolTipText = QT_TR_NOOP("Creates a shape from the selected mesh"); sWhatsThis = "Part_ShapeFromMesh"; sStatusTip = sToolTipText; sPixmap = "Part_Shape_from_Mesh"; } void CmdPartShapeFromMesh::activated(int iMsg) { Q_UNUSED(iMsg); PartGui::ShapeFromMesh dlg(Gui::getMainWindow()); dlg.exec(); } bool CmdPartShapeFromMesh::isActive() { return Gui::Selection().countObjectsOfType("Mesh::Feature") > 0; } //=========================================================================== // Part_PointsFromMesh //=========================================================================== DEF_STD_CMD_A(CmdPartPointsFromMesh) CmdPartPointsFromMesh::CmdPartPointsFromMesh() : Command("Part_PointsFromMesh") { sAppModule = "Part"; sGroup = QT_TR_NOOP("Part"); sMenuText = QT_TR_NOOP("Points From Shape"); sToolTipText = QT_TR_NOOP("Creates distributed points from the selected shape"); sWhatsThis = "Part_PointsFromMesh"; sStatusTip = sToolTipText; sPixmap = "Part_PointsFromMesh"; } void CmdPartPointsFromMesh::activated(int iMsg) { Q_UNUSED(iMsg); auto getDefaultDistance = [](Part::Feature* geometry) { auto bbox = geometry->Shape.getBoundingBox(); int steps {20}; return bbox.CalcDiagonalLength() / steps; }; Base::Type geoid = Base::Type::fromName("App::GeoFeature"); std::vector geoms; geoms = Gui::Selection().getObjectsOfType(geoid); double distance {1.0}; auto found = std::find_if(geoms.begin(), geoms.end(), [](App::DocumentObject* obj) { return freecad_cast(obj); }); if (found != geoms.end()) { double defaultDistance = getDefaultDistance(freecad_cast(*found)); double STD_OCC_TOLERANCE = 1e-6; int decimals = Base::UnitsApi::getDecimals(); double tolerance_from_decimals = pow(10., -decimals); double minimal_tolerance = tolerance_from_decimals < STD_OCC_TOLERANCE ? STD_OCC_TOLERANCE : tolerance_from_decimals; bool ok; distance = QInputDialog::getDouble( Gui::getMainWindow(), QObject::tr("Distance in Parameter Space"), QObject::tr("Enter distance:"), defaultDistance, minimal_tolerance, 10.0 * defaultDistance, decimals, &ok, Qt::MSWindowsFixedSizeDialogHint ); if (!ok) { return; } } Gui::WaitCursor wc; openCommand(QT_TRANSLATE_NOOP("Command", "Points from geometry")); Base::PyGILStateLocker lock; try { PyObject* module = PyImport_ImportModule("BasicShapes.Utils"); if (!module) { throw Py::Exception(); } Py::Module utils(module, true); for (auto it : geoms) { Py::Tuple args(2); args.setItem(0, Py::asObject(it->getPyObject())); args.setItem(1, Py::Float(distance)); utils.callMemberFunction("showCompoundFromPoints", args); } } catch (Py::Exception&) { Base::PyException e; e.reportException(); } commitCommand(); } bool CmdPartPointsFromMesh::isActive() { return Gui::Selection().countObjectsOfType() > 0; } //=========================================================================== // Part_SimpleCopy //=========================================================================== DEF_STD_CMD_A(CmdPartSimpleCopy) CmdPartSimpleCopy::CmdPartSimpleCopy() : Command("Part_SimpleCopy") { sAppModule = "Part"; sGroup = QT_TR_NOOP("Part"); sMenuText = QT_TR_NOOP("Simple Copy"); sToolTipText = QT_TR_NOOP("Creates a simple non-parametric copy of the selected shapes"); sWhatsThis = "Part_SimpleCopy"; sStatusTip = sToolTipText; sPixmap = "Part_3D_object"; } static void _copyShape(const char* cmdName, bool resolve, bool needElement = false, bool refine = false) { Gui::WaitCursor wc; Gui::Command::openCommand(cmdName); for (auto& sel : Gui::Selection().getSelectionEx( "*", App::DocumentObject::getClassTypeId(), resolve ? Gui::ResolveMode::OldStyleElement : Gui::ResolveMode::NoResolve )) { std::map subMap; auto obj = sel.getObject(); if (!obj) { continue; } if (resolve || !sel.hasSubNames()) { subMap.emplace("", obj); } else { for (const auto& sub : sel.getSubNames()) { const char* element = nullptr; auto sobj = obj->resolve(sub.c_str(), nullptr, nullptr, &element); if (!sobj) { continue; } if (!needElement && element) { subMap.emplace(sub.substr(0, element - sub.c_str()), sobj); } else { subMap.emplace(sub, sobj); } } if (subMap.empty()) { continue; } } auto parentName = Gui::Command::getObjectCmd(obj); for (auto& v : subMap) { Gui::Command::doCommand( Gui::Command::Doc, "__shape = Part.getShape(%s,'%s',needSubElement=%s,refine=%s)%s\n" "App.ActiveDocument.addObject('Part::Feature','%s').Shape=__shape\n" "App.ActiveDocument.ActiveObject.Label=%s.Label\n", parentName.c_str(), v.first.c_str(), needElement ? "True" : "False", refine ? "True" : "False", needElement ? ".copy()" : "", v.second->getNameInDocument(), Gui::Command::getObjectCmd(v.second).c_str() ); auto newObj = App::GetApplication().getActiveDocument()->getActiveObject(); Gui::Command::copyVisual(newObj, "ShapeAppearance", v.second); Gui::Command::copyVisual(newObj, "LineColor", v.second); Gui::Command::copyVisual(newObj, "PointColor", v.second); } } Gui::Command::commitCommand(); Gui::Command::updateActive(); } void CmdPartSimpleCopy::activated(int iMsg) { Q_UNUSED(iMsg); _copyShape("Simple copy", true); } bool CmdPartSimpleCopy::isActive() { return Gui::Selection().hasSelection(); } //=========================================================================== // Part_TransformedCopy //=========================================================================== DEF_STD_CMD_A(CmdPartTransformedCopy) CmdPartTransformedCopy::CmdPartTransformedCopy() : Command("Part_TransformedCopy") { sAppModule = "Part"; sGroup = QT_TR_NOOP("Part"); sMenuText = QT_TR_NOOP("Transformed Copy"); sToolTipText = QT_TR_NOOP( "Creates a non-parametric copy with transformed placement of the selected shapes" ); sWhatsThis = "Part_TransformCopy"; sStatusTip = sToolTipText; sPixmap = "Part_Transformed_Copy.svg"; } void CmdPartTransformedCopy::activated(int iMsg) { Q_UNUSED(iMsg); _copyShape("Transformed copy", false); } bool CmdPartTransformedCopy::isActive() { return Gui::Selection().hasSelection(); } //=========================================================================== // Part_ElementCopy //=========================================================================== DEF_STD_CMD_A(CmdPartElementCopy) CmdPartElementCopy::CmdPartElementCopy() : Command("Part_ElementCopy") { sAppModule = "Part"; sGroup = QT_TR_NOOP("Part"); sMenuText = QT_TR_NOOP("Shape Element Copy"); sToolTipText = QT_TR_NOOP("Creates a non-parametric copy of the selected shape element"); sWhatsThis = "Part_ElementCopy"; sStatusTip = sToolTipText; sPixmap = "Part_Element_Copy.svg"; } void CmdPartElementCopy::activated(int iMsg) { Q_UNUSED(iMsg); _copyShape("Element copy", false, true); } bool CmdPartElementCopy::isActive() { return Gui::Selection().hasSelection(); } //=========================================================================== // Part_RefineShape //=========================================================================== DEF_STD_CMD_A(CmdPartRefineShape) CmdPartRefineShape::CmdPartRefineShape() : Command("Part_RefineShape") { sAppModule = "Part"; sGroup = QT_TR_NOOP("Part"); sMenuText = QT_TR_NOOP("Refine Shape"); sToolTipText = QT_TR_NOOP("Creates a refined copy of the selected shapes"); sWhatsThis = "Part_RefineShape"; sStatusTip = sToolTipText; sPixmap = "Part_Refine_Shape"; } void CmdPartRefineShape::activated(int iMsg) { Q_UNUSED(iMsg); ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath( "User parameter:BaseApp/Preferences/Mod/Part" ); bool parametric = hGrp->GetBool("ParametricRefine", true); if (parametric) { Gui::WaitCursor wc; Base::Type partid = Base::Type::fromName("Part::Feature"); std::vector objs = Gui::Selection().getObjectsOfType(partid); openCommand(QT_TRANSLATE_NOOP("Command", "Refine shape")); std::for_each(objs.begin(), objs.end(), [](App::DocumentObject* obj) { try { App::DocumentObjectT objT(obj); Gui::cmdAppDocumentArgs( obj->getDocument(), "addObject('Part::Refine','%s')", obj->getNameInDocument() ); Gui::cmdAppDocumentArgs( obj->getDocument(), "ActiveObject.Source = %s", objT.getObjectPython() ); Gui::cmdAppDocumentArgs( obj->getDocument(), "ActiveObject.Label = %s.Label", objT.getObjectPython() ); Gui::cmdAppObjectHide(obj); auto newObj = App::GetApplication().getActiveDocument()->getActiveObject(); Gui::copyVisualT( newObj->getNameInDocument(), "ShapeAppearance", obj->getNameInDocument() ); Gui::copyVisualT(newObj->getNameInDocument(), "LineColor", obj->getNameInDocument()); Gui::copyVisualT(newObj->getNameInDocument(), "PointColor", obj->getNameInDocument()); } catch (const Base::Exception& e) { Base::Console().warning("%s: %s\n", obj->Label.getValue(), e.what()); } }); commitCommand(); updateActive(); } else { _copyShape("Refined copy", true, false, true); } } bool CmdPartRefineShape::isActive() { return Gui::Selection().hasSelection(); } //=========================================================================== // Part_Defeaturing //=========================================================================== DEF_STD_CMD_A(CmdPartDefeaturing) CmdPartDefeaturing::CmdPartDefeaturing() : Command("Part_Defeaturing") { sAppModule = "Part"; sGroup = QT_TR_NOOP("Part"); sMenuText = QT_TR_NOOP("Defeaturing"); sToolTipText = QT_TR_NOOP("Removes the selected features from a shape"); sWhatsThis = "Part_Defeaturing"; sStatusTip = sToolTipText; sPixmap = "Part_Defeaturing"; } void CmdPartDefeaturing::activated(int iMsg) { Q_UNUSED(iMsg); Gui::WaitCursor wc; Base::Type partid = Base::Type::fromName("Part::Feature"); std::vector objs = Gui::Selection().getSelectionEx(nullptr, partid); openCommand(QT_TRANSLATE_NOOP("Command", "Defeaturing")); for (std::vector::iterator it = objs.begin(); it != objs.end(); ++it) { try { std::string shape; shape.append("sh=App."); shape.append(it->getDocName()); shape.append("."); shape.append(it->getFeatName()); shape.append(".Shape\n"); std::string faces; std::vector subnames = it->getSubNames(); for (const auto& subname : subnames) { faces.append("sh."); faces.append(subname); faces.append(","); } doCommand( Doc, "\nsh = App.getDocument('%s').%s.Shape\n" "nsh = sh.defeaturing([%s])\n" "if not sh.isPartner(nsh):\n" "\t\tdefeat = App.ActiveDocument.addObject('Part::Feature','Defeatured').Shape = " "nsh\n" "\t\tGui.ActiveDocument.%s.hide()\n" "else:\n" "\t\tFreeCAD.Console.PrintError('Defeaturing failed\\n')", it->getDocName(), it->getFeatName(), faces.c_str(), it->getFeatName() ); } catch (const Base::Exception& e) { Base::Console().warning("%s: %s\n", it->getFeatName(), e.what()); } } commitCommand(); updateActive(); } bool CmdPartDefeaturing::isActive() { Base::Type partid = Base::Type::fromName("Part::Feature"); std::vector objs = Gui::Selection().getSelectionEx(nullptr, partid); for (const auto& obj : objs) { std::vector subnames = obj.getSubNames(); for (const auto& subname : subnames) { if (subname.substr(0, 4) == "Face") { return true; } } } return false; } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ void CreateSimplePartCommands() { Gui::CommandManager& rcCmdMgr = Gui::Application::Instance->commandManager(); rcCmdMgr.addCommand(new CmdPartSimpleCylinder()); rcCmdMgr.addCommand(new CmdPartShapeFromMesh()); rcCmdMgr.addCommand(new CmdPartPointsFromMesh()); rcCmdMgr.addCommand(new CmdPartSimpleCopy()); rcCmdMgr.addCommand(new CmdPartElementCopy()); rcCmdMgr.addCommand(new CmdPartTransformedCopy()); rcCmdMgr.addCommand(new CmdPartRefineShape()); rcCmdMgr.addCommand(new CmdPartDefeaturing()); }