Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ jobs:
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install cibuildwheel==2.23.0
- run: pip install cibuildwheel==3.1.4
- name: Build wheels
run: python -m cibuildwheel --output-dir wheelhouse
env:
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,9 @@ A successful [.github/workflows/wheels.yml](.github/workflows/wheels.yml) run wi

Then these can be uploaded to pypi using:

python -m twine upload --repository testpypi wheelhouse/*/*.whl wheelhouse/*/*.tar.gz
for f in wheelhouse/*/*.whl wheelhouse/*/*.tar.gz; do
python3 -m twine upload --repository pypi "$f" || echo "Skipping failed upload: $f"
done

## Acknowledgements

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ build-backend = "scikit_build_core.build"

[project]
name = "libigl"
version = "2.6.3.dev0"
version = "2.6.3.dev2"
description = "libigl: A simple C++ geometry processing library"
readme = "README.md"
requires-python = ">=3.8"
Expand Down
48 changes: 48 additions & 0 deletions src/accumarray.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#include "default_types.h"
#include <igl/accumarray.h>
#include <nanobind/nanobind.h>
#include <nanobind/eigen/dense.h>

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

namespace pyigl
{
auto accumarray_V(
const nb::DRef<const Eigen::MatrixXI> &S,
const nb::DRef<const Eigen::MatrixXN> &V)
{
// Copy to compact column vectors so single-index (i) access works
const Eigen::VectorXI s = S.reshaped();
const Eigen::VectorXN v = V.reshaped();
Eigen::VectorXN A;
igl::accumarray(s, v, A);
return A;
}
auto accumarray_val(
const nb::DRef<const Eigen::MatrixXI> &S,
const Numeric val)
{
const Eigen::VectorXI s = S.reshaped();
Eigen::VectorXN A;
igl::accumarray(s, val, A);
return A;
}
}

void bind_accumarray(nb::module_ &m)
{
m.def("accumarray", &pyigl::accumarray_V, "S"_a, "V"_a,
R"(Accumulate values V at subscripts S. Like MATLAB's accumarray.

@param[in] S #S list of subscripts (integer indices)
@param[in] V #S list of values
@return A max(S)+1 list of accumulated (summed) values)");

m.def("accumarray", &pyigl::accumarray_val, "S"_a, "val"_a,
R"(Accumulate a constant value at subscripts S. Like MATLAB's accumarray.

@param[in] S #S list of subscripts (integer indices)
@param[in] val scalar value to accumulate at each subscript
@return A max(S)+1 list of accumulated (summed) values)");
}
36 changes: 36 additions & 0 deletions src/barycentric_interpolation.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#include "default_types.h"
#include <igl/barycentric_interpolation.h>
#include <nanobind/nanobind.h>
#include <nanobind/eigen/dense.h>

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

namespace pyigl
{
auto barycentric_interpolation(
const nb::DRef<const Eigen::MatrixXN> &D,
const nb::DRef<const Eigen::MatrixXI> &F,
const nb::DRef<const Eigen::MatrixXN> &B,
const nb::DRef<const Eigen::MatrixXI> &I)
{
// I is indexed as a vector internally
const Eigen::VectorXI idx = I.reshaped();
Eigen::MatrixXN X;
igl::barycentric_interpolation(D, F, B, idx, X);
return X;
}
}

void bind_barycentric_interpolation(nb::module_ &m)
{
m.def("barycentric_interpolation", &pyigl::barycentric_interpolation,
"D"_a, "F"_a, "B"_a, "I"_a,
R"(Interpolate per-vertex data on a triangle mesh using barycentric coordinates.

@param[in] D #V by dim list of per-vertex data
@param[in] F #F by 3 list of triangle indices
@param[in] B #X by 3 list of barycentric coordinates
@param[in] I #X list of triangle indices into F
@return X #X by dim list of interpolated data)");
}
48 changes: 48 additions & 0 deletions src/bezier.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#include "default_types.h"
#include <igl/bezier.h>
#include <nanobind/nanobind.h>
#include <nanobind/eigen/dense.h>

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

namespace pyigl
{
// Single parameter t
auto bezier_t(
const nb::DRef<const Eigen::MatrixXN> &V,
const Numeric t)
{
Eigen::MatrixXN P;
igl::bezier(V, t, P);
return P;
}
// Array of parameters T
auto bezier_T(
const nb::DRef<const Eigen::MatrixXN> &V,
const nb::DRef<const Eigen::MatrixXN> &T)
{
// Copy T to compact vector for single-index access
const Eigen::VectorXN t = T.reshaped();
Eigen::MatrixXN P;
igl::bezier(V, t, P);
return P;
}
}

void bind_bezier(nb::module_ &m)
{
m.def("bezier", &pyigl::bezier_t, "V"_a, "t"_a,
R"(Evaluate a polynomial Bezier curve at a single parameter value.

@param[in] V #V by dim list of Bezier control points
@param[in] t evaluation parameter in [0,1]
@return P 1 by dim output point)");

m.def("bezier", &pyigl::bezier_T, "V"_a, "T"_a,
R"(Evaluate a polynomial Bezier curve at many parameter values.

@param[in] V #V by dim list of Bezier control points
@param[in] T #T list of evaluation parameters in [0,1]
@return P #T by dim output points)");
}
62 changes: 62 additions & 0 deletions src/colormap.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#include "default_types.h"
#include <igl/colormap.h>
#include <nanobind/nanobind.h>
#include <nanobind/eigen/dense.h>

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

namespace pyigl
{
// Map scalar array to RGB colors using a colormap
auto colormap(
const igl::ColorMapType cm,
const nb::DRef<const Eigen::VectorXN> &Z,
const bool normalize)
{
Eigen::MatrixXN C;
igl::colormap(cm, Z, normalize, C);
return C;
}
// Map scalar to single RGB triple
auto colormap_scalar(
const igl::ColorMapType cm,
const Numeric f)
{
Numeric r, g, b;
igl::colormap(cm, f, r, g, b);
Eigen::Vector3d rgb;
rgb << r, g, b;
return rgb;
}
}

void bind_colormap(nb::module_ &m)
{
nb::enum_<igl::ColorMapType>(m, "ColorMapType")
.value("INFERNO", igl::COLOR_MAP_TYPE_INFERNO)
.value("JET", igl::COLOR_MAP_TYPE_JET)
.value("MAGMA", igl::COLOR_MAP_TYPE_MAGMA)
.value("PARULA", igl::COLOR_MAP_TYPE_PARULA)
.value("PLASMA", igl::COLOR_MAP_TYPE_PLASMA)
.value("VIRIDIS", igl::COLOR_MAP_TYPE_VIRIDIS)
.value("TURBO", igl::COLOR_MAP_TYPE_TURBO)
.export_values();

m.def("colormap", &pyigl::colormap,
"cm"_a, "Z"_a, "normalize"_a = true,
R"(Map scalar values to RGB colors using a colormap.

@param[in] cm colormap type (igl.ColorMapType.VIRIDIS, .JET, etc.)
@param[in] Z #Z list of scalar values
@param[in] normalize if true, normalize Z to [0,1] range before mapping
@return C #Z by 3 list of RGB colors in [0,1])");

m.def("colormap", &pyigl::colormap_scalar,
"cm"_a, "f"_a,
R"(Map a single scalar in [0,1] to an RGB color.

@param[in] cm colormap type
@param[in] f scalar in [0,1]
@return 3-vector of RGB values in [0,1])");
}
33 changes: 33 additions & 0 deletions src/combine.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#include "default_types.h"
#include <igl/combine.h>
#include <nanobind/nanobind.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 combine(
const std::vector<Eigen::MatrixXN> &VV,
const std::vector<Eigen::MatrixXI> &FF)
{
Eigen::MatrixXN V;
Eigen::MatrixXI F;
igl::combine(VV, FF, V, F);
return std::make_tuple(V, F);
}
}

void bind_combine(nb::module_ &m)
{
m.def("combine", &pyigl::combine, "VV"_a, "FF"_a,
R"(Concatenate multiple meshes into a single mesh.

@param[in] VV list of vertex position matrices, each #Vi by dim
@param[in] FF list of face index matrices, each #Fi by simplex_size
@return V concatenated vertex positions
@return F concatenated face indices (reindexed into V))");
}
24 changes: 24 additions & 0 deletions src/copyleft/cgal/coplanar.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#include "default_types.h"
#include <igl/copyleft/cgal/coplanar.h>
#include <nanobind/nanobind.h>
#include <nanobind/eigen/dense.h>

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

namespace pyigl
{
bool coplanar(const nb::DRef<const Eigen::MatrixXN> &V)
{
return igl::copyleft::cgal::coplanar(V);
}
}

void bind_coplanar(nb::module_ &m)
{
m.def("coplanar", &pyigl::coplanar, "V"_a,
R"(Test whether all points lie on the same plane.

@param[in] V #V by 3 list of 3D vertex positions
@return true if all points are coplanar)");
}
26 changes: 26 additions & 0 deletions src/copyleft/cgal/delaunay_triangulation.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#include "default_types.h"
#include <igl/copyleft/cgal/delaunay_triangulation.h>
#include <nanobind/nanobind.h>
#include <nanobind/eigen/dense.h>

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

namespace pyigl
{
auto delaunay_triangulation(const nb::DRef<const Eigen::MatrixXN> &V)
{
Eigen::MatrixXi F; // int32 required by libigl internals
igl::copyleft::cgal::delaunay_triangulation(V, F);
return Eigen::MatrixXI(F.cast<Integer>());
}
}

void bind_delaunay_triangulation(nb::module_ &m)
{
m.def("delaunay_triangulation", &pyigl::delaunay_triangulation, "V"_a,
R"(Compute the Delaunay triangulation of a 2D point set using CGAL.

@param[in] V #V by 2 list of 2D vertex positions
@return F #F by 3 triangle indices into V)");
}
35 changes: 35 additions & 0 deletions src/copyleft/cgal/extract_cells.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#include "default_types.h"
#include <igl/copyleft/cgal/extract_cells.h>
#include <nanobind/nanobind.h>
#include <nanobind/eigen/dense.h>
#include <nanobind/stl/tuple.h>

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

namespace pyigl
{
auto extract_cells(
const nb::DRef<const Eigen::MatrixXN> &V,
const nb::DRef<const Eigen::MatrixXI> &F)
{
// int32 required by libigl internals (static_assert checks index type)
Eigen::MatrixXi Fi = F.cast<int>();
Eigen::MatrixXi cells;
size_t n = igl::copyleft::cgal::extract_cells(V, Fi, cells);
return std::make_tuple((Integer)n, Eigen::MatrixXI(cells.cast<Integer>()));
}
}

void bind_extract_cells(nb::module_ &m)
{
m.def("extract_cells", &pyigl::extract_cells, "V"_a, "F"_a,
R"(Extract connected 3D cells partitioned by a triangle mesh.

@param[in] V #V by 3 array of vertices
@param[in] F #F by 3 array of triangle indices
@return tuple (num_cells, cells):
- num_cells number of cells (cell 0 is the infinite outer cell)
- cells #F by 2 array of cell indices; cells[i,0] is the cell on the
positive side of face i, cells[i,1] is on the negative side)");
}
42 changes: 42 additions & 0 deletions src/copyleft/cgal/outer_hull.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#include "default_types.h"
#include <igl/copyleft/cgal/outer_hull.h>
#include <nanobind/nanobind.h>
#include <nanobind/eigen/dense.h>
#include <nanobind/stl/tuple.h>

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

namespace pyigl
{
auto outer_hull(
const nb::DRef<const Eigen::MatrixXN> &V,
const nb::DRef<const Eigen::MatrixXI> &F)
{
// int32 required by libigl internals
Eigen::MatrixXi Fi = F.cast<int>();
Eigen::MatrixXN HV;
Eigen::MatrixXi HF;
Eigen::VectorXi J;
Eigen::Matrix<bool, Eigen::Dynamic, 1> flip;
igl::copyleft::cgal::outer_hull(V, Fi, HV, HF, J, flip);
return std::make_tuple(HV,
Eigen::MatrixXI(HF.cast<Integer>()),
Eigen::VectorXI(J.cast<Integer>()),
Eigen::VectorXB(flip));
}
}

void bind_outer_hull(nb::module_ &m)
{
m.def("outer_hull", &pyigl::outer_hull, "V"_a, "F"_a,
R"(Compute the outer hull of a piecewise-constant winding number mesh.

@param[in] V #V by 3 list of vertex positions
@param[in] F #F by 3 list of triangle indices into V
@return tuple (HV, HF, J, flip):
- HV #HV by 3 output vertex positions
- HF #HF by 3 output triangle indices into HV
- J #HF list of indices into F (birth faces)
- flip #HF list of bools, true if facet was flipped)");
}
Loading
Loading