Skip to content

Commit

Permalink
intrinsic stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
alecjacobson committed Nov 18, 2024
1 parent 62183ed commit 6305f70
Show file tree
Hide file tree
Showing 10 changed files with 366 additions and 15 deletions.
20 changes: 20 additions & 0 deletions src/MassMatrixType.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#include "default_types.h"
#include <igl/massmatrix.h>
#include <nanobind/nanobind.h>
#include <nanobind/ndarray.h>
#include <nanobind/eigen/dense.h>

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


void bind_MassMatrixType(nb::module_ &m)
{
nb::enum_<igl::MassMatrixType>(m, "MassMatrixType")
.value("MASSMATRIX_TYPE_BARYCENTRIC", igl::MASSMATRIX_TYPE_BARYCENTRIC)
.value("MASSMATRIX_TYPE_VORONOI", igl::MASSMATRIX_TYPE_VORONOI)
.value("MASSMATRIX_TYPE_FULL", igl::MASSMATRIX_TYPE_FULL)
.value("MASSMATRIX_TYPE_DEFAULT", igl::MASSMATRIX_TYPE_DEFAULT)
.export_values()
;
}
43 changes: 43 additions & 0 deletions src/cotmatrix_intrinsic.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#include "default_types.h"
#include <igl/cotmatrix_intrinsic.h>
#include <nanobind/nanobind.h>
#include <nanobind/ndarray.h>
#include <nanobind/eigen/dense.h>
#include <nanobind/eigen/sparse.h>
#include <nanobind/stl/tuple.h>

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

namespace pyigl
{
auto cotmatrix_intrinsic(
const nb::DRef<const Eigen::MatrixXN> &l,
const nb::DRef<const Eigen::MatrixXI> &F)
{
Eigen::SparseMatrixN L;
igl::cotmatrix_intrinsic(l,F,L);
return L;
}
}

// Bind the wrapper to the Python module
void bind_cotmatrix_intrinsic(nb::module_ &m)
{
m.def(
"cotmatrix_intrinsic",
&pyigl::cotmatrix_intrinsic,
"l"_a,
"F"_a,
R"(
Constructs the cotangent stiffness matrix (discrete laplacian) for a given
mesh with faces F and edge lengths l.
@param[in] l #F by 3 list of (half-)edge lengths
@param[in] F #F by 3 list of face indices into some (not necessarily
determined/embedable) list of vertex positions V. It is assumed #V ==
F.maxCoeff()+1
@param[out] L #V by #V sparse Laplacian matrix
\see cotmatrix, intrinsic_delaunay_cotmatrix)");
}
89 changes: 89 additions & 0 deletions src/heat_geodesics.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#include "default_types.h"
#include <igl/heat_geodesics.h>
#include <nanobind/nanobind.h>
#include <nanobind/ndarray.h>
#include <nanobind/eigen/dense.h>
#include <nanobind/eigen/sparse.h>

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

namespace pyigl
{
void heat_geodesics_precompute_t(
const nb::DRef<const Eigen::MatrixXN> &V,
const nb::DRef<const Eigen::MatrixXI> &F,
const Numeric t,
igl::HeatGeodesicsData<Numeric> &data)
{
if(!igl::heat_geodesics_precompute(V,F,t,data))
{
throw std::runtime_error("heat_geodesics: Precomputation failed.");
}
}
// Obnoxious way to have optional t
void heat_geodesics_precompute(
const nb::DRef<const Eigen::MatrixXN> &V,
const nb::DRef<const Eigen::MatrixXI> &F,
igl::HeatGeodesicsData<Numeric> &data)
{
if(!igl::heat_geodesics_precompute(V,F,data))
{
throw std::runtime_error("heat_geodesics: Precomputation failed.");
}
}

auto heat_geodesics_solve(
const igl::HeatGeodesicsData<Numeric> &data,
const nb::DRef<const Eigen::VectorXI> &gamma)
{
Eigen::VectorXN D;
igl::heat_geodesics_solve(data, gamma, D);
return D;
}

}

// Bind the wrapper to the Python module
void bind_heat_geodesics(nb::module_ &m)
{
nb::class_<igl::HeatGeodesicsData<Numeric>>(m, "HeatGeodesicsData")
.def(nb::init<>())
.def_rw("use_intrinsic_delaunay", &igl::HeatGeodesicsData<Numeric>::use_intrinsic_delaunay)
;

m.def("heat_geodesics_precompute",
&pyigl::heat_geodesics_precompute_t,
"V"_a, "F"_a, "t"_a, "data"_a,
R"(Precompute factorized solvers for computing a fast approximation of
geodesic distances on a mesh (V,F). [Crane et al. 2013]
@param[in] V #V by dim list of mesh vertex positions
@param[in] F #F by 3 list of mesh face indices into V
@param[in] t "heat" parameter (smaller --> more accurate, less stable)
@param[out] data precomputation data (see heat_geodesics_solve)
)");
m.def("heat_geodesics_precompute",
&pyigl::heat_geodesics_precompute,
"V"_a, "F"_a, "data"_a,
R"(Precompute factorized solvers for computing a fast approximation of
geodesic distances on a mesh (V,F). [Crane et al. 2013]
@param[in] V #V by dim list of mesh vertex positions
@param[in] F #F by 3 list of mesh face indices into V
@param[out] data precomputation data (see heat_geodesics_solve)
)");
m.def("heat_geodesics_solve",
&pyigl::heat_geodesics_solve,
"data"_a,
"gamma"_a,
R"(Compute fast approximate geodesic distances using precomputed data from a
set of selected source vertices (gamma).
@param[in] data precomputation data (see heat_geodesics_precompute)
@param[in] gamma #gamma list of indices into V of source vertices
@param[out] D #V list of distances to gamma
\fileinfo
)");
}
35 changes: 35 additions & 0 deletions src/icosahedron.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#include "default_types.h"
#include <igl/icosahedron.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 icosahedron()
{
Eigen::MatrixXN V;
Eigen::MatrixXI F;
igl::icosahedron(V,F);
return std::make_tuple(V,F);
}
}

// Bind the wrapper to the Python module
void bind_icosahedron(nb::module_ &m)
{
m.def(
"icosahedron",
&pyigl::icosahedron,
R"(
Construct a icosahedron with radius 1 centered at the origin
Outputs:
V #V by 3 list of vertex positions
F #F by 3 list of triangle indices into rows of V)");
}

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

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

namespace pyigl
{
auto intrinsic_delaunay_cotmatrix(
const nb::DRef<const Eigen::MatrixXN> &V,
const nb::DRef<const Eigen::MatrixXI> &F)
{
Eigen::SparseMatrixN L;
Eigen::MatrixXN il;
Eigen::MatrixXI iF;
igl::intrinsic_delaunay_cotmatrix(V,F,L,il,iF);
return std::make_tuple(L,il,iF);
}
}

// Bind the wrapper to the Python module
void bind_intrinsic_delaunay_cotmatrix(nb::module_ &m)
{
m.def(
"intrinsic_delaunay_cotmatrix",
&pyigl::intrinsic_delaunay_cotmatrix,
"V"_a,
"F"_a,
R"(
Computes the discrete cotangent Laplacian of a mesh after converting it
into its intrinsic Delaunay triangulation (see, e.g., [Fisher et al.
2007].
@param[in] V #V by dim list of mesh vertex positions
@param[in] F #F by 3 list of mesh elements (triangles or tetrahedra)
@param[out] L #V by #V cotangent matrix, each row i corresponding to V(i,:)
@param[out] l_intrinsic #F by 3 list of intrinsic edge-lengths used to compute L
@param[out] F_intrinsic #F by 3 list of intrinsic face indices used to compute L
\see intrinsic_delaunay_triangulation, cotmatrix, cotmatrix_intrinsic)");
}
63 changes: 63 additions & 0 deletions src/intrinsic_delaunay_triangulation.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#include "default_types.h"
#include <igl/intrinsic_delaunay_triangulation.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 intrinsic_delaunay_triangulation(
const nb::DRef<const Eigen::MatrixXN> &l_in,
const nb::DRef<const Eigen::MatrixXI> &F_in)
{
Eigen::MatrixXN l;
Eigen::MatrixXI F,E,uE;
Eigen::VectorXI EMAP;
std::vector<std::vector<Integer> > uE2E;
igl::intrinsic_delaunay_triangulation(l_in,F_in,l,F,E,uE,EMAP,uE2E);
return std::make_tuple(l,F,E,uE,EMAP,uE2E);

}
}

// Bind the wrapper to the Python module
void bind_intrinsic_delaunay_triangulation(nb::module_ &m)
{
m.def(
"intrinsic_delaunay_triangulation",
&pyigl::intrinsic_delaunay_triangulation,
"l"_a,
"F"_a,
R"(
INTRINSIC_DELAUNAY_TRIANGULATION Flip edges _intrinsically_ until all are
"intrinsic Delaunay". See "An algorithm for the construction of intrinsic
delaunay triangulations with applications to digital geometry processing"
[Fisher et al. 2007].
@param[in] l_in #F_in by 3 list of edge lengths (see edge_lengths)
@param[in] F_in #F_in by 3 list of face indices into some unspecified vertex list V
@param[out] l #F by 3 list of edge lengths
@param[out] F #F by 3 list of new face indices. Note: Combinatorially F may contain
non-manifold edges, duplicate faces and self-loops (e.g., an edge [1,1]
or a face [1,1,1]). However, the *intrinsic geometry* is still
well-defined and correct. See [Fisher et al. 2007] Figure 3 and 2nd to
last paragraph of 1st page. Since F may be "non-eddge-manifold" in the
usual combinatorial sense, it may be useful to call the more verbose
overload below if disentangling edges will be necessary later on.
Calling unique_edge_map on this F will give a _different_ result than
those outputs.
@param[out] E #F*3 by 2 list of all directed edges, such that E.row(f+#F*c) is the
@param[out] edge opposite F(f,c)
@param[out] uE #uE by 2 list of unique undirected edges
@param[out] EMAP #F*3 list of indices into uE, mapping each directed edge to unique
@param[out] undirected edge
@param[out] uE2E #uE list of lists of indices into E of coexisting edges
\see unique_edge_map
)");
}
7 changes: 0 additions & 7 deletions src/massmatrix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,6 @@ namespace pyigl
// Bind the wrapper to the Python module
void bind_massmatrix(nb::module_ &m)
{
nb::enum_<igl::MassMatrixType>(m, "MassMatrixType")
.value("MASSMATRIX_TYPE_BARYCENTRIC", igl::MASSMATRIX_TYPE_BARYCENTRIC)
.value("MASSMATRIX_TYPE_VORONOI", igl::MASSMATRIX_TYPE_VORONOI)
.value("MASSMATRIX_TYPE_FULL", igl::MASSMATRIX_TYPE_FULL)
.value("MASSMATRIX_TYPE_DEFAULT", igl::MASSMATRIX_TYPE_DEFAULT)
.export_values()
;
m.def(
"massmatrix",
&pyigl::massmatrix,
Expand Down
45 changes: 45 additions & 0 deletions src/massmatrix_intrinsic.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#include "default_types.h"
#include <igl/massmatrix_intrinsic.h>
#include <nanobind/nanobind.h>
#include <nanobind/ndarray.h>
#include <nanobind/eigen/dense.h>
#include <nanobind/eigen/sparse.h>
#include <nanobind/stl/tuple.h>

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

namespace pyigl
{
auto massmatrix_intrinsic(
const nb::DRef<const Eigen::MatrixXN> &l,
const nb::DRef<const Eigen::MatrixXI> &F,
const igl::MassMatrixType type)
{
Eigen::SparseMatrixN M;
igl::massmatrix_intrinsic(l,F,type,M);
return M;
}
}

// Bind the wrapper to the Python module
void bind_massmatrix_intrinsic(nb::module_ &m)
{
m.def(
"massmatrix_intrinsic",
&pyigl::massmatrix_intrinsic,
"l"_a,
"F"_a,
"type"_a=igl::MASSMATRIX_TYPE_DEFAULT,
R"(
Constructs the mass matrix for a given
mesh with faces F and edge lengths l.
@param[in] l #F by 3 list of (half-)edge lengths
@param[in] F #F by 3 list of face indices into some (not necessarily
determined/embedable) list of vertex positions V. It is assumed #V ==
F.maxCoeff()+1
@param[out] L #V by #V sparse Laplacian matrix
\see massmatrix, intrinsic_delaunay_massmatrix)");
}
14 changes: 7 additions & 7 deletions src/matlab_format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,13 @@ void bind_matlab_format(nb::module_ &m)
"name"_a = "",
R"(Format a dense matrix for MATLAB-style output.)");

m.def(
"matlab_format",
&pyigl::matlab_format_dense_vector,
"M"_a,
"name"_a = "",
R"(Format a dense matrix for MATLAB-style output.)");

m.def(
"matlab_format",
&pyigl::matlab_format_sparse,
Expand All @@ -77,13 +84,6 @@ void bind_matlab_format(nb::module_ &m)
"name"_a = "",
R"(Format a matrix for MATLAB-style output with 1-based indexing.)");

m.def(
"matlab_format",
&pyigl::matlab_format_dense_vector,
"M"_a,
"name"_a = "",
R"(Format a dense matrix for MATLAB-style output.)");

m.def(
"matlab_format_index",
&pyigl::matlab_format_index_vector,
Expand Down
Loading

0 comments on commit 6305f70

Please sign in to comment.