Skip to content

Restructure into a medial axis library: C++/CUDA API, Python bindings, wheels, docs - #2

Merged
ningnawang merged 8 commits into
mainfrom
restructure-library
Nov 2, 2026
Merged

ningnawang merged 8 commits into
mainfrom
restructure-library

Conversation

@ningnawang

Copy link
Copy Markdown
Owner

Turns libmat into a medial axis library in the style of gpytoolbox / geometry-central: a C++ library with CPU and CUDA builds, Python bindings for every function, examples, pip install libmat wheels, and a docs site.

What changes

  • C++ API: one header per function under include/libmat/ (read_tet_mesh, extract_surface, detect_sharp_features, shrink_spheres, regular_triangulation, slab_tangent_triangles, distance_to_medial_mesh, thin_medial_mesh, medial_mesh_from_spheres, IO helpers). The existing modules moved to include/libmat/<module>/ and src/, and the CUDA code moved to src/cuda and include/libmat/cuda. A single top-level CMake build replaces the per-directory CMakeLists; geogram, CGAL and Eigen are downloaded when they are missing.
  • Python: python/libmat, one module per function, with numpydoc docstrings (Parameters / Returns / Examples). examples/01–08 cover each step; 08 needs CUDA. pytest suite in tests/.
  • Wheels: scikit-build-core + cibuildwheel (.github/workflows/wheels.yml) for Linux x86_64 and macOS x86_64/arm64, Python ≥ 3.10. Wheels are CPU only. Publishing uses PyPI Trusted Publishing on a GitHub release (TestPyPI via manual dispatch).
  • Docs: mkdocs-material site at https://libmat.ningnawang.workers.dev, hosted as a static Cloudflare Worker (wrangler.jsonc, .github/workflows/docs.yml). The Python API pages are generated from the docstrings.
  • README: new quick start, plus a Credit section (citation and the papers LibMAT is built on) and a Contribute section.

Fixes along the way

  • Several non-void functions had no return. GCC compiles these into crashes, so read_tet_mesh crashed on Linux. All are fixed, and libmat_core now builds with -Werror=return-type.
  • Slab tangent triangles: project_point_onto_line now projects onto the line through v0. main's clamped version is kept as project_point_onto_segment for get_closest_concave_point_V2.
  • Build fixes:
    • geogram 1.7.9 builds with CMake 4 and links OpenMP on Linux.
    • A downloaded CGAL builds without GMP when GMP isn't installed.
    • nlohmann_json is updated to 3.12.0 for CMake 4.
  • This branch includes main's latest 63 commits. The feature thresholds are angles in degrees (concave 60, convex 55), as on main.

Testing

  • macOS arm64, CPU: 33 passed, 2 skipped (the CUDA-only tests).
  • Linux x86_64 wheel built and tested with cibuildwheel in Docker (manylinux_2_28): all tests pass.
  • CUDA build tested on a Runpod NVIDIA L4 (CUDA 12.4): 33 passed, 2 skipped (the no-CUDA tests).
    • GPU and CPU distance_to_medial_mesh agree to 1.4e-5 relative.
    • Example 08 runs; after thinning, the L-block's medial mesh has Euler characteristic 1.

Before releasing

  • The docs deploy on push to main needs the CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID repository secrets. Without them, the docs workflow fails after merge.
  • PyPI and TestPyPI need a trusted publisher for wheels.yml, with environments pypi and testpypi.

🤖 Generated with Claude Code

ningnawang and others added 8 commits November 1, 2026 11:38
…ngs and docs

- functional C++ API (namespace libmat, Eigen in/out, one header per function)
  in include/libmat/<function>.h, implementations in src/api and src/cuda/api
- headers moved to include/libmat/{common,inputs,matbase,matfun,io,rpd3d,cuda}
- CMake targets libmat::core (CPU), libmat::cuda (LIBMAT_WITH_CUDA=ON) and
  libmat::libmat; geogram 1.7.9 fetched and built statically
- pybind11 module + python package python/libmat (numpydoc docstrings),
  pip install . via scikit-build-core
- python examples (examples/), pytest tests (tests/), example data (data/)
- mkdocs site with one page per function (docs/), GitHub Pages workflow
- tests_cxx -> apps/viewer, unused code -> legacy/
- thinning: stop pruning tets when an iteration makes no progress

CPU build, 31 python tests, examples and docs verified on macOS arm64.
CUDA code (src/cuda/api, libmat::cuda) has not been compiled yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…sh on Linux

- pip install libmat: cibuildwheel config in pyproject.toml and
  .github/workflows/wheels.yml (Linux x86_64, macOS x86_64/arm64,
  Python >= 3.10), published to PyPI on GitHub releases
- CGAL downloaded if missing; wheels built with CGAL_DISABLE_GMP
- geogram: CMAKE_POLICY_VERSION_MINIMUM for CMake 4, OpenMP linked on
  Linux, clear error on Linux ARM (x86 atomics)
- legacy code: add the missing return statements (GCC turned them into a
  crash in read_tet_mesh), build libmat_core with -Werror=return-type
- docs: brand color #dd7e01, torus + skeleton logo, polyscope-like left
  sidebar, LibMAT title links home, Credit / Contribute / Contributors
- citation author: Ningna Wang and others

Wheels tested locally: cp312 macOS arm64 and manylinux x86_64, 32 tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…69058 example

- describe what each function does instead of attributing it to
  MATFP/MATTopo; the papers are credited once, in the Credit section
- Credit: "If LibMAT is helpful in your research, please cite us!", the
  papers LibMAT is built upon (MATStruct added), newest first
- data/mesh_69058.obj: real input model from MATFP, used by the surface
  mesh examples and docstrings, with a feature detection test
- document that shrink_spheres creates at most one sphere per triangle

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- wrangler.jsonc: static-assets-only Worker "libmat" serving the mkdocs site
- docs.yml: build and deploy with cloudflare/wrangler-action on push to main
  (needs CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID secrets), instead
  of GitHub Pages
- site_url and documentation links point to the new URL
- home page title is just "LibMAT"

First deployed from a local machine with `mkdocs build && npx wrangler deploy`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Conflicts:
- README.md: keep the rewritten README (citation already updated)
- include/libmat/common/common.h: drop the FOR macro, as on main
- include/libmat/inputs/input_types.h: new include paths + mesh_AABB.h
- src/inputs/CMakeLists.txt, src/rpd3d/kNN-CUDA/CMakeLists.txt: removed
  (single top-level CMakeLists); mesh_AABB.cxx added to libmat_core

Adapting main's changes to the library:
- mesh_AABB.h moved to include/libmat/inputs/
- common_cxx.h: std::filesystem instead of <experimental/filesystem>
  (not available on macOS)
- API calls updated: pre_and_init_aabb(..., is_reorder=true),
  detect_mark_sharp_features(..., is_sf_file_exist=false)
- feature thresholds are angles in degrees on main: API defaults are now
  thres_concave=60, thres_convex=55 (were 0.2 / 40 in the old units)

Fix in common_geogram.h: main turned project_point_onto_line into a clamped
segment projection that never set `dist`, so slab tangent triangles were
NaN. The segment version is now project_point_onto_segment (used by
get_closest_concave_point_V2), and project_point_onto_line projects onto the
line through v0 (the old version projected onto a line through the origin,
so slab triangles were not tangent). The slab test now checks tangency.

Tested: macOS arm64 and manylinux x86_64 wheels, 33 tests, examples, docs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…A tests

- downloaded CGAL: build without GMP/MPFR when they are not installed
  (CGAL falls back to Boost.Multiprecision)
- nlohmann_json 3.12.0 (3.11.2 is rejected by CMake 4), CUDA build only
- tests: CUDA distance_to_medial_mesh matches CPU; GPU medial_mesh_from_spheres
  on the L-block gives a contractible medial mesh after thinning

Verified on a Runpod L4 (CUDA 12.4): 33 passed, 2 skipped (no-CUDA tests).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…OS 15 SDK

The macOS wheel jobs on GitHub (Xcode 16.4, clang 17) failed in geogram 1.7.9:
- arm64: clang 17 rejects the -msse3 that geogram's Darwin platform file adds
- x86_64: geogram's bundled zlib redefines fdopen() as NULL when
  TARGET_OS_MAC is defined, which breaks stdio.h of the macOS 15 SDK

Patch the downloaded sources (FetchContent PATCH_COMMAND, idempotent): drop
-msse3 on Darwin (x86_64 macOS targets have SSE3 anyway) and limit zlib's
fdopen override to classic MACOS, as zlib 1.2.12 does.

Clean local build (Apple clang 15) re-downloads and patches geogram: 33 passed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The macOS wheel jobs now failed in geogram's bundled PoissonRecon: clang >= 19
(Apple clang 17) rejects references to members that do not exist in template
code, even when it is never instantiated (SparseMatrix::SetZero uses m_N/m_M,
PlyVertexMini.h subtracts p.value instead of p.point).

Verified with conda-forge clang 19.1.7: the unpatched sources give the same
errors as CI, and with the patch a clean build of geogram + libmat has no
errors and the wheel passes the tests (33 passed, 2 CUDA tests skipped).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ningnawang
ningnawang merged commit 63630bf into main Nov 2, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant