Metadata-Version: 2.1
Name: polyxios
Version: 0.3.0
Summary: Fast 3D file format I/O and processing library
License: BSD 3-Clause License
         
         Copyright (c) 2026, fury-gl
         
         Redistribution and use in source and binary forms, with or without
         modification, are permitted provided that the following conditions are met:
         
         1. Redistributions of source code must retain the above copyright notice, this
            list of conditions and the following disclaimer.
         
         2. Redistributions in binary form must reproduce the above copyright notice,
            this list of conditions and the following disclaimer in the documentation
            and/or other materials provided with the distribution.
         
         3. Neither the name of the copyright holder nor the names of its
            contributors may be used to endorse or promote products derived from
            this software without specific prior written permission.
         
         THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
         AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
         IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
         DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
         FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
         DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
         SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
         CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
         OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
         OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
         
Requires-Python: >=3.11
Requires-Dist: numpy>=1.24
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Requires-Dist: mypy; extra == "dev"
Requires-Dist: cython>=3.0; extra == "dev"
Requires-Dist: pre-commit; extra == "dev"
Requires-Dist: spin; extra == "dev"
Requires-Dist: ruff; extra == "dev"
Requires-Dist: codespell; extra == "dev"
Provides-Extra: doc
Requires-Dist: sphinx; extra == "doc"
Requires-Dist: numpydoc; extra == "doc"
Requires-Dist: sphinx-gallery; extra == "doc"
Requires-Dist: pydata-sphinx-theme<0.21,>=0.20; extra == "doc"
Requires-Dist: sphinx-design; extra == "doc"
Requires-Dist: sphinx-copybutton; extra == "doc"
Requires-Dist: sphinxext-opengraph[social-cards]; extra == "doc"
Requires-Dist: sphinx-sitemap; extra == "doc"
Provides-Extra: viz
Requires-Dist: fury>=2; extra == "viz"
Description-Content-Type: text/markdown

# polyxios

**Fast, clean mesh I/O for Python.** Read and write 3D mesh files in one line - no hidden surprises, no silent data corruption.

---

## Install

```bash
pip install polyxios
```

---

## Usage

```python
import polyxios as px

# Read any supported format
mesh = px.read("brain.vtk")

# Inspect
print(mesh.vertices.shape)      # (n_verts, 3)
print(len(mesh.element_types))  # number of elements

# Write to a different format
px.write(mesh, "brain.ply")
px.write(mesh, "brain.vtp")
```

Need binary output or format-specific options?

```python
px.write(mesh, "brain.vtk", binary=True)
px.write(mesh, "brain.ply", binary=True, endian="little")
```

---

## Command Line Interface (pxios)

polyxios comes with a command-line interface `pxios` to quickly fetch, list, convert, and visualize 3D models.

### Subcommands

`--verbose` can be given on either side of the subcommand (e.g. `pxios --verbose fetch bunny.obj` or `pxios fetch bunny.obj --verbose`) to print debug logs and full tracebacks when a command fails.

*   **`pxios list`**: Lists all available remote or cached files, or registered formats. The three listing modes below are mutually exclusive.
    *   `--local`: Lists locally cached files (can filter by optional extension argument, e.g. `pxios list obj --local`).
    *   `--extensions` / `--formats`: Lists all formats and extensions available in the remote catalog.
    *   `--codecs`: Lists all formats supported by polyxios codecs.
*   **`pxios fetch <filename|extension>`**: Downloads and caches a single model file (e.g., `bunny.obj`) or every model catalogued for an extension (e.g., `obj` or `.obj`).
*   **`pxios convert <input_file> <output_file>`**: Converts a model file from one format to another directly in a single process.
*   **`pxios viz <filename>`**: Visualizes a local or cached model file using the [FURY](https://fury.gl) library.
    *   `--lines`: Render line elements using `actor.line` instead of rendering as a surface/point cloud.
    *   `--points`: Render strictly as a point cloud.

```bash
# List all fetchable remote models
pxios list

# Fetch a single model
pxios fetch bunny.obj

# Fetch every model catalogued for an extension
pxios fetch vtk

# Convert a mesh file
pxios convert bunny.obj bunny.vtk

# Visualize a model
pxios viz bunny.obj
```

---

## Lazy loading - work with large files without filling RAM

For large meshes (gigabytes of binary data), pass `lazy=True`. polyxios
memory-maps the file and only loads the pages you actually touch - the rest
stays on disk until needed.

```python
# File is opened but data is not loaded into RAM yet
mesh = px.read("huge_brain.vtk", lazy=True)

# Only the vertices are pulled from disk here
first_vertex = mesh.vertices[0]

# Element connectivity is still on disk until you access it
```

Lazy loading is supported for binary `.vtk`, `.ply`, and `.stl` files. ASCII
formats load eagerly (the whole file must be parsed to extract values). Binary
STL lazy mode skips vertex deduplication - vertices are returned as-is (3 per
triangle), avoiding the extra pass over the data.

---

## Supported formats

| Format | Extension | Read | Write | Lazy load |
|--------|-----------|------|-------|-----------|
| VTK Legacy | `.vtk` | ✓ | ✓ | binary only |
| VTK RectilinearGrid | `.vtr` | ✓ | ✓ | - |
| VTK PolyData | `.vtp` | ✓ | ✓ | - |
| Wavefront OBJ | `.obj` | ✓ | ✓ | - |
| Stanford PLY | `.ply` | ✓ | ✓ | binary only |
| STL | `.stl` | ✓ | ✓ | binary only |
| OFF | `.off` | ✓ | ✓ | ASCII + big-endian binary, `ST`/`C`/`N` variants → vertex/face attrs |
| Abaqus | `.inp` | ✓ | ✓ | - |
| AVS-UCD | `.avs` | ✓ | ✓ | - |
| Medit binary | `.meshb` | ✓ | ✓ | binary only |
| DOLFIN/FEniCS XML | `.xml` | ✓ | ✓ | - |
| FLAC3D | `.f3grid` | ✓ | ✓ | zones + faces, groups → element tags |
| Gmsh | `.msh` | ✓ | ✓ (v2) | ASCII v2 + v4.1, physical groups → element tags |
| Nastran | `.bdf` `.nas` `.fem` | ✓ | ✓ | free/small/large field read, free-field write with large-field `GRID` on request; `.dat` via `fmt=".bdf"` |
| Tecplot ASCII | `.tec` | ✓ | ✓ | FE zone, POINT + BLOCK packing, solution variables → vertex attrs; `.dat` via `fmt=".tec"` |
| SU2 | `.su2` | ✓ | ✓ | ASCII, VTK element codes, boundary markers → element tags |
| TetGen | `.ele`+`.node` | ✓ | ✓ | paired files, 1-/0-based indices, boundary markers → vertex tags, region attrs |
| UGRID (AFLR) | `.ugrid` | ✓ | ✓ | ASCII, tri/quad surface + tet/pyramid/prism/hex volume, boundary tags → element tags |
| Netgen | `.vol` | ✓ | ✓ | ASCII, points/edges/faces/cells incl. quadratic, `bcnr`/`matnr` + names → element tags |
| Well-Known Text | `.wkt` | ✓ | ✓ | 2D padded to z=0, holes → element attrs, EWKT SRID dropped |

**20 formats supported** - more coming via the plugin system.

---

## Transforms

```python
from polyxios.transforms import pipeline, merge, filter_element_type, remove_orphan_vertices

# Compose transforms into a single function
clean = pipeline(
    filter_element_type(keep="triangle"),
    remove_orphan_vertices,
)
result = clean(mesh)

# Merge two meshes into one
combined = merge(mesh_a, mesh_b)
```

---

## Add your own format

Any third-party package can teach polyxios to read and write a new format -
no fork required, no pull request needed.

**Step 1 - write a codec** (two functions, nothing more):

```python
# mypackage/abc_codec.py
from polyxios._registry import Codec
from polyxios._types import PolyData

def read(path, *, lazy=False) -> PolyData:
    ...

def write(poly: PolyData, path, **opts) -> None:
    ...

def register():
    return ".abc", Codec(read, write)
```

**Step 2 - declare an entry point** in your `pyproject.toml`:

```toml
[project.entry-points."polyxios.codecs"]
abc = "mypackage.abc_codec:register"
```

After `pip install mypackage`, polyxios picks up `.abc` automatically -
no configuration, no restart needed:

```python
mesh = px.read("model.abc")   # works out of the box
```

---

## Contributing / Development

Clone the repo, then use [spin](https://github.com/scientific-python/spin) to
manage the development workflow:

```bash
pip install spin
spin setup       # add upstream remote + install dev deps (libomp on macOS)
spin install     # build Cython extensions and install
spin install -e  # editable install (source changes reflected immediately)
```

| Command | Description |
|---------|-------------|
| `spin setup` | First-time setup: upstream remote, dev deps, OpenMP on macOS |
| `spin build` | Build with Meson/ninja |
| `spin install` | Regular install (compiled) |
| `spin install -e` | Editable install for development |
| `spin test` | Run the full test suite |
| `spin test -k <pattern>` | Run tests matching a name pattern |
| `spin lint` | ruff linter + formatter check + codespell |
| `spin lint --fix` | Auto-fix lint and formatting issues |
| `spin docs` | Build Sphinx documentation |
| `spin docs --clean` | Wipe `_build/` before building |
| `spin docs --open` | Build and open docs in the browser |
| `spin clean` | Remove build artifacts and `__pycache__` |
| `spin release <version>` | Cut a release: bump version, tag, push, start next dev cycle |

See [`docs/contributing.rst`](docs/contributing.rst) for commit message
conventions and the full contributor guide.
For the full release workflow see [`docs/development.rst`](docs/development.rst).

---

## Why polyxios?

- **No silent data corruption** - large mesh indices raise an error instead of truncating
- **All element groups preserved** - a face belonging to multiple tags stays in all of them
- **Safe on untrusted files** - header counts validated before any memory allocation
- **Memory-efficient** - lazy mmap loading for large binary files
- **Works without a compiler** - pure Python fallbacks included; Cython hot-paths optional

---

## License

See [LICENSE](LICENSE).
