diff --git a/CMakeLists.txt b/CMakeLists.txt index 5155e2ce3780c55db19e9f16524bfd67b0f2e4a2..c4b99ebbf576293dbdd67d0adec828d2e47b07a7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,7 @@ project( # scikit-build-core's built-in backport) find_package(Python REQUIRED COMPONENTS Interpreter Development.Module) find_package(pybind11 CONFIG REQUIRED) +find_package(CGAL REQUIRED COMPONENTS ImageIO) # Add a library using FindPython's tooling (pybind11 also provides a helper like # this) @@ -22,5 +23,10 @@ target_link_libraries(_core PRIVATE pybind11::headers) # This is passing in the version as a define just as an example target_compile_definitions(_core PRIVATE VERSION_INFO=${PROJECT_VERSION}) +python_add_library(_cgal MODULE src/cgal_example.cpp WITH_SOABI) +target_link_libraries(_cgal PRIVATE pybind11::headers) +target_link_libraries(_cgal PRIVATE CGAL::CGAL) + # The install directory is the output (wheel) directory install(TARGETS _core DESTINATION pybind_example) +install(TARGETS _cgal DESTINATION pybind_example) diff --git a/pyproject.toml b/pyproject.toml index e5d7fd4e666d0355bd197231c7132a0f9016ecec..d32dfa001876704c70defcf51cf77f01a4d93e29 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,6 +29,8 @@ test = ["pytest"] [tool.scikit-build] +cmake.verbose = true +logging.level = "INFO" wheel.expand-macos-universal-tags = true diff --git a/src/cgal_example.cpp b/src/cgal_example.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7ef74d353a13baf084afc4d80bf813950720d044 --- /dev/null +++ b/src/cgal_example.cpp @@ -0,0 +1,77 @@ +#include <CGAL/Exact_predicates_inexact_constructions_kernel.h> + +#include <CGAL/Mesh_triangulation_3.h> +#include <CGAL/Mesh_complex_3_in_triangulation_3.h> +#include <CGAL/Mesh_criteria_3.h> + +#include <CGAL/Labeled_image_mesh_domain_3.h> +#include <CGAL/make_mesh_3.h> +#include <CGAL/Image_3.h> + +#include <CGAL/ImageIO.h> + +#include <pybind11/pybind11.h> +#include <pybind11/stl.h> // This header is needed to work with STL containers like std::vector + +// Domain +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; +typedef CGAL::Labeled_mesh_domain_3<K> Mesh_domain; + +// Triangulation +typedef CGAL::Mesh_triangulation_3<Mesh_domain, CGAL::Default, CGAL::Sequential_tag>::type Tr; +typedef CGAL::Mesh_complex_3_in_triangulation_3<Tr> C3t3; + +// Criteria +typedef CGAL::Mesh_criteria_3<Tr> Mesh_criteria; + + +int cgalMesh3DImage(const std::string& image_filename, const std::string& mesh_filename) +{ + CGAL::Image_3 image; + if(!image.read(image_filename)){ + std::cerr << "Error: Cannot read file " << image_filename << std::endl; + return EXIT_FAILURE; + } + Mesh_domain domain = Mesh_domain::create_labeled_image_mesh_domain(image); + + // Mesh criteria + auto params = CGAL::parameters::facet_angle(30); + params.facet_size(6); + params.facet_distance(4); + params.cell_radius_edge_ratio(3); + params.cell_size(8); + Mesh_criteria criteria(params); + + C3t3 c3t3 = CGAL::make_mesh_3<C3t3>(domain, criteria); + + // Output + std::ofstream medit_file(mesh_filename); + CGAL::IO::write_MEDIT(medit_file, c3t3); + medit_file.close(); + return 0; +} + + +namespace py = pybind11; + +PYBIND11_MODULE(_cgal, m) { + m.doc() = R"pbdoc( + CGAL example function + --------------------- + + .. currentmodule:: pybind_example.cgal + + .. autosummary:: + :toctree: _generate + + add + subtract + )pbdoc"; + + m.def("mesh_3d_image", &cgalMesh3DImage, R"pbdoc( + Domains From Segmented 3D Images + + The function produces a 3D mesh from a 3D image. + )pbdoc", py::arg("image_filename"), py::arg("mesh_filename")); + +} diff --git a/src/pybind_example/cgal.py b/src/pybind_example/cgal.py new file mode 100644 index 0000000000000000000000000000000000000000..c75eae244710b9ec3c2c838992c3c4104bebf921 --- /dev/null +++ b/src/pybind_example/cgal.py @@ -0,0 +1,8 @@ +from __future__ import annotations + +from ._cgal import __doc__, mesh_3d_image + +__all__ = [ + "__doc__", + "mesh_3d_image" +] diff --git a/tests/test_cgal.py b/tests/test_cgal.py new file mode 100644 index 0000000000000000000000000000000000000000..95372164deb10987e1a5cd7d72e0bb497ab5590b --- /dev/null +++ b/tests/test_cgal.py @@ -0,0 +1,23 @@ +import unittest +import tempfile +import os + +from pybind_example.cgal import mesh_3d_image + + +class TestCgalMesh(unittest.TestCase): + + def setUp(self): + self.image_filename = tempfile.mktemp(suffix=".inr.gz") + self.mesh_filename = tempfile.mktemp(suffix=".medit") + + def tearDown(self): + if os.path.exists(self.image_filename): + os.remove(self.image_filename) + if os.path.exists(self.mesh_filename): + os.remove(self.mesh_filename) + + def test_tissue_image_surface_topomesh(self): + res = mesh_3d_image(self.image_filename, self.mesh_filename) + assert res == 1 # should not work for now, test that it fails + assert not os.path.exists(self.mesh_filename)