{"id":28176072,"url":"https://github.com/voxleone/spinstep","last_synced_at":"2026-04-18T11:02:05.734Z","repository":{"id":290637627,"uuid":"975122175","full_name":"VoxleOne/SpinStep","owner":"VoxleOne","description":"A quaternion-driven traversal framework for trees and orientation-based data structures.","archived":false,"fork":false,"pushed_at":"2026-04-09T15:53:15.000Z","size":1879,"stargazers_count":15,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-04-09T17:31:18.467Z","etag":null,"topics":["3d-graphics","data-structures","n-ary-trees","orientation-graphs","python","qgnn","quaternions","robotics","scipy","spatial-computing","traversal"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/VoxleOne.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"docs/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-04-29T20:21:59.000Z","updated_at":"2026-03-31T14:36:42.000Z","dependencies_parsed_at":"2025-06-12T20:49:36.392Z","dependency_job_id":"2c542178-449f-46d9-84ff-60a0f09b065e","html_url":"https://github.com/VoxleOne/SpinStep","commit_stats":null,"previous_names":["voxleone/spinstep"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/VoxleOne/SpinStep","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VoxleOne%2FSpinStep","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VoxleOne%2FSpinStep/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VoxleOne%2FSpinStep/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VoxleOne%2FSpinStep/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/VoxleOne","download_url":"https://codeload.github.com/VoxleOne/SpinStep/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VoxleOne%2FSpinStep/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31966217,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-18T00:39:45.007Z","status":"online","status_checked_at":"2026-04-18T02:00:07.018Z","response_time":103,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["3d-graphics","data-structures","n-ary-trees","orientation-graphs","python","qgnn","quaternions","robotics","scipy","spatial-computing","traversal"],"created_at":"2025-05-16T00:14:59.345Z","updated_at":"2026-04-18T11:02:05.721Z","avatar_url":"https://github.com/VoxleOne.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SpinStep\n\n**SpinStep** is a quaternion-driven traversal framework for trees and orientation-based data structures. Instead of traversing by position or order, SpinStep uses 3D rotation math to navigate trees based on orientation — making it ideal for robotics, spatial reasoning, 3D scene graphs, and anywhere quaternion math naturally applies.\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"docs/assets/img/quaternion-tree.png\" alt=\"A 3D Graph concept image\" width=\"750\" /\u003e\n\u003c/div\u003e\n\n## Overview\n\nSpinStep provides two traversal modes:\n\n- **Continuous traversal** — apply a single rotation step at each node and visit children whose orientation falls within an angular threshold (`QuaternionDepthIterator`).\n- **Discrete traversal** — try every rotation from a predefined symmetry group or custom set and visit reachable children (`DiscreteQuaternionIterator` with `DiscreteOrientationSet`).\n\nBoth modes are built on a simple `Node` class that stores a name, a unit quaternion orientation `[x, y, z, w]`, and a list of children.\n\n## Installation\n\n**Requirements:** Python 3.9+\n\nInstall from source:\n\n```bash\ngit clone https://github.com/VoxleOne/SpinStep.git\ncd SpinStep\npip install .\n```\n\nOr install in editable mode for development:\n\n```bash\npip install -e \".[dev]\"\n```\n\n## Quick Start\n\n```python\nfrom spinstep import Node, QuaternionDepthIterator\n\n# Build a small tree with quaternion orientations [x, y, z, w]\nroot = Node(\"root\", [0, 0, 0, 1], [\n    Node(\"child\", [0.2588, 0, 0, 0.9659])  # ~30° rotation around Z\n])\n\n# Traverse using a 30° rotation step\niterator = QuaternionDepthIterator(root, [0.2588, 0, 0, 0.9659])\n\nfor node in iterator:\n    print(\"Visited:\", node.name)\n# Output:\n# Visited: root\n# Visited: child\n```\n\n## Core Concepts\n\n### Node\n\nA tree node with a quaternion-based orientation. Each node stores a name, a unit quaternion `[x, y, z, w]` (automatically normalised), and a list of children.\n\n```python\nfrom spinstep import Node\n\nroot = Node(\"root\", [0, 0, 0, 1])\nchild = Node(\"child\", [0, 0, 0.3827, 0.9239])  # ~45° around Z\nroot.children.append(child)\n```\n\n### QuaternionDepthIterator\n\nDepth-first iterator that applies a continuous rotation step at each node. Only children within an angular threshold of the rotated state are visited.\n\n```python\nfrom spinstep import Node, QuaternionDepthIterator\n\nroot = Node(\"root\", [0, 0, 0, 1], [\n    Node(\"close\", [0.2588, 0, 0, 0.9659]),   # ~30° — will be visited\n    Node(\"far\", [0.7071, 0, 0, 0.7071]),      # ~90° — too far\n])\n\nfor node in QuaternionDepthIterator(root, [0.2588, 0, 0, 0.9659]):\n    print(node.name)\n# Output:\n# root\n# close\n```\n\n### DiscreteOrientationSet\n\nA set of discrete quaternion orientations with spatial querying. Comes with factory methods for common symmetry groups.\n\n```python\nfrom spinstep import DiscreteOrientationSet\n\ncube_set = DiscreteOrientationSet.from_cube()          # 24 orientations\nicosa_set = DiscreteOrientationSet.from_icosahedron()   # 60 orientations\ngrid_set = DiscreteOrientationSet.from_sphere_grid(200) # 200 Fibonacci-sampled\n```\n\n### DiscreteQuaternionIterator\n\nDepth-first iterator that tries every rotation in a `DiscreteOrientationSet` at each node. Children reachable by any rotation within the angular threshold are visited.\n\n```python\nimport numpy as np\nfrom spinstep import Node, DiscreteOrientationSet, DiscreteQuaternionIterator\n\nroot = Node(\"root\", [0, 0, 0, 1], [\n    Node(\"child1\", [0, 0, 0.3827, 0.9239]),\n    Node(\"child2\", [0, 0.7071, 0, 0.7071]),\n])\n\norientation_set = DiscreteOrientationSet.from_cube()\nit = DiscreteQuaternionIterator(root, orientation_set, angle_threshold=np.pi / 4)\n\nfor node in it:\n    print(node.name)\n# Output:\n# root\n# child1\n# child2\n```\n\n## Examples\n\n### Continuous Traversal with Custom Threshold\n\n```python\nimport numpy as np\nfrom spinstep import Node, QuaternionDepthIterator\n\nroot = Node(\"origin\", [0, 0, 0, 1], [\n    Node(\"alpha\", [0.1305, 0, 0, 0.9914]),  # ~15°\n])\n\n# Use explicit angle threshold of 20° (in radians)\nit = QuaternionDepthIterator(root, [0.1305, 0, 0, 0.9914], angle_threshold=np.deg2rad(20))\nprint([n.name for n in it])\n# Output: ['origin', 'alpha']\n```\n\n### Query Orientations by Angle\n\n```python\nimport numpy as np\nfrom spinstep import DiscreteOrientationSet\n\ndos = DiscreteOrientationSet.from_cube()\nindices = dos.query_within_angle([0, 0, 0, 1], np.deg2rad(10))\nprint(f\"Found {len(indices)} orientations within 10° of identity\")\n```\n\n## Optional Dependencies\n\nSpinStep works out of the box with NumPy and SciPy. Two optional dependencies unlock additional features:\n\n| Package | Install | Feature |\n|---------|---------|---------|\n| [CuPy](https://cupy.dev/) | `pip install cupy-cuda12x` | GPU-accelerated orientation storage and angular distance computation |\n| [healpy](https://healpy.readthedocs.io/) | `pip install healpy` | HEALPix-based unique relative spin detection via `get_unique_relative_spins()` |\n\nGPU example:\n\n```python\nimport numpy as np\nfrom spinstep import DiscreteOrientationSet\n\norientations = np.random.randn(1000, 4)\n# Store orientations on GPU (requires CuPy)\ngpu_set = DiscreteOrientationSet(orientations, use_cuda=True)\n```\n\n## Development\n\n```bash\n# Install with development dependencies\npip install -e \".[dev]\"\n\n# Run tests\npython -m pytest tests/ -v\n\n# Run linter\nruff check spinstep/\n```\n\n## Documentation\n\nFull documentation is available in the [docs/](docs/index.md) directory:\n\n- [Getting Started](docs/getting-started.md)\n- [Continuous Traversal Guide](docs/continuous-traversal.md)\n- [Discrete Traversal Guide](docs/discrete-traversal.md)\n- [FAQ](docs/faq.md)\n- [API Reference](docs/09-api-reference.md)\n- [Contributing](docs/CONTRIBUTING.md)\n\n## License\n\nMIT — see [LICENSE](LICENSE) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvoxleone%2Fspinstep","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvoxleone%2Fspinstep","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvoxleone%2Fspinstep/lists"}