Metadata-Version: 2.4
Name: vcti-tree-exporter-mesh
Version: 1.0.0
Summary: Tree exporter plugins for mesh-schema DataNode trees: PLY, OBJ, and STL writers
Author: Visual Collaboration Technologies Inc.
Requires-Python: <3.15,>=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy
Requires-Dist: vcti-tree-exporter>=2.0.0
Requires-Dist: vcti-mesh-schema>=1.0.0
Provides-Extra: test
Requires-Dist: pytest; extra == "test"
Requires-Dist: pytest-cov; extra == "test"
Requires-Dist: vcti-fileloader>=5.2.0; extra == "test"
Provides-Extra: lint
Requires-Dist: ruff; extra == "lint"
Provides-Extra: typecheck
Requires-Dist: mypy; extra == "typecheck"
Dynamic: license-file

# vcti-tree-exporter-mesh

Tree exporter plugins for mesh-schema DataNode trees: PLY, OBJ, and STL writers.

## Overview

`vcti-tree-exporter-mesh` is the write side of the mesh package family.
It ships three exporters satisfying the
[`vcti-tree-exporter`](https://pypi.org/project/vcti-tree-exporter/)
`Exporter` protocol — `PlyExporter` (binary little-endian), `ObjExporter`
(text), `StlExporter` (binary) — that consume a
[mesh-schema](https://pypi.org/project/vcti-mesh-schema/) subtree from
any tree (typically one a mesh loader such as
[`vcti-fileloader-slim`](https://pypi.org/project/vcti-fileloader-slim/)
populated) and write its points and triangles to disk. The three formats
live in one package deliberately: all are zero-dependency and
schema-bound; a format earns its own package only when it brings a heavy
dependency.

## Installation

```bash
pip install vcti-tree-exporter-mesh
```

### In `requirements.txt`

```
vcti-tree-exporter-mesh>=1.0.0
```

### In `pyproject.toml` dependencies

```toml
dependencies = [
    "vcti-tree-exporter-mesh>=1.0.0",
]
```

---

## Quick Start

Convert a SLIM mesh to STL — loader in, exporter out, the mesh subtree
as the hand-off:

```python
from pathlib import Path
from vcti.fileloader.core import DataNode
from vcti.fileloader.slim import SlimLoader
from vcti.tree.core import DictTree
from vcti.tree.exporter.mesh import StlExporter

loader, tree = SlimLoader(), DictTree(root_data=DataNode())
with loader.open(Path("3d.slm")) as handle:
    loader.populate(handle, tree, tree.root_handle)
    StlExporter().export(tree, Path("3d.stl"))
```

Each exporter finds the tree's (single) mesh subtree by itself; pass
`root=` when the tree holds several. Through the registry, resolution
works by id or attribute lookup like the rest of the exporter family:

```python
from vcti.tree.exporter.core import build_registry, get_exporter
from vcti.tree.exporter.mesh import get_exporter_descriptors

registry = build_registry(get_exporter_descriptors())
get_exporter(registry, "ply").export(tree, Path("mesh.ply"), overwrite=True)
```

---

## The three formats

| Exporter | id | Output | Notes |
|---|---|---|---|
| `PlyExporter` | `ply` | binary little-endian PLY | float32 vertices; vertex-only meshes allowed |
| `ObjExporter` | `obj` | Wavefront OBJ text | 1-based faces; `\n` line endings on all platforms |
| `StlExporter` | `stl` | binary STL | computed facet normals; requires a non-empty `triangle` block |

Common behavior: the mesh subtree is validated against the schema before
writing (violations raise `ExportError` with context, never raw numpy
errors); 2-D meshes are padded with `z = 0`; existing files raise
`FileExistsError` unless `overwrite=True`.

See [docs/design.md](docs/design.md) for the model and boundaries.

---

## Dependencies

- [vcti-tree-exporter](https://pypi.org/project/vcti-tree-exporter/) — the `Exporter` protocol and descriptor/registry helpers.
- [vcti-mesh-schema](https://pypi.org/project/vcti-mesh-schema/) — the mesh block schema the writers consume.
- [numpy](https://numpy.org/) — binary encoding of blocks.
