Skip to content

Quickstart

Install

pip install geomcheck

Python 3.10 or newer. The runtime dependencies are NumPy, SciPy, Trimesh, PyMeshLab and embreex; all ship binary wheels, and nothing needs a GPU or a display.

To work on the code, or to reproduce the paper, install from source:

git clone https://github.com/Stark-Will/geometric-probes-3d
cd geometric-probes-3d
python -m venv .venv && .venv/bin/pip install -e ".[test]"
.venv/bin/python -m pytest -q

The paper's exact environment is pinned in requirements.lock.txt in the repository.

Linux: install libOpenGL.so.0 for decimation

PyMeshLab loads its filters from plugins. On Linux, the plugin that provides quadric edge-collapse decimation links against the system library libOpenGL.so.0. Minimal images (Docker, CI runners, servers) often lack it; PyMeshLab then prints Unable to load the following plugins: … libfilter_meshing.so on first use and the decimation filter is missing. Install it with

sudo apt-get install libopengl0        # Debian / Ubuntu
sudo dnf install libglvnd-opengl       # Fedora / RHEL

Only the library is needed, not a GPU or display. You can check with geomcheck.decimation_available(). Without it, every probe still works on undecimated meshes, and compute_all(..., decimate_to=N) raises PyMeshLabFilterUnavailable with these instructions instead of an AttributeError.

Probe a mesh

from geomcheck import compute_all

r = compute_all("model.glb")          # any file trimesh can load: GLB, OBJ, PLY, STL, ...
print(r["watertight"], r["n_boundary_loops"], r["n_small_components"])
print(r["self_intersect_face_frac"], r["hidden_surface_frac"], r["thin_frac_0.005"])

compute_all accepts a path or a trimesh.Trimesh and returns a flat dict of plain Python scalars, so it is easy to collect into a table:

import trimesh
from geomcheck import compute_all

sphere = trimesh.creation.icosphere(subdivisions=3)
floater = trimesh.creation.icosphere(subdivisions=2, radius=0.05)
floater.apply_translation((2.5, 0, 0))

r = compute_all(trimesh.util.concatenate([sphere, floater]))
assert r["n_components"] == 2 and r["n_small_components"] == 1

Options

compute_all(path_or_mesh, do_self_intersection=True, do_rays=True, decimate_to=None)
Argument Effect
do_self_intersection Run the PyMeshLab self-intersection probe. Set False to skip it.
do_rays Run the Embree ray probes (hidden surface, thin walls). Set False to skip them.
decimate_to If set and the mesh has more faces, first decimate it to about this many faces (quadric edge collapse, topology/boundary/normal preserving). The paper used 10000 for every corpus except 3D-DefectBench, whose meshes were already near that size.

Decimation can change thickness and intersection counts, so compare numbers only between meshes probed with the same setting. orig_n_faces always records the face count before decimation.

Many meshes

The repository includes a memory-safe batch runner (one mesh per subprocess, wall-clock timeout, RSS watchdog, resumable). It writes one JSON per mesh and a combined CSV:

python scripts/run_probes.py --glob 'my_models/*.glb' --out my_results --workers 2
python scripts/run_probes.py --glob 'my_models/*.glb' --out my_results_dec --decimate 10000

The runner additionally needs psutil and pandas.

Configuration

All thresholds live in one dictionary, geomcheck.CONFIG; see the probe reference. The paper's results were produced with these values unchanged.