{"id":19078751,"url":"https://github.com/qu1x/trackball","last_synced_at":"2025-04-30T05:09:53.275Z","repository":{"id":51845826,"uuid":"345056884","full_name":"qu1x/trackball","owner":"qu1x","description":"Virtual Trackball Orbiting via the Exponential Map","archived":false,"fork":false,"pushed_at":"2025-02-22T14:11:57.000Z","size":169,"stargazers_count":6,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-30T05:09:44.995Z","etag":null,"topics":["arcball","c","camera","exponential-map","quaternion","rust-lang","virtual-trackball"],"latest_commit_sha":null,"homepage":"https://qu1x.dev/bevy_trackball","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/qu1x.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSES/Apache-2.0","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}},"created_at":"2021-03-06T09:40:51.000Z","updated_at":"2025-02-22T14:10:01.000Z","dependencies_parsed_at":"2023-12-27T00:22:38.369Z","dependency_job_id":"2ea99855-3ae4-4801-a2e8-42751be3e0dc","html_url":"https://github.com/qu1x/trackball","commit_stats":{"total_commits":135,"total_committers":2,"mean_commits":67.5,"dds":0.007407407407407418,"last_synced_commit":"cd2b869ae185db31ea8dd01cc32a90b69a290673"},"previous_names":[],"tags_count":25,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qu1x%2Ftrackball","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qu1x%2Ftrackball/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qu1x%2Ftrackball/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qu1x%2Ftrackball/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/qu1x","download_url":"https://codeload.github.com/qu1x/trackball/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251644842,"owners_count":21620634,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["arcball","c","camera","exponential-map","quaternion","rust-lang","virtual-trackball"],"created_at":"2024-11-09T02:11:45.828Z","updated_at":"2025-04-30T05:09:53.257Z","avatar_url":"https://github.com/qu1x.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# trackball\n\nVirtual Trackball Orbiting via the Exponential Map\n\n[![Build][]](https://github.com/qu1x/trackball/actions/workflows/build.yml)\n[![Documentation][]](https://docs.rs/trackball)\n[![Downloads][]](https://crates.io/crates/trackball)\n[![Version][]](https://crates.io/crates/trackball)\n[![Rust][]](https://www.rust-lang.org)\n[![License][]](https://opensource.org/licenses)\n\n[Build]: https://github.com/qu1x/trackball/actions/workflows/build.yml/badge.svg\n[Documentation]: https://docs.rs/trackball/badge.svg\n[Downloads]: https://img.shields.io/crates/d/trackball.svg\n[Version]: https://img.shields.io/crates/v/trackball.svg\n[Rust]: https://img.shields.io/badge/rust-v1.85.0-brightgreen.svg\n[License]: https://img.shields.io/badge/License-MIT%20OR%20Apache--2.0-blue.svg\n\nThis is an alternative trackball technique using exponential map and parallel transport to\npreserve distances and angles for inducing coherent and intuitive trackball rotations. For\ninstance, displacements on straight radial lines through the screen's center are carried to arcs\nof the same length on great circles of the trackball. This is in contrast to state-of-the-art\ntechniques using orthogonal projection which distorts radial distances further away from the\nscreen's center. This implementation strictly follows the recipe given in the paper of\nStantchev, G.. “Virtual Trackball Modeling and the Exponential Map.” . [S2CID] [44199608].\n\n[S2CID]: https://en.wikipedia.org/wiki/S2CID_(identifier)\n[44199608]: https://api.semanticscholar.org/CorpusID:44199608\n\n## Features\n\n  * Common trackball operations split into several operation handlers.\n  * Coherent and intuitive orbiting via the exponential map, see [`Orbit`] operation handler.\n  * Identical C11 implementation for [`Orbit`] operation handler behind `cc` feature gate.\n  * Coherent [`First`] person view aka free look or mouse look wrt [`Orbit`] operation handler.\n  * Observer [`Frame`] with [`Frame::slide()`], [`Frame::orbit()`], [`Frame::scale()`]\n    operations in world space and their local complements in camera space and with orbit and\n    slide operations around arbitrary points in either world or camera space.\n  * Gliding [`Clamp`] operation handler trait ensuring boundary conditions of observer\n    [`Frame`]. When [`Delta`] between initial and final [`Frame`] is not orthogonal to a\n    boundary [`Plane`], [`Delta`] is changed in such a way that the clamped movement glides\n    along the plane.\n  * [`Bound`] implementing [`Clamp`] providing customizable orthogonal boundary conditions.\n  * Object inspection mode scaling clip plane distances by measuring from target instead of eye.\n  * Scale-preserving transitioning between orthographic and perspective projection mode.\n  * Converting between [`Fixed`] quantities wrt to field of view, see [`Scope::set_fov()`].\n  * Time-free [`Touch`] gesture recognition for slide, orbit, scale, and focus operations.\n\n[`Frame::slide()`]: https://docs.rs/trackball/latest/trackball/struct.Frame.html#method.slide\n[`Frame::orbit()`]: https://docs.rs/trackball/latest/trackball/struct.Frame.html#method.orbit\n[`Frame::scale()`]: https://docs.rs/trackball/latest/trackball/struct.Frame.html#method.scale\n\n[`First`]: https://docs.rs/trackball/latest/trackball/struct.First.html\n[`Frame`]: https://docs.rs/trackball/latest/trackball/struct.Frame.html\n[`Clamp`]: https://docs.rs/trackball/latest/trackball/struct.Clamp.html\n[`Delta`]: https://docs.rs/trackball/latest/trackball/struct.Delta.html\n[`Bound`]: https://docs.rs/trackball/latest/trackball/struct.Bound.html\n[`Plane`]: https://docs.rs/trackball/latest/trackball/struct.Plane.html\n[`Scope`]: https://docs.rs/trackball/latest/trackball/struct.Scope.html\n[`Touch`]: https://docs.rs/trackball/latest/trackball/struct.Touch.html\n\n[`Fixed`]: https://docs.rs/trackball/latest/trackball/enum.Fixed.html\n[`Scope::set_fov()`]: https://docs.rs/trackball/latest/trackball/struct.Scope.html#method.set_fov\n\nSee the [release history](RELEASES.md) to keep track of the development.\n\n## Example\n\nA trackball camera mode implementation can be as easy as this by delegating events of your 3D\ngraphics library of choice to the [`Orbit`] operation handler along with other handlers.\n\n```rust\nuse trackball::{\n\tnalgebra::{Point2, Vector3},\n\tFrame, Image, Orbit,\n};\n\n/// Trackball camera mode.\npub struct Trackball {\n\t// Frame wrt camera eye and target.\n\tframe: Frame\u003cf32\u003e,\n\t// Image as projection of `Scope` wrt `Frame`.\n\timage: Image\u003cf32\u003e,\n\t// Orbit induced by displacement on screen.\n\torbit: Orbit\u003cf32\u003e,\n}\n\nimpl Trackball {\n\t// Usually, a cursor position event with left mouse button being pressed.\n\tfn handle_left_button_displacement(\u0026mut self, pos: \u0026Point2\u003cf32\u003e) {\n\t\t// Maximum position as screen's width and height.\n\t\tlet max = self.image.max();\n\t\t// Induced rotation in camera space.\n\t\tlet rot = self.orbit.compute(\u0026pos, max).unwrap_or_default();\n\t\t// Apply induced rotation to local observer frame.\n\t\tself.frame.local_orbit(\u0026rot);\n\t}\n\t// Event when left mouse button is released again.\n\tfn handle_left_button_release(\u0026mut self) {\n\t\t// Can also or instead be invoked on `Self::handle_left_button_press()`.\n\t\tself.orbit.discard();\n\t}\n}\n```\n\n## C11 Implementation\n\nUse identical [C11 implementation](c11) for [`Orbit`] operation handler behind `cc` feature gate.\n\n[`Orbit`]: https://docs.rs/trackball/latest/trackball/struct.Orbit.html\n\n## License\n\nCopyright © 2021-2025 Rouven Spreckels \u003crs@qu1x.dev\u003e\n\nThis project is licensed under either of\n\n * Apache License, Version 2.0, ([LICENSES/Apache-2.0](LICENSES/Apache-2.0) or\n   https://www.apache.org/licenses/LICENSE-2.0)\n * MIT license ([LICENSES/MIT](LICENSES/MIT) or https://opensource.org/licenses/MIT)\n\nat your option.\n\n# Contribution\n\nUnless you explicitly state otherwise, any contribution intentionally submitted for inclusion in\nthis project by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without\nany additional terms or conditions.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fqu1x%2Ftrackball","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fqu1x%2Ftrackball","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fqu1x%2Ftrackball/lists"}