Skip to content

Commit

Permalink
refactor tests
Browse files Browse the repository at this point in the history
  • Loading branch information
alecjacobson committed Nov 19, 2024
1 parent 6305f70 commit 85f5d3f
Show file tree
Hide file tree
Showing 11 changed files with 766 additions and 400 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ option(LIBIGL_RESTRICTED_TRIANGLE "Build target igl_restricted::triangle" ON)
FetchContent_Declare(
libigl
GIT_REPOSITORY https://github.com/libigl/libigl.git
GIT_TAG 7326483d8dcea0169054599ae7e09917929b4b46
GIT_TAG f82ad2b463e0307c56f8101bcfe5c290c9cd30cd
)
FetchContent_MakeAvailable(libigl)

Expand Down
2 changes: 1 addition & 1 deletion src/adjacency_matrix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ R"(Constructs the adjacency matrix for a simplicial mesh.
@return A Sparse adjacency matrix of size max(F)+1 by max(F)+1)");

m.def(
"adjacency_matrix_polygon",
"adjacency_matrix",
&pyigl::adjacency_matrix_polygon,
"I"_a,
"C"_a,
Expand Down
38 changes: 38 additions & 0 deletions src/bfs_orient.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#include "default_types.h"
#include <igl/bfs_orient.h>
#include <nanobind/nanobind.h>
#include <nanobind/ndarray.h>
#include <nanobind/eigen/dense.h>
#include <nanobind/stl/tuple.h>

namespace nb = nanobind;
using namespace nb::literals;

namespace pyigl
{
auto bfs_orient(
const nb::DRef<const Eigen::MatrixXI> &F)
{
Eigen::MatrixXI FF;
Eigen::VectorXI C;
igl::bfs_orient(F,FF,C);
return std::make_tuple(FF,C);
}
}

// Bind the wrapper to the Python module
void bind_bfs_orient(nb::module_ &m)
{
m.def(
"bfs_orient",
&pyigl::bfs_orient,
"F"_a,
R"(
Consistently orient faces in orientable patches using BFS.
@param[in] F #F by 3 list of faces
@param[out] FF #F by 3 list of faces (OK if same as F)
@param[out] C #F list of component ids)"
);
}

55 changes: 55 additions & 0 deletions src/biharmonic_coordinates.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#include "default_types.h"
#include <igl/biharmonic_coordinates.h>
#include <nanobind/nanobind.h>
#include <nanobind/ndarray.h>
#include <nanobind/eigen/dense.h>
#include <nanobind/stl/tuple.h>
#include <nanobind/stl/vector.h>

namespace nb = nanobind;
using namespace nb::literals;
namespace pyigl
{
auto biharmonic_coordinates(
const nb::DRef<const Eigen::MatrixXN> &V,
const nb::DRef<const Eigen::MatrixXI> &T,
const std::vector<std::vector<Integer>> &S,
const int k)
{
Eigen::MatrixXN W;
igl::biharmonic_coordinates(V, T, S, k, W);
return W;
}
}

void bind_biharmonic_coordinates(nb::module_ &m)
{
m.def("biharmonic_coordinates", &pyigl::biharmonic_coordinates,
"V"_a,
"T"_a,
"S"_a,
"k"_a=2,
R"(Compute "discrete biharmonic generalized barycentric coordinates" as
described in "Linear Subspace Design for Real-Time Shape Deformation"
[Wang et al. 2015]. Not to be confused with "Bounded Biharmonic Weights
for Real-Time Deformation" [Jacobson et al. 2011] or "Biharmonic
Coordinates" (2D complex barycentric coordinates) [Weber et al. 2012].
These weights minimize a discrete version of the squared Laplacian energy
subject to positional interpolation constraints at selected vertices
(point handles) and transformation interpolation constraints at regions
(region handles).
@tparam SType should be a simple index type e.g. `int`,`size_t`
@param[in] V #V by dim list of mesh vertex positions
@param[in] T #T by dim+1 list of / triangle indices into V if dim=2
\ tetrahedron indices into V if dim=3
@param[in] S #point-handles+#region-handles list of lists of selected vertices for
each handle. Point handles should have singleton lists and region
handles should have lists of size at least dim+1 (and these points
should be in general position).
@param[out] W #V by #points-handles+(#region-handles * dim+1) matrix of weights so
that columns correspond to each handles generalized barycentric
coordinates (for point-handles) or animation space weights (for region
handles).
@return true only on success
)");
}
65 changes: 65 additions & 0 deletions src/bijective_composite_harmonic_mapping.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#include "default_types.h"
#include <igl/bijective_composite_harmonic_mapping.h>
#include <nanobind/nanobind.h>
#include <nanobind/ndarray.h>
#include <nanobind/eigen/dense.h>
#include <nanobind/stl/tuple.h>

namespace nb = nanobind;
using namespace nb::literals;
namespace pyigl
{
auto bijective_composite_harmonic_mapping(
const nb::DRef<const Eigen::MatrixXN> & V,
const nb::DRef<const Eigen::MatrixXI> & F,
const nb::DRef<const Eigen::VectorXI> & b,
const nb::DRef<const Eigen::MatrixXN> & bc,
const int min_steps,
const int max_steps,
const int num_inner_iters,
const bool test_for_flips)
{
Eigen::MatrixXN U;
if(!igl::bijective_composite_harmonic_mapping(V, F, b, bc, min_steps, max_steps, num_inner_iters, test_for_flips, U))
{
throw std::runtime_error("bijective_composite_harmonic_mapping failed");
}
return U;
}
}

void bind_bijective_composite_harmonic_mapping(nb::module_ &m)
{
m.def("bijective_composite_harmonic_mapping", &pyigl::bijective_composite_harmonic_mapping,
"V"_a,
"F"_a,
"b"_a,
"bc"_a,
"min_steps"_a=1,
"max_steps"_a=200,
"num_inner_iters"_a=20,
"test_for_flips"_a=true,
R"(Compute a injective planar mapping of a triangulated polygon (V,F) subjected to
boundary conditions (b,bc). The mapping should be bijective in the sense
that no triangles' areas become negative (this assumes they started
positive). This mapping is computed by "composing" harmonic mappings
between incremental morphs of the boundary conditions. This is a bit like
a discrete version of "Bijective Composite Mean Value Mappings" [Schneider
et al. 2013] but with a discrete harmonic map (cf. harmonic coordinates)
instead of mean value coordinates. This is inspired by "Embedding a
triangular graph within a given boundary" [Xu et al. 2011].
@param[in] V #V by 2 list of triangle mesh vertex positions
@param[in] F #F by 3 list of triangle indices into V
@param[in] b #b list of boundary indices into V
@param[in] bc #b by 2 list of boundary conditions corresponding to b
@param[in] min_steps minimum number of steps to take from V(b,:) to bc
@param[in] max_steps minimum number of steps to take from V(b,:) to bc (if
max_steps == min_steps then no further number of steps will be tried)
@param[in] num_inner_iters number of iterations of harmonic solves to run after
for each morph step (to try to push flips back in)
@param[in] test_for_flips whether to check if flips occurred (and trigger more
steps). if test_for_flips = false then this function always returns
true
@param[out] U #V by 2 list of output mesh vertex locations
@return true if and only if U contains a successful bijectie mapping)");
}
43 changes: 43 additions & 0 deletions src/blue_noise.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#include "default_types.h"
#include <igl/blue_noise.h>
#include <nanobind/nanobind.h>
#include <nanobind/ndarray.h>
#include <nanobind/eigen/dense.h>
#include <nanobind/stl/tuple.h>

namespace nb = nanobind;
using namespace nb::literals;
namespace pyigl
{
auto blue_noise(
const nb::DRef<const Eigen::MatrixXN> & V,
const nb::DRef<const Eigen::MatrixXI> & F,
const Numeric r)
{
Eigen::MatrixXN B;
Eigen::VectorXI FI;
Eigen::MatrixXN P;
igl::blue_noise(V, F, r, B, FI, P);
return std::make_tuple(B, FI, P);
}
}

void bind_blue_noise(nb::module_ &m)
{
m.def("blue_noise", &pyigl::blue_noise,
"V"_a,
"F"_a,
"r"_a,
R"("Fast Poisson Disk Sampling in Arbitrary Dimensions" [Bridson 2007].
For very dense samplings this is faster than (up to 2x) cyCodeBase's
implementation of "Sample Elimination for Generating Poisson Disk Sample
Sets" [Yuksel 2015]. YMMV
@param[in] V #V by dim list of mesh vertex positions
@param[in] F #F by 3 list of mesh triangle indices into rows of V
@param[in] r Poisson disk radius (evaluated according to Euclidean distance on V)
@param[out] B #P by 3 list of barycentric coordinates, ith row are coordinates of
ith sampled point in face FI(i)
@param[out] FI #P list of indices into F
@param[out] P #P by dim list of sample positions.
)");
}
2 changes: 1 addition & 1 deletion src/cotmatrix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ mesh (V,F).
@param[out] L #V by #V cotangent matrix, each row i corresponding to V(i,:))");

m.def(
"cotmatrix_polygon",
"cotmatrix",
&pyigl::cotmatrix_polygon,
"V"_a,
"I"_a,
Expand Down
31 changes: 31 additions & 0 deletions src/ears.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include "default_types.h"
#include <igl/ears.h>
#include <nanobind/nanobind.h>
#include <nanobind/ndarray.h>
#include <nanobind/eigen/dense.h>
#include <nanobind/stl/tuple.h>

namespace nb = nanobind;
using namespace nb::literals;
namespace pyigl
{
auto ears(
const nb::DRef<const Eigen::MatrixXI> & F)
{
Eigen::VectorXI ear,ear_opp;
igl::ears(F,ear,ear_opp);
return std::make_tuple(ear,ear_opp);
}
}

void bind_ears(nb::module_ &m)
{
m.def("ears", &pyigl::ears,
"F"_a,
R"(Find all ears (faces with two boundary edges) in a given mesh
@param[in] F #F by 3 list of triangle mesh indices
@param[out] ears #ears list of indices into F of ears
@param[out] ear_opp #ears list of indices indicating which edge is non-boundary
(connecting to flops))");
}
55 changes: 55 additions & 0 deletions src/split_nonmanifold.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#include "default_types.h"
#include <igl/split_nonmanifold.h>
#include <nanobind/nanobind.h>
#include <nanobind/ndarray.h>
#include <nanobind/eigen/dense.h>
#include <nanobind/stl/tuple.h>

namespace nb = nanobind;
using namespace nb::literals;
namespace pyigl
{
auto split_nonmanifold(
const nb::DRef<const Eigen::MatrixXI> & F)
{
Eigen::MatrixXI SF;
Eigen::VectorXI SVI;
igl::split_nonmanifold(F, SF, SVI);
return std::make_tuple(SF, SVI);
}
auto split_nonmanifold_VF(
const nb::DRef<const Eigen::MatrixXN> & V,
const nb::DRef<const Eigen::MatrixXI> & F)
{
Eigen::MatrixXI SF;
Eigen::MatrixXN SV;
Eigen::VectorXI SVI;
igl::split_nonmanifold(V, F, SV, SF, SVI);
return std::make_tuple(SV, SF, SVI);
}
}

void bind_split_nonmanifold(nb::module_ &m)
{
m.def("split_nonmanifold", &pyigl::split_nonmanifold,
"F"_a,
R"(Split a non-manifold (or non-orientable) mesh into a orientable manifold
mesh possibly with more connected components and geometrically duplicate
vertices.
@param[in] F #F by 3 list of mesh triangle indices into rows of some V
@param[out] SF #F by 3 list of mesh triangle indices into rows of a new vertex list
SV = V(SVI,:)
@param[out] SVI #SV list of indices into V identifying vertex positions)");
m.def("split_nonmanifold", &pyigl::split_nonmanifold_VF,
"V"_a,
"F"_a,
R"(Split a non-manifold (or non-orientable) mesh into a orientable manifold
mesh possibly with more connected components and geometrically duplicate
vertices.
@param[in] V #V by dim explicit list of vertex positions
@param[in] F #F by 3 list of mesh triangle indices into rows of some V
@param[out] SV #SV by dim explicit list of vertex positions
@param[out] SF #F by 3 list of mesh triangle indices into rows of a new vertex list
SV = V(SVI,:)
@param[out] SVI #SV list of indices into V identifying vertex positions)");
}
29 changes: 29 additions & 0 deletions src/triangle_fan.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#include "default_types.h"
#include <igl/triangle_fan.h>
#include <nanobind/nanobind.h>
#include <nanobind/ndarray.h>
#include <nanobind/eigen/dense.h>
#include <nanobind/stl/tuple.h>

namespace nb = nanobind;
using namespace nb::literals;
namespace pyigl
{
auto triangle_fan(
const nb::DRef<const Eigen::MatrixXI> & E)
{
Eigen::MatrixXI cap;
igl::triangle_fan(E, cap);
return cap;
}
}

void bind_triangle_fan(nb::module_ &m)
{
m.def("triangle_fan", &pyigl::triangle_fan,
"E"_a,
R"(Given a list of faces tessellate all of the "exterior" edges forming another
list of
@param[in] E #E by simplex_size-1 list of exterior edges (see exterior_edges.h)
@param[out] cap #cap by simplex_size list of "faces" tessellating the boundary edges)");
}
Loading

0 comments on commit 85f5d3f

Please sign in to comment.