Merge pull request #17779 from wwmayer/noboostpy

Remove support for Boost.Python
This commit is contained in:
Chris Hennes
2025-03-17 00:00:32 -05:00
committed by GitHub
10 changed files with 27 additions and 955 deletions

View File

@@ -203,6 +203,10 @@ macro(InitializeFreeCADBuildOptions)
set(BUILD_SMESH OFF)
endif()
if (BUILD_CAM OR BUILD_FLAT_MESH)
set(FREECAD_USE_PYBIND11 ON)
endif()
# force build directory to be different to source directory
if (BUILD_FORCE_DIRECTORY)
if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR})

View File

@@ -87,7 +87,6 @@ macro(PrintFinalReport)
value(Python3_EXECUTABLE)
value(PYTHON_LIBRARY)
value(FREECAD_CREATE_MAC_APP)
value(FREECAD_USE_PYBIND11)
value(FREECAD_USE_EXTERNAL_KDL)
value(FREECAD_USE_PYSIDE)
value(FREECAD_USE_SHIBOKEN)

View File

@@ -2,7 +2,6 @@ macro(SetupPybind11)
# -------------------------------- PyBind11 -----------------------------
# necessary for flat-mesh feature
option(FREECAD_USE_PYBIND11 "Use pybind11" OFF)
if (FREECAD_USE_PYBIND11)
find_package(pybind11 REQUIRED)
endif()

View File

@@ -19,6 +19,9 @@ if(FREECAD_LIBPACK_VERSION VERSION_GREATER_EQUAL "3.1.0")
find_package(pybind11 REQUIRED PATHS ${FREECAD_LIBPACK_DIR}/share/cmake/pybind11 NO_DEFAULT_PATH)
message(STATUS "Found LibPack 3 pybind11 ${pybind11_VERSION}")
set(FREECAD_USE_PYBIND11 ON)
else()
# We have completely removed support for boost-python and require pybind11, which requires LibPack 3.1 or later
message(FATAL_ERROR "FreeCAD now requires LibPack 3.1.0 or newer (you are using ${FREECAD_LIBPACK_VERSION}): please upgrade your LibPack")
endif()
find_package(XercesC REQUIRED PATHS ${FREECAD_LIBPACK_DIR}/cmake NO_DEFAULT_PATH)
@@ -28,6 +31,7 @@ find_package(yaml-cpp REQUIRED PATHS ${FREECAD_LIBPACK_DIR}/lib/cmake NO_DEFAULT
message(STATUS "Found LibPack 3 yaml-cpp ${yaml-cpp_VERSION}")
find_package(Coin REQUIRED PATHS ${FREECAD_LIBPACK_DIR}/lib/cmake NO_DEFAULT_PATH)
message(STATUS "Found LibPack 3 Coin ${Coin_VERSION}")
# For compatibility with the rest of the cMake scripts:
set (COIN3D_FOUND TRUE)

View File

@@ -21,7 +21,6 @@ packages=(
libboost-graph-dev
libboost-iostreams-dev
libboost-program-options-dev
libboost-python-dev
libboost-regex-dev
libboost-serialization-dev
libboost-thread-dev
@@ -58,6 +57,7 @@ packages=(
python3-packaging
python3-pivy
python3-ply
python3-pybind11
python3-pyside2.qtcore
python3-pyside2.qtgui
python3-pyside2.qtnetwork

View File

@@ -23,39 +23,7 @@ include_directories(
link_directories(${OCC_LIBRARY_DIR})
if(NOT FREECAD_USE_PYBIND11)
if(NOT FREECAD_LIBPACK_USE OR FREECAD_LIBPACK_CHECKFILE_CLBUNDLER OR FREECAD_LIBPACK_CHECKFILE_VERSION)
# boost-python >= 1.67 on some platforms has suffix
if (FORCE_BOOST_PY_SUFFIX)
set(BOOST_PY_SUFFIX ${FORCE_BOOST_PY_SUFFIX})
else ()
set(BOOST_PY_SUFFIX ${Python3_VERSION_MAJOR}${Python3_VERSION_MINOR})
endif ()
find_package( Boost COMPONENTS python${BOOST_PY_SUFFIX} )
if (NOT Boost_PYTHON${BOOST_PY_SUFFIX}_FOUND)
# try just the major version
find_package( Boost COMPONENTS python${Python3_VERSION_MAJOR} )
if (NOT Boost_PYTHON${Python3_VERSION_MAJOR}_FOUND)
# unversioned
find_package( Boost COMPONENTS python REQUIRED)
endif()
endif()
if(Boost_FOUND)
include_directories(SYSTEM ${Boost_INCLUDE_DIRS})
MESSAGE(STATUS "found Boost: " ${Boost_LIB_VERSION})
MESSAGE(STATUS "boost-incude dirs are: " ${Boost_INCLUDE_DIRS})
MESSAGE(STATUS "boost-python lib is: " ${Boost_PYTHON_LIBRARY})
MESSAGE(STATUS "boost_LIBRARY_DIRS is: " ${Boost_LIBRARY_DIRS})
MESSAGE(STATUS "Boost_LIBRARIES is: " ${Boost_LIBRARIES})
endif()
else()
include_directories(SYSTEM ${Boost_INCLUDE_DIRS})
endif()
else()
include_directories(SYSTEM ${pybind11_INCLUDE_DIR})
endif(NOT FREECAD_USE_PYBIND11)
include_directories(${pybind11_INCLUDE_DIR})
# this defines the source-files for library
@@ -81,15 +49,9 @@ set(AREA_SRC_CLIPPER
)
# this defines the additional source-files for python module (wrapper to libarea)
if (NOT FREECAD_USE_PYBIND11)
set(PYAREA_SRC
PythonStuff.cpp
)
else (NOT FREECAD_USE_PYBIND11)
set(PYAREA_SRC
set(PYAREA_SRC
pyarea.cpp
)
endif (NOT FREECAD_USE_PYBIND11)
)
# this defines the headers
if(DEFINED INCLUDE_INSTALL_DIR)

View File

@@ -1,578 +0,0 @@
// PythonStuff.cpp
// Copyright 2011, Dan Heeks
// This program is released under the BSD license. See the file COPYING for details.
#include "PythonStuff.h"
#include "Area.h"
#include "Point.h"
#include "AreaDxf.h"
#include "kurve/geometry.h"
#include "Adaptive.hpp"
#if defined(_POSIX_C_SOURCE)
#undef _POSIX_C_SOURCE
#endif
#if defined(_XOPEN_SOURCE)
#undef _XOPEN_SOURCE
#endif
#if _DEBUG
#undef _DEBUG
#include <Python.h>
#define _DEBUG
#else
#include <Python.h>
#endif
#if defined(__GNUG__) && !defined(__clang__)
#pragma implementation
#endif
#define BOOST_BIND_GLOBAL_PLACEHOLDERS
#include <boost/foreach.hpp>
#include <boost/python.hpp>
#include <boost/python/module.hpp>
#include <boost/python/class.hpp>
#include <boost/python/wrapper.hpp>
#include <boost/python/call.hpp>
#include "clipper.hpp"
using namespace ClipperLib;
namespace bp = boost::python;
boost::python::list getVertices(const CCurve& curve)
{
boost::python::list vlist;
BOOST_FOREACH (const CVertex& vertex, curve.m_vertices) {
vlist.append(vertex);
}
return vlist;
}
boost::python::list getCurves(const CArea& area)
{
boost::python::list clist;
BOOST_FOREACH (const CCurve& curve, area.m_curves) {
clist.append(curve);
}
return clist;
}
boost::python::tuple
transformed_point(const geoff_geometry::Matrix& matrix, double x, double y, double z)
{
geoff_geometry::Point3d p(x, y, z);
p = p.Transform(matrix);
return bp::make_tuple(p.x, p.y, p.z);
}
static void print_curve(const CCurve& c)
{
std::size_t nvertices = c.m_vertices.size();
#if defined SIZEOF_SIZE_T && SIZEOF_SIZE_T == 4
printf("number of vertices = %d\n", nvertices);
#elif defined(_WIN32)
printf("number of vertices = %Iu\n", nvertices);
#else
printf("number of vertices = %lu\n", nvertices);
#endif
int i = 0;
for (std::list<CVertex>::const_iterator It = c.m_vertices.begin(); It != c.m_vertices.end();
It++, i++) {
const CVertex& vertex = *It;
printf("vertex %d type = %d, x = %g, y = %g",
i + 1,
vertex.m_type,
vertex.m_p.x / CArea::get_units(),
vertex.m_p.y / CArea::get_units());
if (vertex.m_type) {
printf(", xc = %g, yc = %g",
vertex.m_c.x / CArea::get_units(),
vertex.m_c.y / CArea::get_units());
}
printf("\n");
}
}
static void print_area(const CArea& a)
{
for (std::list<CCurve>::const_iterator It = a.m_curves.begin(); It != a.m_curves.end(); It++) {
const CCurve& curve = *It;
print_curve(curve);
}
}
static unsigned int num_vertices(const CCurve& curve)
{
return static_cast<unsigned int>(curve.m_vertices.size());
}
static CVertex FirstVertex(const CCurve& curve)
{
return curve.m_vertices.front();
}
static CVertex LastVertex(const CCurve& curve)
{
return curve.m_vertices.back();
}
static void set_units(double units)
{
CArea::set_units(units);
}
static double get_units()
{
return CArea::get_units();
}
static bool holes_linked()
{
return CArea::HolesLinked();
}
static CArea AreaFromDxf(const char* filepath)
{
CArea area;
AreaDxfRead dxf(&area, filepath);
dxf.DoRead();
return area;
}
static void append_point(CCurve& c, const Point& p)
{
c.m_vertices.emplace_back(p);
}
static boost::python::tuple nearest_point_to_curve(CCurve& c1, const CCurve& c2)
{
double dist;
Point p = c1.NearestPoint(c2, &dist);
return bp::make_tuple(p, dist);
}
boost::python::list MakePocketToolpath(const CArea& a,
double tool_radius,
double extra_offset,
double stepover,
bool from_center,
bool use_zig_zag,
double zig_angle)
{
std::list<CCurve> toolpath;
CAreaPocketParams params(tool_radius,
extra_offset,
stepover,
from_center,
use_zig_zag ? ZigZagPocketMode : SpiralPocketMode,
zig_angle);
a.SplitAndMakePocketToolpath(toolpath, params);
boost::python::list clist;
BOOST_FOREACH (const CCurve& c, toolpath) {
clist.append(c);
}
return clist;
}
boost::python::list SplitArea(const CArea& a)
{
std::list<CArea> areas;
a.Split(areas);
boost::python::list alist;
BOOST_FOREACH (const CArea& a, areas) {
alist.append(a);
}
return alist;
}
void dxfArea(CArea& area, const char* /*str*/)
{
area = CArea();
}
boost::python::list getCurveSpans(const CCurve& c)
{
boost::python::list span_list;
const Point* prev_p = NULL;
for (std::list<CVertex>::const_iterator VIt = c.m_vertices.begin(); VIt != c.m_vertices.end();
VIt++) {
const CVertex& vertex = *VIt;
if (prev_p) {
span_list.append(Span(*prev_p, vertex));
}
prev_p = &(vertex.m_p);
}
return span_list;
}
Span getFirstCurveSpan(const CCurve& c)
{
if (c.m_vertices.size() < 2) {
return Span();
}
std::list<CVertex>::const_iterator VIt = c.m_vertices.begin();
const Point& p = (*VIt).m_p;
VIt++;
return Span(p, *VIt, true);
}
Span getLastCurveSpan(const CCurve& c)
{
if (c.m_vertices.size() < 2) {
return Span();
}
std::list<CVertex>::const_reverse_iterator VIt = c.m_vertices.rbegin();
const CVertex& v = (*VIt);
VIt++;
return Span((*VIt).m_p, v, c.m_vertices.size() == 2);
}
bp::tuple TangentialArc(const Point& p0, const Point& p1, const Point& v0)
{
Point c;
int dir;
tangential_arc(p0, p1, v0, c, dir);
return bp::make_tuple(c, dir);
}
boost::python::list spanIntersect(const Span& span1, const Span& span2)
{
boost::python::list plist;
std::list<Point> pts;
span1.Intersect(span2, pts);
BOOST_FOREACH (const Point& p, pts) {
plist.append(p);
}
return plist;
}
// Matrix(boost::python::list &l){}
std::shared_ptr<geoff_geometry::Matrix> matrix_constructor(const boost::python::list& lst)
{
double m[16] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
boost::python::ssize_t n = boost::python::len(lst);
int j = 0;
for (boost::python::ssize_t i = 0; i < n; i++) {
boost::python::object elem = lst[i];
m[j] = boost::python::extract<double>(elem.attr("__float__")());
j++;
if (j >= 16) {
break;
}
}
return std::shared_ptr<geoff_geometry::Matrix>(new geoff_geometry::Matrix(m));
}
boost::python::list InsideCurves(const CArea& a, const CCurve& curve)
{
boost::python::list plist;
std::list<CCurve> curves_inside;
a.InsideCurves(curve, curves_inside);
BOOST_FOREACH (const CCurve& c, curves_inside) {
plist.append(c);
}
return plist;
}
boost::python::list CurveIntersections(const CCurve& c1, const CCurve& c2)
{
boost::python::list plist;
std::list<Point> pts;
c1.CurveIntersections(c2, pts);
BOOST_FOREACH (const Point& p, pts) {
plist.append(p);
}
return plist;
}
boost::python::list AreaIntersections(const CArea& a, const CCurve& c2)
{
boost::python::list plist;
std::list<Point> pts;
a.CurveIntersections(c2, pts);
BOOST_FOREACH (const Point& p, pts) {
plist.append(p);
}
return plist;
}
double AreaGetArea(const CArea& a)
{
return a.GetArea();
}
// Adaptive2d.Execute wrapper
bp::list AdaptiveExecute(AdaptivePath::Adaptive2d& ada,
const boost::python::list& stock_paths,
const boost::python::list& in_paths,
boost::python::object progressCallbackFn)
{
bp::list out_list;
// convert stock paths
AdaptivePath::DPaths stock_dpaths;
for (bp::ssize_t i = 0; i < bp::len(stock_paths); i++) {
bp::list in_path = bp::extract<boost::python::list>(stock_paths[i]);
AdaptivePath::DPath dpath;
for (bp::ssize_t j = 0; j < bp::len(in_path); j++) {
bp::list in_point = bp::extract<bp::list>(in_path[j]);
dpath.push_back(pair<double, double>(bp::extract<double>(in_point[0]),
bp::extract<double>(in_point[1])));
}
stock_dpaths.push_back(dpath);
}
// convert inputs
AdaptivePath::DPaths dpaths;
for (bp::ssize_t i = 0; i < bp::len(in_paths); i++) {
bp::list in_path = bp::extract<boost::python::list>(in_paths[i]);
AdaptivePath::DPath dpath;
for (bp::ssize_t j = 0; j < bp::len(in_path); j++) {
bp::list in_point = bp::extract<bp::list>(in_path[j]);
dpath.push_back(pair<double, double>(bp::extract<double>(in_point[0]),
bp::extract<double>(in_point[1])));
}
dpaths.push_back(dpath);
}
// Execute with callback
std::list<AdaptivePath::AdaptiveOutput> result =
ada.Execute(stock_dpaths, dpaths, [progressCallbackFn](AdaptivePath::TPaths tp) -> bool {
bp::list out_paths;
for (const auto& in_pair : tp) {
bp::list path;
for (const auto& in_pt : in_pair.second) {
path.append(bp::make_tuple(in_pt.first, in_pt.second));
}
out_paths.append(bp::make_tuple(in_pair.first, path));
}
return bp::extract<bool>(progressCallbackFn(out_paths));
});
// convert outputs back
BOOST_FOREACH (const auto& res, result) {
out_list.append(res);
}
return out_list;
}
// Converts a std::pair instance to a Python tuple.
template<typename T1, typename T2>
struct std_pair_to_tuple
{
static PyObject* convert(std::pair<T1, T2> const& p)
{
return boost::python::incref(boost::python::make_tuple(p.first, p.second).ptr());
}
static PyTypeObject const* get_pytype()
{
return &PyTuple_Type;
}
};
boost::python::list AdaptiveOutput_AdaptivePaths(const AdaptivePath::AdaptiveOutput& ado)
{
bp::list olist;
for (auto& ap : ado.AdaptivePaths) {
bp::list op;
for (auto& pt : ap.second) {
op.append(bp::make_tuple(pt.first, pt.second));
}
olist.append(bp::make_tuple(ap.first, op));
}
return olist;
}
BOOST_PYTHON_MODULE(area)
{
bp::class_<Point>("Point")
.def(bp::init<double, double>())
.def(bp::init<Point>())
.def(bp::other<double>() * bp::self)
.def(bp::self * bp::other<double>())
.def(bp::self / bp::other<double>())
.def(bp::self * bp::other<Point>())
.def(bp::self - bp::other<Point>())
.def(bp::self + bp::other<Point>())
.def(bp::self ^ bp::other<Point>())
.def(bp::self == bp::other<Point>())
.def(bp::self != bp::other<Point>())
.def(-bp::self)
.def(~bp::self)
.def("dist", &Point::dist)
.def("length", &Point::length)
.def("normalize", &Point::normalize)
.def("Rotate", static_cast<void (Point::*)(double, double)>(&Point::Rotate))
.def("Rotate", static_cast<void (Point::*)(double)>(&Point::Rotate))
.def_readwrite("x", &Point::x)
.def_readwrite("y", &Point::y)
.def("Transform", &Point::Transform);
bp::class_<CVertex>("Vertex")
.def(bp::init<CVertex>())
.def(bp::init<int, Point, Point>())
.def(bp::init<Point>())
.def(bp::init<int, Point, Point, int>())
.def_readwrite("type", &CVertex::m_type)
.def_readwrite("p", &CVertex::m_p)
.def_readwrite("c", &CVertex::m_c)
.def_readwrite("user_data", &CVertex::m_user_data);
bp::class_<Span>("Span")
.def(bp::init<Span>())
.def(bp::init<Point, CVertex, bool>())
.def("NearestPoint",
static_cast<Point (Span::*)(const Point& p) const>(&Span::NearestPoint))
.def("NearestPoint",
static_cast<Point (Span::*)(const Span& p, double* d) const>(&Span::NearestPoint))
.def("GetBox", &Span::GetBox)
.def("IncludedAngle", &Span::IncludedAngle)
.def("GetArea", &Span::GetArea)
.def("On", &Span::On)
.def("MidPerim", &Span::MidPerim)
.def("MidParam", &Span::MidParam)
.def("Length", &Span::Length)
.def("GetVector", &Span::GetVector)
.def("Intersect", &spanIntersect)
.def_readwrite("p", &Span::m_p)
.def_readwrite("v", &Span::m_v);
bp::class_<CCurve>("Curve")
.def(bp::init<CCurve>())
.def("getVertices", &getVertices)
.def("append", &CCurve::append)
.def("append", &append_point)
.def("text", &print_curve)
.def("NearestPoint",
static_cast<Point (CCurve::*)(const Point& p) const>(&CCurve::NearestPoint))
.def("NearestPoint", &nearest_point_to_curve)
.def("Reverse", &CCurve::Reverse)
.def("getNumVertices", &num_vertices)
.def("FirstVertex", &FirstVertex)
.def("LastVertex", &LastVertex)
.def("GetArea", &CCurve::GetArea)
.def("IsClockwise", &CCurve::IsClockwise)
.def("IsClosed", &CCurve::IsClosed)
.def("ChangeStart", &CCurve::ChangeStart)
.def("ChangeEnd", &CCurve::ChangeEnd)
.def("Offset", &CCurve::Offset)
.def("OffsetForward", &CCurve::OffsetForward)
.def("GetSpans", &getCurveSpans)
.def("GetFirstSpan", &getFirstCurveSpan)
.def("GetLastSpan", &getLastCurveSpan)
.def("Break", &CCurve::Break)
.def("Perim", &CCurve::Perim)
.def("PerimToPoint", &CCurve::PerimToPoint)
.def("PointToPerim", &CCurve::PointToPerim)
.def("FitArcs", &CCurve::FitArcs)
.def("UnFitArcs", &CCurve::UnFitArcs)
.def("Intersections", &CurveIntersections);
bp::class_<CBox2D>("Box")
.def(bp::init<CBox2D>())
.def("MinX", &CBox2D::MinX)
.def("MaxX", &CBox2D::MaxX)
.def("MinY", &CBox2D::MinY)
.def("MaxY", &CBox2D::MaxY);
bp::class_<CArea>("Area")
.def(bp::init<CArea>())
.def("getCurves", &getCurves)
.def("append", &CArea::append)
.def("Subtract", &CArea::Subtract)
.def("Intersect", &CArea::Intersect)
.def("Union", &CArea::Union)
.def("Offset", &CArea::Offset)
.def("FitArcs", &CArea::FitArcs)
.def("text", &print_area)
.def("num_curves", &CArea::num_curves)
.def("NearestPoint", &CArea::NearestPoint)
.def("GetBox", &CArea::GetBox)
.def("Reorder", &CArea::Reorder)
.def("MakePocketToolpath", &MakePocketToolpath)
.def("Split", &SplitArea)
.def("InsideCurves", &InsideCurves)
.def("Thicken", &CArea::Thicken)
.def("Intersections", &AreaIntersections)
.def("GetArea", &AreaGetArea);
bp::class_<geoff_geometry::Matrix, std::shared_ptr<geoff_geometry::Matrix>>("Matrix")
.def(bp::init<geoff_geometry::Matrix>())
.def("__init__", bp::make_constructor(&matrix_constructor))
.def("TransformedPoint", &transformed_point)
.def("Multiply", &geoff_geometry::Matrix::Multiply);
bp::def("set_units", set_units);
bp::def("get_units", get_units);
bp::def("holes_linked", holes_linked);
bp::def("AreaFromDxf", AreaFromDxf);
bp::def("TangentialArc", TangentialArc);
using namespace AdaptivePath;
boost::python::
to_python_converter<std::pair<double, double>, std_pair_to_tuple<double, double>, true>();
bp::enum_<MotionType>("AdaptiveMotionType")
.value("Cutting", MotionType::mtCutting)
.value("LinkClear", MotionType::mtLinkClear)
.value("LinkNotClear", MotionType::mtLinkNotClear)
.value("LinkClearAtPrevPass", MotionType::mtLinkClearAtPrevPass);
bp::enum_<OperationType>("AdaptiveOperationType")
.value("ClearingInside", OperationType::otClearingInside)
.value("ClearingOutside", OperationType::otClearingOutside)
.value("ProfilingInside", OperationType::otProfilingInside)
.value("ProfilingOutside", OperationType::otProfilingOutside);
bp::class_<AdaptiveOutput>("AdaptiveOutput")
.def(bp::init<>())
.add_property("HelixCenterPoint",
bp::make_getter(&AdaptiveOutput::HelixCenterPoint,
bp::return_value_policy<bp::return_by_value>()))
.add_property("StartPoint",
bp::make_getter(&AdaptiveOutput::StartPoint,
bp::return_value_policy<bp::return_by_value>()))
.add_property("AdaptivePaths", &AdaptiveOutput_AdaptivePaths)
.def_readonly("ReturnMotionType", &AdaptiveOutput::ReturnMotionType);
bp::class_<Adaptive2d>("Adaptive2d")
.def(bp::init<>())
.def("Execute", &AdaptiveExecute)
.def_readwrite("stepOverFactor", &Adaptive2d::stepOverFactor)
.def_readwrite("toolDiameter", &Adaptive2d::toolDiameter)
.def_readwrite("stockToLeave", &Adaptive2d::stockToLeave)
.def_readwrite("helixRampDiameter", &Adaptive2d::helixRampDiameter)
.def_readwrite("forceInsideOut", &Adaptive2d::forceInsideOut)
.def_readwrite("finishingProfile", &Adaptive2d::finishingProfile)
//.def_readwrite("polyTreeNestingLimit", &Adaptive2d::polyTreeNestingLimit)
.def_readwrite("tolerance", &Adaptive2d::tolerance)
.def_readwrite("keepToolDownDistRatio", &Adaptive2d::keepToolDownDistRatio)
.def_readwrite("opType", &Adaptive2d::opType);
}

View File

@@ -1,9 +0,0 @@
// PythonStuff.h
// Copyright 2011, Dan Heeks
// This program is released under the BSD license. See the file COPYING for details.
extern void Message(const char*);
void PythonInit();
void PythonFinish();

View File

@@ -100,7 +100,6 @@ INSTALL(TARGETS MeshPart DESTINATION ${CMAKE_INSTALL_LIBDIR})
################################ flat mesh ###############################
if (BUILD_FLAT_MESH)
if (FREECAD_USE_PYBIND11)
SET(FLATMESH_SRCS
MeshFlattening.cpp
MeshFlattening.h
@@ -118,52 +117,5 @@ if (BUILD_FLAT_MESH)
SET_BIN_DIR(flatmesh flatmesh /Mod/MeshPart)
install(TARGETS flatmesh DESTINATION ${CMAKE_INSTALL_LIBDIR})
else()
if(NOT FREECAD_LIBPACK_USE OR FREECAD_LIBPACK_CHECKFILE_CLBUNDLER OR
(FREECAD_LIBPACK_CHECKFILE_VERSION AND FREECAD_LIBPACK_VERSION VERSION_LESS "3.1.0"))
# boost-python >= 1.67 on some platforms has suffix
if (FORCE_BOOST_PY_SUFFIX)
set(BOOST_PY_SUFFIX ${FORCE_BOOST_PY_SUFFIX})
else ()
set(BOOST_PY_SUFFIX ${Python3_VERSION_MAJOR}${Python3_VERSION_MINOR})
endif ()
find_package( Boost COMPONENTS python${BOOST_PY_SUFFIX} )
if (NOT Boost_PYTHON${BOOST_PY_SUFFIX}_FOUND)
# try just the major version
find_package( Boost COMPONENTS python${Python3_VERSION_MAJOR} )
if (NOT Boost_PYTHON${Python3_VERSION_MAJOR}_FOUND)
# unversioned
find_package( Boost COMPONENTS python REQUIRED)
endif()
endif()
if(Boost_FOUND)
include_directories(SYSTEM ${Boost_INCLUDE_DIRS})
SET(FLATMESH_SRCS
MeshFlattening.cpp
MeshFlattening.h
MeshFlatteningNurbs.h
MeshFlatteningNurbs.cpp
MeshFlatteningLscmRelax.h
MeshFlatteningLscmRelax.cpp
MeshFlatteningBoostPython.cpp
)
add_library(flatmesh SHARED ${FLATMESH_SRCS})
SET_PYTHON_PREFIX_SUFFIX(flatmesh)
if (BUILD_DYNAMIC_LINK_PYTHON)
target_link_libraries(flatmesh ${Python3_LIBRARIES})
endif(BUILD_DYNAMIC_LINK_PYTHON)
target_link_libraries(flatmesh ${MeshPart_LIBS} ${Boost_LIBRARIES})
SET_BIN_DIR(flatmesh flatmesh /Mod/MeshPart)
install(TARGETS flatmesh DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif()
endif()
endif()
endif(BUILD_FLAT_MESH)
############################################################################

View File

@@ -1,261 +0,0 @@
/***************************************************************************
* Copyright (c) 2017 Lorenz Lechner *
* *
* 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 "PreCompiled.h"
#ifndef _PreComp_
#include <TopoDS.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Face.hxx>
#include <map>
#include <memory>
#include <stdexcept>
#include <vector>
#endif
// boost is purposely not in the precompiled headers, see
// https://github.com/FreeCAD/FreeCAD/pull/7979#issuecomment-1358123252
#include <Base/Interpreter.h>
#include <Eigen/Core>
#include <Eigen/Geometry>
#include <Eigen/Sparse>
#include <Mod/Part/App/TopoShapeEdgePy.h>
#include <Mod/Part/App/TopoShapeFacePy.h>
#include <boost/python.hpp>
#include <boost/python/call.hpp>
#include <boost/python/class.hpp>
#include <boost/python/copy_const_reference.hpp>
#include <boost/python/module.hpp>
#include <boost/python/return_value_policy.hpp>
#include <boost/python/wrapper.hpp>
#include "MeshFlattening.h"
#include "MeshFlatteningLscmRelax.h"
#include "MeshFlatteningNurbs.h"
// clang-format off
namespace py = boost::python;
const TopoDS_Face& getTopoDSFace(const py::object& face)
{
if (PyObject_TypeCheck(face.ptr(), &(Part::TopoShapeFacePy::Type)))
{
const Part::TopoShapeFacePy* fpy = static_cast<Part::TopoShapeFacePy*>(face.ptr());
const TopoDS_Face& myFace = TopoDS::Face(fpy->getTopoShapePtr()->getShape());
return myFace;
}
throw std::invalid_argument("must be a face");
}
const TopoDS_Edge& getTopoDSEdge(py::object* edge)
{
if (PyObject_TypeCheck(edge->ptr(), &(Part::TopoShapeEdgePy::Type)))
{
const Part::TopoShapeEdgePy* epy = static_cast<Part::TopoShapeEdgePy*>(edge->ptr());
const TopoDS_Edge& myEdge = TopoDS::Edge(epy->getTopoShapePtr()->getShape());
return myEdge;
}
throw std::invalid_argument("must be an edge");
}
Py::Object makeEdge(const TopoDS_Edge& edge)
{
return Py::asObject(new Part::TopoShapeEdgePy(new Part::TopoShape(edge)));
}
std::shared_ptr<FaceUnwrapper> FaceUnwrapper_face(const py::object& face)
{
const TopoDS_Face& myFace = getTopoDSFace(face);
return std::make_shared<FaceUnwrapper>(myFace);
}
std::shared_ptr<FaceUnwrapper> FaceUnwrapper_mesh(const py::object& points,
const py::object& facets)
{
try {
Py::Sequence l1(points.ptr());
ColMat<double, 3> coords;
coords.resize(l1.size(), 3);
int row = 0;
for (Py::Sequence::iterator it = l1.begin(); it != l1.end(); ++it, ++row) {
Py::Sequence c(*it);
int col = 0;
for (Py::Sequence::iterator jt = c.begin(); jt != c.end(); ++jt, ++col) {
double v = static_cast<double>(Py::Float(*jt));
coords(row, col) = v;
}
}
Py::Sequence l2(facets.ptr());
ColMat<long, 3> triangles;
triangles.resize(l2.size(), 3);
row = 0;
for (Py::Sequence::iterator it = l2.begin(); it != l2.end(); ++it, ++row) {
Py::Sequence c(*it);
int col = 0;
for (Py::Sequence::iterator jt = c.begin(); jt != c.end(); ++jt, ++col) {
long v = static_cast<long>(Py::Long(*jt));
triangles(row, col) = v;
}
}
return std::shared_ptr<FaceUnwrapper>(new FaceUnwrapper(coords, triangles));
}
catch (const Py::Exception&) {
Base::PyException e;
throw std::invalid_argument(e.what());
}
}
boost::python::list interpolateFlatFacePy(FaceUnwrapper& instance, const py::object& face)
{
const TopoDS_Face& myFace = getTopoDSFace(face);
ColMat<double, 3> mat = instance.interpolateFlatFace(myFace);
boost::python::list plist;
auto cols = mat.cols();
auto rows = mat.rows();
for (int i=0; i<rows; i++) {
boost::python::list vec;
for (int j=0; j<cols; j++) {
double c = mat.coeff(i, j);
vec.append(c);
}
plist.append(vec);
}
return plist;
}
boost::python::list getFlatBoundaryNodesPy(FaceUnwrapper& instance)
{
std::vector<ColMat<double, 3>> mat_array = instance.getFlatBoundaryNodes();
boost::python::list ary;
for (auto& mat : mat_array) {
boost::python::list plist;
auto cols = mat.cols();
auto rows = mat.rows();
for (int i=0; i<rows; i++) {
boost::python::list vec;
for (int j=0; j<cols; j++) {
double c = mat.coeff(i, j);
vec.append(c);
}
plist.append(vec);
}
ary.append(plist);
}
return ary;
}
namespace fm {
// https://www.boost.org/doc/libs/1_52_0/libs/python/doc/v2/faq.html
template<typename eigen_type>
struct eigen_matrix
{
static PyObject* convert(const eigen_type& mat)
{
// <class 'numpy.array'>
py::list ary;
for (int i = 0; i < mat.rows(); i++) {
py::list row;
for (int j = 0; j < mat.cols(); j++) {
row.append(mat.coeff(i ,j));
}
ary.append(row);
}
return boost::python::incref(ary.ptr());
}
static void to_python_converter()
{
py::to_python_converter<eigen_type, eigen_matrix<eigen_type>>();
}
};
} // namespace fm
BOOST_PYTHON_MODULE(flatmesh)
{
py::class_<lscmrelax::LscmRelax>("LscmRelax")
.def(py::init<ColMat<double, 3>, ColMat<long, 3>, std::vector<long>>())
.def("lscm", &lscmrelax::LscmRelax::lscm)
.def("relax", &lscmrelax::LscmRelax::relax)
.def("rotate_by_min_bound_area", &lscmrelax::LscmRelax::rotate_by_min_bound_area)
.def("transform", &lscmrelax::LscmRelax::transform)
.def_readonly("rhs", &lscmrelax::LscmRelax::rhs)
.def_readonly("MATRIX", &lscmrelax::LscmRelax::MATRIX)
.def_readonly("area", &lscmrelax::LscmRelax::get_area)
.def_readonly("flat_area", &lscmrelax::LscmRelax::get_flat_area)
.def_readonly("flat_vertices_3D", &lscmrelax::LscmRelax::get_flat_vertices_3D);
py::class_<nurbs::NurbsBase2D>("NurbsBase2D")
.def(py::init<Eigen::VectorXd, Eigen::VectorXd, Eigen::VectorXd, int, int>())
.def_readonly("u_knots", &nurbs::NurbsBase2D::u_knots)
.def_readonly("weights", &nurbs::NurbsBase2D::weights)
.def_readonly("degree_u", &nurbs::NurbsBase2D::degree_u)
.def_readonly("degree_v", &nurbs::NurbsBase2D::degree_u)
.def("getUVMesh", &nurbs::NurbsBase2D::getUVMesh)
.def("computeFirstDerivatives", &nurbs::NurbsBase2D::computeFirstDerivatives)
.def("getInfluenceVector", &nurbs::NurbsBase2D::getInfluenceVector)
.def("getInfluenceMatrix", &nurbs::NurbsBase2D::getInfluenceMatrix)
.def("getDuVector", &nurbs::NurbsBase2D::getDuVector)
.def("getDuMatrix", &nurbs::NurbsBase2D::getDuMatrix)
.def("getDvVector", &nurbs::NurbsBase2D::getDvVector)
.def("getDvMatrix", &nurbs::NurbsBase2D::getDvMatrix)
.def("interpolateUBS", &nurbs::NurbsBase2D::interpolateUBS);
py::class_<nurbs::NurbsBase1D>("NurbsBase1D")
.def(py::init<Eigen::VectorXd, Eigen::VectorXd, int>())
.def_readonly("u_knots", &nurbs::NurbsBase1D::u_knots)
.def_readonly("weights", &nurbs::NurbsBase1D::weights)
.def_readonly("degree_u", &nurbs::NurbsBase1D::degree_u)
.def("getUMesh", &nurbs::NurbsBase1D::getUMesh)
.def("computeFirstDerivatives", &nurbs::NurbsBase1D::computeFirstDerivatives)
.def("getInfluenceVector", &nurbs::NurbsBase1D::getInfluenceVector)
.def("getInfluenceMatrix", &nurbs::NurbsBase1D::getInfluenceMatrix)
.def("getDuVector", &nurbs::NurbsBase1D::getDuVector)
.def("getDuMatrix", &nurbs::NurbsBase1D::getDuMatrix)
.add_static_property("getKnotSequence", &nurbs::NurbsBase1D::getKnotSequence)
.add_static_property("getWeightList", &nurbs::NurbsBase1D::getWeightList);
py::class_<FaceUnwrapper>("FaceUnwrapper")
.def("__init__", py::make_constructor(&FaceUnwrapper_face))
.def("__init__", py::make_constructor(&FaceUnwrapper_mesh))
.def(py::init<ColMat<double, 3>, ColMat<long, 3>>())
.def("findFlatNodes", &FaceUnwrapper::findFlatNodes)
.def("interpolateFlatFace", &interpolateFlatFacePy)
.def("getFlatBoundaryNodes", &getFlatBoundaryNodesPy)
.add_property("tris", py::make_getter(&FaceUnwrapper::tris, py::return_value_policy<py::return_by_value>()))
.add_property("nodes", py::make_getter(&FaceUnwrapper::xyz_nodes, py::return_value_policy<py::return_by_value>()))
.add_property("uv_nodes", py::make_getter(&FaceUnwrapper::uv_nodes, py::return_value_policy<py::return_by_value>()))
.add_property("ze_nodes", py::make_getter(&FaceUnwrapper::ze_nodes, py::return_value_policy<py::return_by_value>()))
.add_property("ze_poles", py::make_getter(&FaceUnwrapper::ze_poles, py::return_value_policy<py::return_by_value>()))
.add_property("A", py::make_getter(&FaceUnwrapper::A, py::return_value_policy<py::return_by_value>()));
fm::eigen_matrix<spMat>::to_python_converter();
fm::eigen_matrix<ColMat<double, 2>>::to_python_converter();
fm::eigen_matrix<ColMat<double, 3>>::to_python_converter();
fm::eigen_matrix<ColMat<long, 1>>::to_python_converter();
fm::eigen_matrix<ColMat<long, 3>>::to_python_converter();
}
// clang-format on