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