-
Notifications
You must be signed in to change notification settings - Fork 1
Add schema for head & hand pose #17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| include "pose.fbs"; | ||
|
|
||
| namespace core; | ||
|
|
||
| // Describe a HandJoint pose. | ||
| struct HandJointPose { | ||
| // The concrete pose data | ||
| pose: Pose; | ||
|
|
||
| // Whether the hand pose data is valid | ||
| is_valid: bool; | ||
|
|
||
| // The radius of each joint. | ||
| // See: https://registry.khronos.org/OpenXR/specs/1.0/man/html/XrHandJointLocationEXT.html | ||
| radius: float32; | ||
| } | ||
|
|
||
| struct HandJoints { | ||
| poses: [HandJointPose:26]; | ||
| } | ||
|
|
||
| // Describe a hand pose. | ||
| table HandPose { | ||
| // Vector of HandJointPose. | ||
| // For OpenXR, this should be 26 according to XR_HAND_JOINT_COUNT_EXT | ||
| joints: HandJoints (id: 0); | ||
|
|
||
| // Whether the hand pose data is active | ||
| is_active: bool (id: 1); | ||
|
|
||
| // The timestamp of the pose data in the XrTime format (i.e. int64) | ||
| // See: https://github.com/KhronosGroup/OpenXR-SDK/blob/release-1.0.0/include/openxr/openxr.h#L113 | ||
| timestamp: int64 (id: 2); | ||
| } | ||
|
|
||
| root_type HandPose; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| include "pose.fbs"; | ||
|
|
||
| namespace core; | ||
|
|
||
| // Describe a Head pose. | ||
| table HeadPose { | ||
| // The concrete pose data | ||
| pose: Pose (id: 0); | ||
|
|
||
| // Whether the head pose data is valid | ||
| is_valid: bool (id: 1); | ||
|
|
||
| // The timestamp of the pose data in the XrTime format (i.e. int64) | ||
| // See: https://github.com/KhronosGroup/OpenXR-SDK/blob/release-1.0.0/include/openxr/openxr.h#L113 | ||
| timestamp: int64 (id: 2); | ||
| } | ||
|
|
||
| root_type HeadPose; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| namespace core; | ||
|
|
||
| struct Point { | ||
| x: float; | ||
| y: float; | ||
| z: float; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,14 +1,13 @@ | ||
| include "tensor.fbs"; | ||
| include "point.fbs"; | ||
| include "quaternion.fbs"; | ||
|
|
||
| namespace core; | ||
|
|
||
| // Describes a pose. | ||
| table Pose { | ||
| struct Pose { | ||
| // Position of the pose (x, y, z) in meters. | ||
| position: Tensor (id: 0); | ||
| position: Point (id: 0); | ||
|
|
||
| // Orientation of the pose (w, x, y, z). | ||
| orientation: Tensor (id: 1); | ||
| orientation: Quaternion (id: 1); | ||
| } | ||
|
|
||
| root_type Pose; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| namespace core; | ||
|
|
||
| struct Quaternion { | ||
| x: float; | ||
| y: float; | ||
| z: float; | ||
| w: float; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| // SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
jiwenc-nv marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| // Python bindings for the HandPose FlatBuffer schema. | ||
| // Includes HandJointPose struct, HandJoints struct, and HandPoseT table. | ||
|
|
||
| #pragma once | ||
|
|
||
| #include <memory> | ||
| #include <array> | ||
| #include <vector> | ||
| #include <cstring> | ||
|
|
||
| #include <pybind11/pybind11.h> | ||
| #include <pybind11/stl.h> | ||
|
|
||
| #include <schema/hand_generated.h> | ||
|
|
||
| namespace py = pybind11; | ||
|
|
||
| namespace core { | ||
|
|
||
| inline void bind_hand(py::module& m) { | ||
| // Bind HandJointPose struct (pose, is_valid, radius). | ||
| py::class_<HandJointPose>(m, "HandJointPose") | ||
| .def(py::init<>()) | ||
| .def(py::init<const Pose&, bool, float>(), | ||
| py::arg("pose"), | ||
| py::arg("is_valid") = false, | ||
| py::arg("radius") = 0.0f) | ||
| .def_property_readonly("pose", &HandJointPose::pose, | ||
| py::return_value_policy::reference_internal) | ||
| .def_property_readonly("is_valid", &HandJointPose::is_valid) | ||
| .def_property_readonly("radius", &HandJointPose::radius) | ||
| .def("__repr__", [](const HandJointPose& self) { | ||
| return "HandJointPose(pose=Pose(position=Point(x=" + | ||
| std::to_string(self.pose().position().x()) + | ||
| ", y=" + std::to_string(self.pose().position().y()) + | ||
| ", z=" + std::to_string(self.pose().position().z()) + | ||
| "), orientation=Quaternion(x=" + std::to_string(self.pose().orientation().x()) + | ||
| ", y=" + std::to_string(self.pose().orientation().y()) + | ||
| ", z=" + std::to_string(self.pose().orientation().z()) + | ||
| ", w=" + std::to_string(self.pose().orientation().w()) + | ||
| ")), is_valid=" + (self.is_valid() ? "True" : "False") + | ||
| ", radius=" + std::to_string(self.radius()) + ")"; | ||
| }); | ||
|
|
||
| // Bind HandJoints struct (fixed-size array of 26 HandJointPose). | ||
| py::class_<HandJoints>(m, "HandJoints") | ||
| .def(py::init<>()) | ||
| .def("poses", [](const HandJoints& self, size_t index) -> const HandJointPose* { | ||
| if (index >= 26) { | ||
| throw py::index_error("HandJoints index out of range (must be 0-25)"); | ||
| } | ||
| return (*self.poses())[index]; | ||
| }, py::arg("index"), py::return_value_policy::reference_internal, | ||
| "Get the HandJointPose at the specified index (0-25).") | ||
| .def("__len__", [](const HandJoints&) { return 26; }) | ||
| .def("__getitem__", [](const HandJoints& self, size_t index) -> const HandJointPose* { | ||
| if (index >= 26) { | ||
| throw py::index_error("HandJoints index out of range (must be 0-25)"); | ||
| } | ||
| return (*self.poses())[index]; | ||
| }, py::return_value_policy::reference_internal) | ||
| .def("__repr__", [](const HandJoints&) { | ||
| return "HandJoints(poses=[...26 HandJointPose entries...])"; | ||
| }); | ||
|
|
||
| // Bind HandPoseT class (FlatBuffers object API for tables). | ||
| py::class_<HandPoseT, std::unique_ptr<HandPoseT>>(m, "HandPoseT") | ||
| .def(py::init<>()) | ||
| .def_property_readonly( | ||
| "joints", | ||
| [](const HandPoseT& self) -> const HandJoints* { | ||
| return self.joints.get(); | ||
| }, | ||
| py::return_value_policy::reference_internal) | ||
| .def_readwrite("is_active", &HandPoseT::is_active) | ||
| .def_readwrite("timestamp", &HandPoseT::timestamp) | ||
| // Convenience method to set joints from a list of HandJointPose. | ||
| .def("set_joints", [](HandPoseT& self, const std::vector<HandJointPose>& joint_poses) { | ||
| if (joint_poses.size() != 26) { | ||
| throw std::runtime_error("HandPoseT requires exactly 26 joint poses"); | ||
| } | ||
| self.joints = std::make_unique<HandJoints>(); | ||
| // Copy each joint pose into the fixed-size array using memcpy. | ||
| // HandJoints is a POD struct with a fixed array, so this is safe. | ||
| auto* mutable_array = const_cast<flatbuffers::Array<HandJointPose, 26>*>(self.joints->poses()); | ||
| for (size_t i = 0; i < 26; ++i) { | ||
| mutable_array->Mutate(i, joint_poses[i]); | ||
| } | ||
| }, py::arg("joint_poses"), | ||
| "Set the joints from a list of 26 HandJointPose entries.") | ||
| .def("__repr__", [](const HandPoseT& self) { | ||
| std::string joints_str = "None"; | ||
| if (self.joints) { | ||
| joints_str = "HandJoints(poses=[...26 entries...])"; | ||
| } | ||
| return "HandPoseT(joints=" + joints_str + | ||
| ", is_active=" + (self.is_active ? "True" : "False") + | ||
| ", timestamp=" + std::to_string(self.timestamp) + ")"; | ||
| }); | ||
| } | ||
|
|
||
| } // namespace core | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| // SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. add new headers to cmakelists for easier access/search from IDE
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do you mean list the header file explicitly in the CMakeLists.txt?
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, along with cpp |
||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| // Python bindings for the HeadPose FlatBuffer schema. | ||
| // HeadPoseT is a table type (mutable object-API) with pose, is_valid, and timestamp fields. | ||
|
|
||
| #pragma once | ||
|
|
||
| #include <memory> | ||
|
|
||
| #include "pybind11/pybind11.h" | ||
|
|
||
| #include <schema/head_generated.h> | ||
|
|
||
| namespace py = pybind11; | ||
|
|
||
| namespace core { | ||
|
|
||
| inline void bind_head(py::module& m) { | ||
| // Bind HeadPoseT class (FlatBuffers object API for tables). | ||
| py::class_<HeadPoseT, std::unique_ptr<HeadPoseT>>(m, "HeadPoseT") | ||
| .def(py::init<>()) | ||
| .def_property_readonly( | ||
| "pose", | ||
| [](const HeadPoseT& self) -> const Pose* { | ||
| return self.pose.get(); | ||
| }, | ||
| py::return_value_policy::reference_internal) | ||
| .def_readwrite("is_valid", &HeadPoseT::is_valid) | ||
| .def_readwrite("timestamp", &HeadPoseT::timestamp) | ||
| // Convenience method to set pose from components. | ||
| .def("set_pose", [](HeadPoseT& self, const Point& position, const Quaternion& orientation) { | ||
| self.pose = std::make_unique<Pose>(position, orientation); | ||
| }, py::arg("position"), py::arg("orientation"), | ||
| "Set the pose from position and orientation components.") | ||
| .def("__repr__", [](const HeadPoseT& self) { | ||
| std::string pose_str = "None"; | ||
| if (self.pose) { | ||
| pose_str = "Pose(position=Point(x=" + std::to_string(self.pose->position().x()) + | ||
| ", y=" + std::to_string(self.pose->position().y()) + | ||
| ", z=" + std::to_string(self.pose->position().z()) + | ||
| "), orientation=Quaternion(x=" + std::to_string(self.pose->orientation().x()) + | ||
| ", y=" + std::to_string(self.pose->orientation().y()) + | ||
| ", z=" + std::to_string(self.pose->orientation().z()) + | ||
| ", w=" + std::to_string(self.pose->orientation().w()) + "))"; | ||
| } | ||
| return "HeadPoseT(pose=" + pose_str + | ||
| ", is_valid=" + (self.is_valid ? "True" : "False") + | ||
| ", timestamp=" + std::to_string(self.timestamp) + ")"; | ||
| }); | ||
| } | ||
|
|
||
| } // namespace core | ||
Uh oh!
There was an error while loading. Please reload this page.