Skip to content

Add high-level mesh-based API for SPHARM parametrization - #24

Open
keisuke-ishihara wants to merge 5 commits into
AllenCell:mainfrom
Ishihara-SynthMorph:feature/mesh-input-api
Open

keisuke-ishihara wants to merge 5 commits into
AllenCell:mainfrom
Ishihara-SynthMorph:feature/mesh-input-api

Conversation

@keisuke-ishihara

Copy link
Copy Markdown

Summary

Closes #23.

get_shcoeffs() currently accepts only binary images, even though the library already converts images to a vtkPolyData mesh internally before fitting spherical harmonics. This PR exposes that mesh path directly so users with existing surface meshes (from meshing pipelines, simulation outputs, etc.) don't need to voxelize them back into images — a lossy and unnecessary round-trip.

  • shparam.get_shcoeffs_from_mesh(mesh, lmax, alignment_2d=True, make_unique=False) — accepts a vtk.vtkPolyData, returns the same nested-tuple structure as get_shcoeffs (with image_ set to None)
  • shparam.get_shcoeffs_from_vertices_faces(vertices, faces, lmax, alignment_2d=True, make_unique=False) — convenience wrapper for users working with raw numpy arrays
  • shparam._get_shcoeffs_from_mesh_coords — private core extracted from get_shcoeffs, shared by both the image and mesh paths to avoid duplication
  • shtools.get_mesh_from_vertices_faces(vertices, faces, center=True) — builds and validates a vtkPolyData from numpy arrays
  • shtools.check_mesh_for_parametrization(mesh) — non-raising warnings for geometric assumption violations (non-watertight surface, centroid outside mesh)
  • shtools.align_points_2d(x, y, make_unique=False) — PCA-based 2D alignment, refactored out of the shared alignment logic

Validation

Situation Behavior
Empty mesh / zero points ValueError
Invalid vertex array shape, NaN/Inf, out-of-range face indices ValueError
Non-watertight / non-manifold surface UserWarning (computation proceeds)
Centroid outside mesh (non-star-shaped proxy) UserWarning (computation proceeds)

Note on alignment

The 2D alignment angle is not guaranteed to be bit-identical between get_shcoeffs and get_shcoeffs_from_mesh for the same object, since PCA runs on different point sets (voxel coordinates vs. surface vertices). Documented in the docstring.

Test plan

  • Added tests/test_shparam_mesh.py covering mesh and vertices/faces entry points, validation errors, and warnings
  • README updated with usage example

🤖 Generated with Claude Code

dependabot Bot and others added 5 commits June 2, 2026 09:24
Bumps [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish) from 1.4.2 to 1.13.0.
- [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases)
- [Commits](pypa/gh-action-pypi-publish@v1.4.2...v1.13.0)

---
updated-dependencies:
- dependency-name: pypa/gh-action-pypi-publish
  dependency-version: 1.13.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Closes #3.

Adds public entry points to compute spherical harmonics coefficients
directly from a surface mesh, exposing functionality the library already
implemented internally (get_shcoeffs voxelizes/re-meshes an image before
fitting on mesh point coordinates).

shparam.py:
- get_shcoeffs_from_mesh(mesh, lmax, ...): fit directly from a vtkPolyData.
- get_shcoeffs_from_vertices_faces(vertices, faces, lmax, ...): wrapper for
  raw numpy arrays.
- Factor the shared fitting math into _get_shcoeffs_from_mesh_coords so the
  image and mesh paths use one implementation. Return shape matches
  get_shcoeffs; the image_ slot is None for mesh input.
- Center on the vertex-mean centroid and align on the mesh point cloud;
  the caller's mesh is deep-copied so it is not mutated.

shtools.py:
- get_mesh_from_vertices_faces: build a triangular vtkPolyData with hard-error
  validation (shape, finite values, index bounds).
- check_mesh_for_parametrization: warn (never raise) on non-watertight meshes
  (vtkFeatureEdges, after cleaning coincident points) and off-center centroids
  (vtkSelectEnclosedPoints).
- get_alignment_angle_2d / align_points_2d: factor the PCA angle math out of
  align_image_2d so image and point-cloud alignment share it.

Co-Authored-By: Claude Code <noreply@anthropic.com>
Add a Notes section clarifying that alignment_2d/make_unique behave the
same as in get_shcoeffs, but the mesh path aligns on surface vertices and
rotates points directly (vs. voxel-volume PCA + image rotation), so the
two paths are not guaranteed to produce bit-identical orientations.

Co-Authored-By: Claude Code <noreply@anthropic.com>
…om package

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

This branch has not been deployed

No deployments
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.

Feature request: expose mesh-based API (get_shcoeffs_from_mesh / get_shcoeffs_from_vertices_faces)

1 participant