From 0bdbf24334eede1ec41c2db2ef8063bc91eba010 Mon Sep 17 00:00:00 2001 From: Alec Jacobson Date: Sat, 11 Feb 2023 14:44:29 -0500 Subject: [PATCH 1/6] unfinished starter implementation --- CMakeLists.txt | 5 +++ igl/_version.py | 2 +- src/triangle/triangulate.cpp | 61 ++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 src/triangle/triangulate.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 1cdffc69..a7976bf2 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) @@ -36,6 +37,7 @@ npe_add_module(pyigl BINDING_SOURCES ${PYIGL_SOURCES}) target_link_libraries(pyigl PRIVATE igl::core) +target_compile_features(pyigl PRIVATE cxx_std_17) target_include_directories(pyigl PRIVATE "src/include") set_target_properties(pyigl PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${PYIGL_OUTPUT_DIRECTORY}" @@ -65,6 +67,7 @@ function(pyigl_include prefix name) set(target_name "pyigl${prefix_lc}_${name}") npe_add_module( ${target_name} BINDING_SOURCES ${sources}) target_link_libraries( ${target_name} PRIVATE igl::core igl${prefix_lc}::${name}) + target_compile_features( ${target_name} PRIVATE cxx_std_17) target_include_directories( ${target_name} PRIVATE "src/include") set(output_dir "${PYIGL_OUTPUT_DIRECTORY}/${subpath}") file(MAKE_DIRECTORY ${output_dir}) @@ -87,10 +90,12 @@ function(pyigl_include prefix name) endfunction() pyigl_include("copyleft" "cgal") +pyigl_include("restricted" "triangle") add_library(pyigl_classes MODULE classes/classes.cpp) target_link_libraries(pyigl_classes PRIVATE npe igl::core) +target_compile_features(pyigl_classes PRIVATE cxx_std_17) target_link_libraries(pyigl_classes PRIVATE pybind11::module) set_target_properties(pyigl_classes PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}" SUFFIX "${PYTHON_MODULE_EXTENSION}") target_include_directories(pyigl_classes PRIVATE "src/include") 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..b34350e0 --- /dev/null +++ b/src/triangle/triangulate.cpp @@ -0,0 +1,61 @@ +#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) +npe_arg(E, dense_int, dense_long) +npe_arg(H, npe_matches(V)) +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, EM, flags, V2, F2, VM2, E2, EM2); +// if(VM.size() && EM.size()) +// { +// return std::make_tuple(npe::move(V2), npe::move(F2), npe::move(VM2), npe::move(E2), npe::move(EM2)); +// }else if(VM.size()) +// { +// return std::make_tuple(npe::move(V2), npe::move(F2), npe::move(VM2)); +// }else +// { +// return std::make_tuple(npe::move(V2), npe::move(F2), npe::move(E2), npe::move(EM2)); +// } +//} + +npe_end_code() + From fb1880b37c107f752ace05f0333f929fa1cd2472 Mon Sep 17 00:00:00 2001 From: Alec Jacobson Date: Sat, 11 Feb 2023 15:22:23 -0500 Subject: [PATCH 2/6] missing pybind11/stl.h; dont need c++17; test --- CMakeLists.txt | 3 --- src/triangle/triangulate.cpp | 36 +++++++++++++++++++----------------- tests/test_basic.py | 21 +++++++++++++++++++++ 3 files changed, 40 insertions(+), 20 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a7976bf2..5491100b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,7 +37,6 @@ npe_add_module(pyigl BINDING_SOURCES ${PYIGL_SOURCES}) target_link_libraries(pyigl PRIVATE igl::core) -target_compile_features(pyigl PRIVATE cxx_std_17) target_include_directories(pyigl PRIVATE "src/include") set_target_properties(pyigl PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${PYIGL_OUTPUT_DIRECTORY}" @@ -67,7 +66,6 @@ function(pyigl_include prefix name) set(target_name "pyigl${prefix_lc}_${name}") npe_add_module( ${target_name} BINDING_SOURCES ${sources}) target_link_libraries( ${target_name} PRIVATE igl::core igl${prefix_lc}::${name}) - target_compile_features( ${target_name} PRIVATE cxx_std_17) target_include_directories( ${target_name} PRIVATE "src/include") set(output_dir "${PYIGL_OUTPUT_DIRECTORY}/${subpath}") file(MAKE_DIRECTORY ${output_dir}) @@ -95,7 +93,6 @@ pyigl_include("restricted" "triangle") add_library(pyigl_classes MODULE classes/classes.cpp) target_link_libraries(pyigl_classes PRIVATE npe igl::core) -target_compile_features(pyigl_classes PRIVATE cxx_std_17) target_link_libraries(pyigl_classes PRIVATE pybind11::module) set_target_properties(pyigl_classes PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}" SUFFIX "${PYTHON_MODULE_EXTENSION}") target_include_directories(pyigl_classes PRIVATE "src/include") diff --git a/src/triangle/triangulate.cpp b/src/triangle/triangulate.cpp index b34350e0..34a10ea0 100644 --- a/src/triangle/triangulate.cpp +++ b/src/triangle/triangulate.cpp @@ -1,3 +1,5 @@ +#include + #include #include @@ -24,7 +26,7 @@ npe_doc(ds_triangulate) npe_arg(V, dense_float, dense_double) npe_arg(E, dense_int, dense_long) -npe_arg(H, npe_matches(V)) +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()) @@ -38,24 +40,24 @@ using F2Type = decltype(F2); using VM2Type = decltype(VM2); using E2Type = decltype(E2); using EM2Type = decltype(EM2); -//if(VM.size() == 0 && EM.size() == 0) -//{ +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, EM, flags, V2, F2, VM2, E2, EM2); -// if(VM.size() && EM.size()) -// { -// return std::make_tuple(npe::move(V2), npe::move(F2), npe::move(VM2), npe::move(E2), npe::move(EM2)); -// }else if(VM.size()) -// { -// return std::make_tuple(npe::move(V2), npe::move(F2), npe::move(VM2)); -// }else -// { -// return std::make_tuple(npe::move(V2), npe::move(F2), npe::move(E2), npe::move(EM2)); -// } -//} +}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 1aa0b59a..af7da3a6 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -3,6 +3,7 @@ import platform import igl +import igl.triangle import numpy as np import scipy as sp import scipy.sparse as csc @@ -2468,5 +2469,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) + + if __name__ == '__main__': unittest.main() From 5f44f132333a81a188ca919129ef148ca2c5c610 Mon Sep 17 00:00:00 2001 From: Alec Jacobson Date: Sat, 11 Feb 2023 16:00:54 -0500 Subject: [PATCH 3/6] restore longlong --- src/triangle/triangulate.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/triangle/triangulate.cpp b/src/triangle/triangulate.cpp index 34a10ea0..891aa31f 100644 --- a/src/triangle/triangulate.cpp +++ b/src/triangle/triangulate.cpp @@ -25,7 +25,8 @@ npe_function(triangulate) npe_doc(ds_triangulate) npe_arg(V, dense_float, dense_double) -npe_arg(E, dense_int, dense_long) +// 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()) From 21dbcbcbb2df57fa4d2344dad962a0bfcce1572d Mon Sep 17 00:00:00 2001 From: Alec Jacobson Date: Sat, 11 Feb 2023 18:39:11 -0500 Subject: [PATCH 4/6] not sure why test is failing on CI, verbose output --- tests/test_basic.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/test_basic.py b/tests/test_basic.py index af7da3a6..76259677 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -2481,8 +2481,10 @@ def test_triangulate(self): # 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) + V2,F2,VM2,E2,EM2 = igl.triangle.triangulate(V,E,H,flags='',VM=VM,EM=EM) self.assertTrue(V2.shape == V.shape) + print(V2) + print(F2) self.assertTrue(F2.shape == (3*2,3)) self.assertTrue(VM2.shape == VM.shape) self.assertTrue(E2.shape == E.shape) From a66712ffe7cb20ad459a2c73516f5b3372bbf7c9 Mon Sep 17 00:00:00 2001 From: Alec Jacobson Date: Sat, 11 Feb 2023 19:16:17 -0500 Subject: [PATCH 5/6] subtle bug in test --- tests/test_basic.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/test_basic.py b/tests/test_basic.py index 76259677..3d7e1df5 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -2477,14 +2477,12 @@ def test_triangulate(self): 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]) + 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='',VM=VM,EM=EM) + V2,F2,VM2,E2,EM2 = igl.triangle.triangulate(V,E,H,flags='Q',VM=VM,EM=EM) self.assertTrue(V2.shape == V.shape) - print(V2) - print(F2) self.assertTrue(F2.shape == (3*2,3)) self.assertTrue(VM2.shape == VM.shape) self.assertTrue(E2.shape == E.shape) From 45c74c8a96c80fd57e47bbfd2826a6c701f0613e Mon Sep 17 00:00:00 2001 From: Alec Jacobson Date: Sat, 11 Feb 2023 21:53:58 -0500 Subject: [PATCH 6/6] fix empty dll string --- CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5491100b..87711ecb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,9 +80,11 @@ 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()