Metadata-Version: 2.1
Name: pypolaris
Version: 0.1.0
Summary: Native Python wrapper for the pypolaris tracking system
Requires-Python: >=3.8,<3.13
Description-Content-Type: text/markdown

# pypolaris

Cross-platform SWIG/C++ wrapper for NDI Polaris trackers.

- `CAPIcommon/`: NDI communication library.
- `CAPIsample/src/main.cpp`: Python-facing implementation.
- `pypolaris.i` and `pypolaris.h`: SWIG interface and public wrapper API.
- `sroms/`: tool definition files used by examples and local testing.
- `CMakeLists.txt`: the only native build definition.

Build from the repository root:

```shell
uv run --python 3.12 python build-system/build_wheel.py pypolaris
```

This creates one wheel for the selected Python and the current operating
system. Cross-platform wheels are built by the repository's GitHub Actions
matrix, not by cross-compiling this command locally.

Multiple-object support introduced in version 0.0.9 remains available. Pass
the tool definitions in a `StringVector` to `Initialize`; the corresponding
measurements and visibility flags are exposed through `objs` and `objIDs`:

```python
objects = pypolaris.StringVector()
objects.push_back(b"coil-1.rom")
objects.push_back(b"coil-2.rom")
tracker.Initialize(b"COM1", b"NBSprobe", b"NBSref", objects)
tracker.Run()
print(tracker.objs, tracker.objIDs)
```

The single-object `Initialize` overload and the `obj`/`objID` attributes from
version 0.0.7 remain available for compatibility.

`Initialize()` returns `0` only after tracking starts. Device warnings, such as
`WARNING03` (incompatible loaded tools), are reported to stderr and initialization
continues. These warnings still indicate a tool configuration issue; they do not
guarantee that the tools can be tracked reliably. Actual errors stop initialization,
disconnect the tracker and return the original negative NDI error code. Transport
failures, unreadable ROM files or no enabled tools return `-1`.

Connection progress and raw commands (including ROM uploads) are quiet by default.
Enable them explicitly before initialization when troubleshooting:

```python
tracker.SetVerbose(True)
```

Warnings and errors remain visible regardless of this setting. Tracking commands
(`BX`, `BX2`, `TX`) are never traced to avoid per-frame console overhead.

The native calls release Python's GIL while waiting for the tracker. Access to
each Polaris connection is serialized, so concurrent Python work can continue
without interleaving device commands. Separate `pypolaris` instances no longer
share a connection or tracking state.

For the lowest per-frame overhead, use `ReadFrame()` instead of `Run()`. It
returns numeric values directly and avoids creating the legacy CSV strings:

```python
frame = tracker.ReadFrame()
if frame.status == 0:
    for transform in frame.transforms:
        if transform.visible:
            print(transform.toolHandle, transform.tx, transform.ty, transform.tz)
```

`frame.status` is `0` on success, `-1` after a transport/parse failure and `-2`
when tracking has not been started. `Run()` remains backward compatible,
updates `probe`, `ref`, `objs` and their ID flags, and returns `1`, `-1` or `-2`
for those same states.

Do not commit generated `pypolaris.py`, `_pypolaris.*`, CMake build trees or
wheels. The shared builder stages those files automatically.
