From 23288e7b01dcadeb46fb0cb6b70346a5b25eab08 Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 13 Apr 2022 15:41:15 +0200 Subject: [PATCH] Points: fixes #5785: a python method to convert a Shape into a point cloud without extra dialog but parameter --- src/Mod/Points/CMakeLists.txt | 25 +++++-- src/Mod/Points/Gui/Command.cpp | 81 +++++++++-------------- src/Mod/Points/pointscommands/__init__.py | 0 src/Mod/Points/pointscommands/commands.py | 61 +++++++++++++++++ 4 files changed, 114 insertions(+), 53 deletions(-) create mode 100644 src/Mod/Points/pointscommands/__init__.py create mode 100644 src/Mod/Points/pointscommands/commands.py diff --git a/src/Mod/Points/CMakeLists.txt b/src/Mod/Points/CMakeLists.txt index a1e872e02b..bbb97826e3 100644 --- a/src/Mod/Points/CMakeLists.txt +++ b/src/Mod/Points/CMakeLists.txt @@ -12,9 +12,24 @@ if(BUILD_GUI) list (APPEND Points_Scripts InitGui.py) endif(BUILD_GUI) -INSTALL( - FILES - ${Points_Scripts} - DESTINATION - Mod/Points +# ************************************************************************************************ +# ****** Python non Gui packages and modules ***************************************************** +# ************************************************************************************************ + +SET(PointsCommands_SRCS + pointscommands/__init__.py + pointscommands/commands.py ) + +SET(PointsAllScripts + ${PointsCommands_SRCS} +) + +ADD_CUSTOM_TARGET(PointsScripts ALL + SOURCES ${PointsAllScripts} +) +fc_copy_sources(PointsScripts "${CMAKE_BINARY_DIR}/Mod/Points" ${PointsAllScripts}) + +# install directories for Python packages +INSTALL(FILES ${Points_Scripts} DESTINATION Mod/Points) +INSTALL(FILES ${PointsCommands_SRCS} DESTINATION Mod/Points/pointscommands) diff --git a/src/Mod/Points/Gui/Command.cpp b/src/Mod/Points/Gui/Command.cpp index 9ea6bd09bb..973d519005 100644 --- a/src/Mod/Points/Gui/Command.cpp +++ b/src/Mod/Points/Gui/Command.cpp @@ -30,6 +30,7 @@ #endif #include +#include #include #include #include @@ -212,59 +213,43 @@ void CmdPointsConvert::activated(int iMsg) Gui::WaitCursor wc; openCommand(QT_TRANSLATE_NOOP("Command", "Convert to points")); - std::vector geoObject = getSelection().getObjectsOfType(Base::Type::fromName("App::GeoFeature")); + std::vector geoObject = getSelection().getObjectsOfType(); - bool addedPoints = false; - for (std::vector::iterator it = geoObject.begin(); it != geoObject.end(); ++it) { - Base::Placement globalPlacement = static_cast(*it)->globalPlacement(); - Base::Placement localPlacement = static_cast(*it)->Placement.getValue(); - localPlacement = globalPlacement * localPlacement.inverse(); - const App::PropertyComplexGeoData* prop = static_cast(*it)->getPropertyOfGeometry(); - if (prop) { - const Data::ComplexGeoData* data = prop->getComplexData(); - std::vector vertexes; - std::vector normals; - data->getPoints(vertexes, normals, static_cast(tol)); - if (!vertexes.empty()) { - Points::Feature* fea = nullptr; - if (vertexes.size() == normals.size()) { - fea = static_cast(Base::Type::fromName("Points::FeatureCustom").createInstance()); - if (!fea) { - Base::Console().Error("Failed to create instance of 'Points::FeatureCustom'\n"); - continue; - } - Points::PropertyNormalList* prop = static_cast - (fea->addDynamicProperty("Points::PropertyNormalList", "Normal")); - if (prop) { - std::vector normf; - normf.resize(normals.size()); - std::transform(normals.begin(), normals.end(), normf.begin(), Base::toVector); - prop->setValues(normf); - } - } - else { - fea = new Points::Feature; - } - - Points::PointKernel kernel; - kernel.reserve(vertexes.size()); - for (std::vector::iterator pt = vertexes.begin(); pt != vertexes.end(); ++pt) - kernel.push_back(*pt); - fea->Points.setValue(kernel); - fea->Placement.setValue(localPlacement); - - App::Document* doc = (*it)->getDocument(); - doc->addObject(fea, "Points"); - fea->purgeTouched(); - addedPoints = true; + auto run_python = [](const std::vector& geoObject, double tol) -> bool { + Py::List list; + for (auto it : geoObject) { + const App::PropertyComplexGeoData* prop = it->getPropertyOfGeometry(); + if (prop) { + list.append(Py::asObject(it->getPyObject())); } } - } - if (addedPoints) - commitCommand(); - else + if (list.size() > 0) { + PyObject* module = PyImport_ImportModule("pointscommands.commands"); + if (!module) { + throw Py::Exception(); + } + + Py::Module commands(module, true); + commands.callMemberFunction("make_points_from_geometry", Py::TupleN(list, Py::Float(tol))); + return true; + } + + return false; + }; + + Base::PyGILStateLocker lock; + try { + if (run_python(geoObject, tol)) + commitCommand(); + else + abortCommand(); + } + catch (const Py::Exception&) { abortCommand(); + Base::PyException e; + e.ReportException(); + } } bool CmdPointsConvert::isActive() diff --git a/src/Mod/Points/pointscommands/__init__.py b/src/Mod/Points/pointscommands/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/Mod/Points/pointscommands/commands.py b/src/Mod/Points/pointscommands/commands.py new file mode 100644 index 0000000000..d534510925 --- /dev/null +++ b/src/Mod/Points/pointscommands/commands.py @@ -0,0 +1,61 @@ +# *************************************************************************** +# * Copyright (c) 2022 Werner Mayer * +# * * +# * This file is part of the FreeCAD CAx development system. * +# * * +# * 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__ = "FreeCAD Points command definitions" +__author__ = "Werner Mayer" +__url__ = "https://www.freecadweb.org" + +## @package commands +# \ingroup Points +# \brief FreeCAD Points command definitions + +import FreeCAD +import Points + +def make_points_from_geometry(geometries, distance): + for geom in geometries: + global_plm = geom.getGlobalPlacement() + local_plm = geom.Placement + plm = global_plm * local_plm.inverse() + + prop = geom.getPropertyOfGeometry() + if prop is None: + continue + + points_and_normals = prop.getPoints(distance) + if len(points_and_normals[0]) == 0: + continue + + points = geom.Document.addObject("Points::Feature", "Points") + + kernel = Points.Points() + kernel.addPoints(points_and_normals[0]) + + points.Points = kernel + points.Placement = plm + + if len(points_and_normals[1]) > 0 and len(points_and_normals[0]) == len(points_and_normals[1]): + points.addProperty("Points::PropertyNormalList", "Normal") + points.Normal = points_and_normals[1] + + points.purgeTouched() \ No newline at end of file