From 599b14b430cd789443e1b22fa08d7b4d88238252 Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 3 Mar 2023 18:11:46 +0100 Subject: [PATCH] Part: extend command Part_PointsFromMesh to support any geometric type --- src/Mod/Part/BasicShapes/Utils.py | 45 +++++++++++++++++ src/Mod/Part/CMakeLists.txt | 1 + src/Mod/Part/Gui/CommandSimple.cpp | 80 ++++++++++++++++++++++-------- 3 files changed, 106 insertions(+), 20 deletions(-) create mode 100644 src/Mod/Part/BasicShapes/Utils.py diff --git a/src/Mod/Part/BasicShapes/Utils.py b/src/Mod/Part/BasicShapes/Utils.py new file mode 100644 index 0000000000..7d78171056 --- /dev/null +++ b/src/Mod/Part/BasicShapes/Utils.py @@ -0,0 +1,45 @@ +# *************************************************************************** +# * * +# * Copyright (c) 2023 Werner Mayer * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * This program 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 program; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** + +__title__ = "BasicShapes.Utils" +__author__ = "Werner Mayer" +__url__ = "http://www.freecadweb.org" +__doc__ = "Utilities for shapes" + + +import Part + +def makeCompoundFromPoints(geometry, distance = 1.0): + """Get sampled points from geometry and create a compound.""" + try: + points = geometry.getPropertyOfGeometry().getPoints(distance)[0] + return Part.makeCompound([Part.Point(m).toShape() for m in points]) + except AttributeError: + return None + +def showCompoundFromPoints(geometry, distance = 1.0): + """Create a compound from geometry and show it.""" + try: + compound = makeCompoundFromPoints(geometry, distance) + return Part.show(compound, geometry.Label + "_pts") + except AttributeError: + return None diff --git a/src/Mod/Part/CMakeLists.txt b/src/Mod/Part/CMakeLists.txt index 85a4164d8a..96fafdeca9 100644 --- a/src/Mod/Part/CMakeLists.txt +++ b/src/Mod/Part/CMakeLists.txt @@ -30,6 +30,7 @@ set(AttachmentEditor_Scripts set(BasicShapes_Scripts BasicShapes/__init__.py BasicShapes/Shapes.py + BasicShapes/Utils.py ) if(BUILD_GUI) diff --git a/src/Mod/Part/Gui/CommandSimple.cpp b/src/Mod/Part/Gui/CommandSimple.cpp index 76a038e05e..e46d034e1d 100644 --- a/src/Mod/Part/Gui/CommandSimple.cpp +++ b/src/Mod/Part/Gui/CommandSimple.cpp @@ -24,11 +24,13 @@ #include "PreCompiled.h" #ifndef _PreComp_ # include +# include #endif #include #include #include +#include #include #include #include @@ -38,6 +40,7 @@ #include "DlgPartCylinderImp.h" #include "ShapeFromMesh.h" +#include //=========================================================================== @@ -129,8 +132,8 @@ CmdPartPointsFromMesh::CmdPartPointsFromMesh() { sAppModule = "Part"; sGroup = QT_TR_NOOP("Part"); - sMenuText = QT_TR_NOOP("Create points object from mesh"); - sToolTipText = QT_TR_NOOP("Create selectable points object from selected mesh object"); + sMenuText = QT_TR_NOOP("Create points object from geometry"); + sToolTipText = QT_TR_NOOP("Create selectable points object from selected geometric object"); sWhatsThis = "Part_PointsFromMesh"; sStatusTip = sToolTipText; sPixmap = "Part_PointsFromMesh"; @@ -140,24 +143,61 @@ void CmdPartPointsFromMesh::activated(int iMsg) { Q_UNUSED(iMsg); - Base::Type meshid = Base::Type::fromName("Mesh::Feature"); - std::vector meshes; - meshes = Gui::Selection().getObjectsOfType(meshid); - Gui::WaitCursor wc; - std::vector::iterator it; - openCommand(QT_TRANSLATE_NOOP("Command", "Points from mesh")); + auto getDefaultDistance = [](Part::Feature* geometry) { + auto bbox = geometry->Shape.getBoundingBox(); + int steps{20}; + return bbox.CalcDiagonalLength() / steps; + }; - for (it = meshes.begin(); it != meshes.end(); ++it) { - App::Document* doc = (*it)->getDocument(); - std::string mesh = (*it)->getNameInDocument(); - if (!(*it)->isDerivedFrom(Base::Type::fromName("Mesh::Feature"))) - continue; - doCommand(Doc,"import Part"); - doCommand(Doc,"mesh_pts = FreeCAD.getDocument(\"%s\").getObject(\"%s\").Mesh.Points\n", - doc->getName(), mesh.c_str()); - doCommand(Doc,"Part.show(Part.makeCompound([Part.Point(m.Vector).toShape() for m in mesh_pts]),\"%s\")\n", - (mesh+"_pts").c_str()); - doCommand(Doc,"del mesh_pts\n"); + 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 Base::freecad_dynamic_cast(obj); + }); + + if (found != geoms.end()) { + + double defaultDistance = getDefaultDistance(Base::freecad_dynamic_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(); @@ -165,7 +205,7 @@ void CmdPartPointsFromMesh::activated(int iMsg) bool CmdPartPointsFromMesh::isActive() { - Base::Type meshid = Base::Type::fromName("Mesh::Feature"); + Base::Type meshid = Base::Type::fromName("App::GeoFeature"); return Gui::Selection().countObjectsOfType(meshid) > 0; }