diff --git a/CMakeLists.txt b/CMakeLists.txt index 1cdffc69..87711ecb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,6 +24,7 @@ include(CXXFeatures) set(CMAKE_POSITION_INDEPENDENT_CODE ON CACHE INTERNAL "") option(LIBIGL_COPYLEFT_CGAL "Build target igl_copyleft::cgal" ON) +option(LIBIGL_RESTRICTED_TRIANGLE "Build target igl_restricted::triangle" ON) # libigl options must come before include(PyiglDependencies) include(PyiglDependencies) if(NOT TARGET igl::core) @@ -79,14 +80,17 @@ function(pyigl_include prefix name) target_link_libraries( pyigl INTERFACE ${target_name}) endif() # https://stackoverflow.com/a/69736197/148668 + # https://cmake.org/cmake/help/latest/manual/cmake.1.html#cmdoption-cmake-E-arg-copy + # until then just needlessly also copy TARGET_FILE in case TARGET_RUNTIME_DLLS is empty if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") add_custom_command(TARGET ${target_name} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy $ $ + COMMAND ${CMAKE_COMMAND} -E copy $ $ $ COMMAND_EXPAND_LISTS) endif() endfunction() pyigl_include("copyleft" "cgal") +pyigl_include("restricted" "triangle") add_library(pyigl_classes MODULE classes/classes.cpp) diff --git a/igl/_version.py b/igl/_version.py index 8ef6ae96..78181c42 100644 --- a/igl/_version.py +++ b/igl/_version.py @@ -1 +1 @@ -__version__ = "2.5.2dev" +__version__ = "2.5.3dev" diff --git a/src/triangle/triangulate.cpp b/src/triangle/triangulate.cpp new file mode 100644 index 00000000..891aa31f --- /dev/null +++ b/src/triangle/triangulate.cpp @@ -0,0 +1,64 @@ +#include + +#include +#include + +#include + +const char* ds_triangulate = R"igl_Qu8mg5v7( +Triangulate the interior of a polygon using the triangle library. + +Parameters +---------- + V : #V by 2 list of 2D vertex positions + E : #E by 2 list of vertex ids forming unoriented edges of the boundary of the polygon + H : #H by 2 coordinates of points contained inside holes of the polygon + flags : string of options pass to triangle (see triangle documentation) +Returns +-------- + V2 #V2 by 2 coordinates of the vertives of the generated triangulation + F2 #F2 by 3 list of indices forming the faces of the generated triangulation + +)igl_Qu8mg5v7"; + +npe_function(triangulate) +npe_doc(ds_triangulate) + +npe_arg(V, dense_float, dense_double) +// remove dense_longlong when https://github.com/libigl/libigl-python-bindings/actions/runs/4152507964 gets merged +npe_arg(E, dense_int, dense_long, dense_longlong) +npe_default_arg(H, npe_matches(V) ,pybind11::array()) +npe_default_arg(flags, std::string, "") +npe_default_arg(VM, npe_matches(E), pybind11::array()) +npe_default_arg(EM, npe_matches(E), pybind11::array()) +npe_begin_code() + +EigenDenseLike V2; +EigenDenseLike F2; +EigenDenseLike VM2,E2,EM2; +using V2Type = decltype(V2); +using F2Type = decltype(F2); +using VM2Type = decltype(VM2); +using E2Type = decltype(E2); +using EM2Type = decltype(EM2); +if(VM.size() == 0 && EM.size() == 0) +{ + igl::triangle::triangulate(V, E, H, flags, V2, F2); + return std::list({npe::move(V2), npe::move(F2)}); +}else +{ + igl::triangle::triangulate(V, E, H, VM.reshaped(), EM.reshaped(), flags, V2, F2, VM2, E2, EM2); + if(VM.size() && EM.size()) + { + return std::list({npe::move(V2), npe::move(F2), npe::move(VM2), npe::move(E2), npe::move(EM2)}); + }else if(VM.size()) + { + return std::list({npe::move(V2), npe::move(F2), npe::move(VM2)}); + }else + { + return std::list({npe::move(V2), npe::move(F2), npe::move(E2), npe::move(EM2)}); + } +} + +npe_end_code() + diff --git a/tests/test_basic.py b/tests/test_basic.py index 051fb004..9c02503c 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -3,6 +3,7 @@ import platform import igl +import igl.triangle import igl.copyleft.cgal import numpy as np import scipy as sp @@ -2469,6 +2470,25 @@ def test_flip_edge(self): emap.dtype == self.f1.dtype) self.assertTrue(np.array(ue2e).dtype == self.f1.dtype) + def test_triangulate(self): + V = np.array([[0,0],[1,0],[1,1],[0,1]],dtype='float64') + E = np.array([[0,1],[1,2],[2,3],[3,0]]) + V2,F2 = igl.triangle.triangulate(V,E,flags='Q') + self.assertTrue(V2.shape == V.shape) + self.assertTrue(F2.shape == (2,3)) + V = np.array([[0,0],[4,0],[0,4],[1,1],[1,2],[2,1]],dtype='float64') + E = np.array([[0,1],[1,2],[2,0],[3,4],[4,5],[5,3]]) + H = np.array([[1.1,1.1]]) + # Markers can't be 0 + VM = 1+np.array(range(V.shape[0])) + EM = 1+np.array(range(E.shape[0])) + V2,F2,VM2,E2,EM2 = igl.triangle.triangulate(V,E,H,flags='Q',VM=VM,EM=EM) + self.assertTrue(V2.shape == V.shape) + self.assertTrue(F2.shape == (3*2,3)) + self.assertTrue(VM2.shape == VM.shape) + self.assertTrue(E2.shape == E.shape) + self.assertTrue(EM2.shape == EM.shape) + # copyleft.cgal def test_convex_hull(self): V = np.array([[0,0,0],[1,0,0],[0,1,0],[0,0,1]],dtype="float64")