Metadata-Version: 2.4
Name: thinskin
Version: 0.1.0
Summary: Identify and annotate thin (narrow) regions in STL meshes.
Project-URL: Homepage, https://github.com/SemiQuant/ThinSkin
Project-URL: Repository, https://github.com/SemiQuant/ThinSkin
Project-URL: Issues, https://github.com/SemiQuant/ThinSkin/issues
Author-email: SemiQuant <JasonLimberis@ucsf.edu>
License: MIT
License-File: LICENSE
Keywords: 3d-printing,cad,mesh,stl,thickness,trimesh
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Manufacturing
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Multimedia :: Graphics :: 3D Modeling
Classifier: Topic :: Scientific/Engineering :: Visualization
Requires-Python: >=3.9
Requires-Dist: click>=8.0
Requires-Dist: matplotlib>=3.5
Requires-Dist: numpy>=1.21
Requires-Dist: rtree>=1.0
Requires-Dist: scipy>=1.7
Requires-Dist: trimesh>=3.20
Provides-Extra: dev
Requires-Dist: build; extra == 'dev'
Requires-Dist: pytest; extra == 'dev'
Requires-Dist: twine; extra == 'dev'
Description-Content-Type: text/markdown

# ThinSkin

[![PyPI version](https://img.shields.io/pypi/v/thinskin.svg)](https://pypi.org/project/thinskin/)
[![Python versions](https://img.shields.io/pypi/pyversions/thinskin.svg)](https://pypi.org/project/thinskin/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

**ThinSkin** analyses an STL mesh and identifies regions where the local
geometry is **thinner than a specified diameter threshold** — handy for
checking 3D-print wall thickness, minimum feature sizes, and structurally
fragile areas before manufacturing.

## How it works

For every vertex in the mesh, ThinSkin estimates the local *inscribed
diameter* using two complementary approaches and takes the **minimum** of the
two as the effective local diameter:

1. **Ray-cast thickness** — casts a ray inward along the inverted vertex
   normal and measures the distance to the nearest opposing surface.
2. **Local curvature radius** — derived from the mean curvature at each vertex
   via the cotangent-weighted Laplacian.

Vertices whose effective diameter falls below the threshold are flagged as
*narrow*.

## Installation

```bash
pip install thinskin
```

ThinSkin uses [`trimesh`](https://trimesh.org/) for ray casting, which relies
on [`rtree`](https://pypi.org/project/Rtree/) (bundled `libspatialindex`). If
you hit native-library issues, install via conda/mamba:

```bash
micromamba install -c conda-forge rtree
pip install thinskin
```

### From source

```bash
git clone https://github.com/SemiQuant/ThinSkin.git
cd ThinSkin
pip install -e ".[dev]"
```

## Usage

### Command line

```bash
thinskin model.stl --diameter 2.0
```

Options:

| Option | Alias | Default | Description |
| --- | --- | --- | --- |
| `--diameter` | `-d` | `2.0` | Minimum diameter threshold (mm). |
| `--output` | `-o` | `<input>_narrow.stl` | Output STL path. |
| `--version` | `-V` | | Print version and exit. |
| `--help` | `-h` | | Show help and exit. |

You can also run it as a module:

```bash
python -m thinskin model.stl -d 1.5
```

### Outputs

For an input `model.stl`, ThinSkin writes (when narrow regions are found):

| File | Description |
| --- | --- |
| `model_narrow.stl` | Mesh containing only the flagged (narrow) faces — overlay in MeshLab. |
| `model_narrow_coloured.obj` | Full mesh with per-vertex colours (red = narrow, green = OK). |
| `model_narrow_annotated_views.png` | CAD-style 2×2 multi-view annotated report. |

The console also prints mesh stats, a results summary, and a diameter
distribution histogram as tables.

### Python API

```python
import thinskin

mesh = thinskin.load_mesh("model.stl")
eff_diam, thickness, curv_radius = thinskin.compute_effective_diameter(mesh)

threshold = 2.0
narrow = eff_diam < threshold
print(f"{int(narrow.sum())} narrow vertices below {threshold} mm")

# Render the annotated report
thinskin.generate_annotated_report(mesh, eff_diam, threshold, "model_narrow.stl")
```

## Requirements

- Python ≥ 3.9
- `click`, `numpy`, `scipy`, `trimesh`, `rtree`, `matplotlib`

## License

[MIT](LICENSE) © SemiQuant (Jason Limberis)
