diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index 008707fcb3..6c524c1ad5 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -64,7 +64,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: "photonlibpy-stubgen" - path: ./photon-lib/py/photonlibpy/*.pyi + path: ./photon-lib/py/photonlibpy/lib/*.pyi build-host: @@ -76,11 +76,8 @@ jobs: # Reference: https://github.com/wpilibsuite/wpilib-tool-plugin/blob/main/src/main/java/edu/wpi/first/tools/NativePlatforms.java#L23 os: - name: "ubuntu-22.04" - native_build_task: "Linuxx86-64" - name: "macos-12" - native_build_task: "Osxuniversal" - name: "windows-2022" - native_build_task: "Windowsx86-64" python_version: # - '3.8' # - '3.9' @@ -114,7 +111,7 @@ jobs: - run: ./gradlew photon-lib:tasks -i -PpythonExecutable=python${{ matrix.python_version }} - run: | chmod +x gradlew - ./gradlew photon-lib:installPhotonlibpyNative -PpythonExecutable=python${{ matrix.python_version }} -PnativeBuildPlatform=${{ matrix.os.native_build_task }} + ./gradlew photon-lib:installPhotonlibpyNative -PpythonExecutable=python${{ matrix.python_version }} - name: Install dependencies working-directory: ./photon-lib/py @@ -126,7 +123,7 @@ jobs: - uses: actions/download-artifact@v4 with: name: "photonlibpy-stubgen" - path: ./photon-lib/py/photonlibpy/*.pyi + path: ./photon-lib/py/photonlibpy/lib/*.pyi - name: Build wheel working-directory: ./photon-lib/py @@ -168,7 +165,7 @@ jobs: name: roborio build-options: "-PArchOverride=linuxathena" # gradle needs first letter uppercase - arch: "Linuxathena" + # arch: "Linuxathena" # - container: wpilib/raspbian-cross-ubuntu:bullseye-22.04-py38 # name: raspbian-py38 @@ -188,7 +185,7 @@ jobs: - container: wpilib/aarch64-cross-ubuntu:bullseye-22.04-py310 name: raspbian-aarch64-py310 build-options: "-PArchOverride=linuxarm64" - arch: "Linuxarm64" + # arch: "Linuxarm64" # - container: wpilib/aarch64-cross-ubuntu:bullseye-22.04-py311 # name: raspbian-aarch64-py311 # - container: wpilib/aarch64-cross-ubuntu:bullseye-22.04-py312 @@ -243,7 +240,7 @@ jobs: - uses: actions/download-artifact@v4 with: name: "photonlibpy-stubgen" - path: ./photon-lib/py/photonlibpy/*.pyi + path: ./photon-lib/py/photonlibpy/lib/*.pyi - name: Build wheel working-directory: ./photon-lib/py diff --git a/photon-lib/py/create_photonlib_pyi.py b/photon-lib/py/create_photonlib_pyi.py index c060b97f3d..be02c2c139 100644 --- a/photon-lib/py/create_photonlib_pyi.py +++ b/photon-lib/py/create_photonlib_pyi.py @@ -6,7 +6,7 @@ def write_stubgen(): # From nanobind==2.1.0 from nanobind.stubgen import StubGen - # this is legal since we import everything from this shared library in __init__.py + # this is legal since we import everything from this shared library in __init__.py # but still isn't /great/, lol from photonlibpy.lib import _photonlibpy as _pp diff --git a/photon-lib/py/setup.py b/photon-lib/py/setup.py index e096b5e7a4..f9df1ac091 100644 --- a/photon-lib/py/setup.py +++ b/photon-lib/py/setup.py @@ -72,6 +72,7 @@ def finalize_options(self): print("Generating typehints") try: from create_photonlib_pyi import write_stubgen + write_stubgen() except Exception as e: print(e) diff --git a/photon-lib/src/main/pybindings/cpp/photonlib_nanobind.cpp b/photon-lib/src/main/pybindings/cpp/photonlib_nanobind.cpp index 474a504360..57d2f83710 100644 --- a/photon-lib/src/main/pybindings/cpp/photonlib_nanobind.cpp +++ b/photon-lib/src/main/pybindings/cpp/photonlib_nanobind.cpp @@ -22,110 +22,8 @@ * SOFTWARE. */ -#include - -#include - -#include "photon/PhotonCamera.h" -#include "photon/simulation/VisionSystemSim.h" - -// actual nanobind include #include -#include -#include -#include - -namespace nb = nanobind; -using namespace nb::literals; - -// repr helper -template <> struct fmt::formatter : formatter { - auto format(photon::PhotonTrackedTarget const &c, format_context &ctx) const { - return fmt::format_to(ctx.out(), "PhotonTrackedTarget", c.yaw, c.pitch); - } -}; -template <> struct fmt::formatter : formatter { - auto format(photon::PhotonPipelineMetadata const &c, format_context &ctx) const { - return fmt::format_to(ctx.out(), "PhotonPipelineMetadata", c.sequenceID); - } -}; - -frc::Pose3d makePose(double x, double y, double z, double W, double X, double Y, - double Z) { - return frc::Pose3d{frc::Translation3d{units::meter_t{x}, units::meter_t{y}, - units::meter_t{z}}, - frc::Rotation3d{frc::Quaternion{W, X, Y, Z}}}; -} - -void wrap_geom(nb::module_ m) { - using namespace frc; - nb::class_(m, "Transform3d").def(nb::init<>()); - nb::class_(m, "Pose3d") - .def(nb::init<>()) - .def(nb::new_(&makePose), - "Create a Pose3d from translation/rotation components"); -} - -void wrap_photon(nb::module_ m) { - nb::class_(m, "PhotonPipelineMetadata") - .def_ro("sequenceID", &photon::PhotonPipelineMetadata::sequenceID) - .def_ro("captureTimestampMicros", - &photon::PhotonPipelineMetadata::captureTimestampMicros) - .def_ro("publishTimestampMicros", - &photon::PhotonPipelineMetadata::publishTimestampMicros); - - nb::class_(m, "PhotonTrackedTarget") - .def_ro("yaw", &photon::PhotonTrackedTarget::yaw) - .def_ro("pitch", &photon::PhotonTrackedTarget::pitch) - // String representation - .def("__repr__", [](const photon::PhotonTrackedTarget& t) { - std::string s; - fmt::format_to(std::back_inserter(s), - "{}>", t); - return s; - }); - nb::class_(m, "MultiTargetPNPResult") - .def_ro("fiducialIDsUsed", - &photon::MultiTargetPNPResult::fiducialIDsUsed); - - nb::class_(m, "PhotonPipelineResult") - .def_ro("metadata", &photon::PhotonPipelineResult::metadata) - .def_ro("targets", &photon::PhotonPipelineResult::targets) - .def_ro("multitagResult", &photon::PhotonPipelineResult::multitagResult) - .def("__repr__", [](const photon::PhotonPipelineResult& t) { - std::string s; - fmt::format_to(std::back_inserter(s), - "PhotonPipelineResult", t.metadata, fmt::join(t.targets, ", ")); - return s; - }); - - nb::class_(m, "PhotonCamera") - .def(nb::init()) - .def("GetDriverMode", &photon::PhotonCamera::GetDriverMode) - .def("GetLatestResult", &photon::PhotonCamera::GetLatestResult); -} - -void wrap_photon_sim(nb::module_ m) { - using namespace photon; - - nb::class_(m, "VisionSystemSim") - .def(nb::init()) - .def("AddCamera", &VisionSystemSim::AddCamera) - .def("AddVisionTargets", - nb::overload_cast&>( - &VisionSystemSim::AddVisionTargets)) - .def("Update", - nb::overload_cast(&VisionSystemSim::Update)); - - nb::class_(m, "PhotonCameraSim") - .def(nb::init()); - - nb::class_(m, "VisionTargetSim") - .def(nb::init(), "pose"_a, "model"_a, "Create a simulated target at a given pose") - .def(nb::init(), "pose"_a, "model"_a, "fiducial_id"_a, "Create a simulated AprilTag at a given pose"); - - nb::class_(m, "TargetModel").def(nb::init()); -} +#include "photonlib_nanobind.hpp" NB_MODULE(_photonlibpy, m) { m.doc() = "C++ bindings for photonlib"; diff --git a/photon-lib/src/main/pybindings/cpp/photonlib_nanobind.hpp b/photon-lib/src/main/pybindings/cpp/photonlib_nanobind.hpp new file mode 100644 index 0000000000..3eb9deee3c --- /dev/null +++ b/photon-lib/src/main/pybindings/cpp/photonlib_nanobind.hpp @@ -0,0 +1,29 @@ +/* + * MIT License + * + * Copyright (c) PhotonVision + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +void wrap_geom(nanobind::module_ m); +void wrap_photon(nanobind::module_ m); +void wrap_photon_sim(nanobind::module_ m); diff --git a/photon-lib/src/main/pybindings/cpp/wrap_geom.cpp b/photon-lib/src/main/pybindings/cpp/wrap_geom.cpp new file mode 100644 index 0000000000..cb1e74d49e --- /dev/null +++ b/photon-lib/src/main/pybindings/cpp/wrap_geom.cpp @@ -0,0 +1,56 @@ +/* + * MIT License + * + * Copyright (c) PhotonVision + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +#include + +#include "photon/PhotonCamera.h" +#include "photon/simulation/VisionSystemSim.h" +#include "photonlib_nanobind.hpp" + +// actual nanobind include +#include +#include +#include +#include + +namespace nb = nanobind; +using namespace nb::literals; + +frc::Pose3d makePose(double x, double y, double z, double W, double X, double Y, + double Z) { + return frc::Pose3d{frc::Translation3d{units::meter_t{x}, units::meter_t{y}, + units::meter_t{z}}, + frc::Rotation3d{frc::Quaternion{W, X, Y, Z}}}; +} + +void wrap_geom(nb::module_ m) { + using namespace frc; + nb::class_(m, "Transform3d").def(nb::init<>()); + nb::class_(m, "Pose3d") + .def(nb::init<>()) + .def(nb::new_(&makePose), + "Create a Pose3d from translation/rotation components"); +} diff --git a/photon-lib/src/main/pybindings/cpp/wrap_photonlib.cpp b/photon-lib/src/main/pybindings/cpp/wrap_photonlib.cpp new file mode 100644 index 0000000000..920b714543 --- /dev/null +++ b/photon-lib/src/main/pybindings/cpp/wrap_photonlib.cpp @@ -0,0 +1,91 @@ +/* + * MIT License + * + * Copyright (c) PhotonVision + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +#include + +#include "photon/PhotonCamera.h" +#include "photon/simulation/VisionSystemSim.h" +#include "photonlib_nanobind.hpp" + +// actual nanobind include +#include +#include +#include +#include + +namespace nb = nanobind; +using namespace nb::literals; + +// repr helper +template <> struct fmt::formatter : formatter { + auto format(photon::PhotonTrackedTarget const &c, format_context &ctx) const { + return fmt::format_to(ctx.out(), "PhotonTrackedTarget", c.yaw, c.pitch); + } +}; +template <> struct fmt::formatter : formatter { + auto format(photon::PhotonPipelineMetadata const &c, format_context &ctx) const { + return fmt::format_to(ctx.out(), "PhotonPipelineMetadata", c.sequenceID); + } +}; + +void wrap_photon(nb::module_ m) { + nb::class_(m, "PhotonPipelineMetadata") + .def_ro("sequenceID", &photon::PhotonPipelineMetadata::sequenceID) + .def_ro("captureTimestampMicros", + &photon::PhotonPipelineMetadata::captureTimestampMicros) + .def_ro("publishTimestampMicros", + &photon::PhotonPipelineMetadata::publishTimestampMicros); + + nb::class_(m, "PhotonTrackedTarget") + .def_ro("yaw", &photon::PhotonTrackedTarget::yaw) + .def_ro("pitch", &photon::PhotonTrackedTarget::pitch) + // String representation + .def("__repr__", [](const photon::PhotonTrackedTarget& t) { + std::string s; + fmt::format_to(std::back_inserter(s), + "{}>", t); + return s; + }); + nb::class_(m, "MultiTargetPNPResult") + .def_ro("fiducialIDsUsed", + &photon::MultiTargetPNPResult::fiducialIDsUsed); + + nb::class_(m, "PhotonPipelineResult") + .def_ro("metadata", &photon::PhotonPipelineResult::metadata) + .def_ro("targets", &photon::PhotonPipelineResult::targets) + .def_ro("multitagResult", &photon::PhotonPipelineResult::multitagResult) + .def("__repr__", [](const photon::PhotonPipelineResult& t) { + std::string s; + fmt::format_to(std::back_inserter(s), + "PhotonPipelineResult", t.metadata, fmt::join(t.targets, ", ")); + return s; + }); + + nb::class_(m, "PhotonCamera") + .def(nb::init()) + .def("GetDriverMode", &photon::PhotonCamera::GetDriverMode) + .def("GetLatestResult", &photon::PhotonCamera::GetLatestResult); +} diff --git a/photon-lib/src/main/pybindings/cpp/wrap_photonlib_sim.cpp b/photon-lib/src/main/pybindings/cpp/wrap_photonlib_sim.cpp new file mode 100644 index 0000000000..6daa9506f0 --- /dev/null +++ b/photon-lib/src/main/pybindings/cpp/wrap_photonlib_sim.cpp @@ -0,0 +1,62 @@ +/* + * MIT License + * + * Copyright (c) PhotonVision + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +#include + +#include "photon/PhotonCamera.h" +#include "photon/simulation/VisionSystemSim.h" +#include "photonlib_nanobind.hpp" + +// actual nanobind include +#include +#include +#include +#include + +namespace nb = nanobind; +using namespace nb::literals; + +void wrap_photon_sim(nb::module_ m) { + using namespace photon; + + nb::class_(m, "VisionSystemSim") + .def(nb::init()) + .def("AddCamera", &VisionSystemSim::AddCamera) + .def("AddVisionTargets", + nb::overload_cast&>( + &VisionSystemSim::AddVisionTargets)) + .def("Update", + nb::overload_cast(&VisionSystemSim::Update)); + + nb::class_(m, "PhotonCameraSim") + .def(nb::init()); + + nb::class_(m, "VisionTargetSim") + .def(nb::init(), "pose"_a, "model"_a, "Create a simulated target at a given pose") + .def(nb::init(), "pose"_a, "model"_a, "fiducial_id"_a, "Create a simulated AprilTag at a given pose"); + + nb::class_(m, "TargetModel").def(nb::init()); +} diff --git a/test.py b/test.py deleted file mode 100644 index 290ebfaf97..0000000000 --- a/test.py +++ /dev/null @@ -1,3 +0,0 @@ -import photonlibpy -print(photonlibpy) -print(photonlibpy.PhotonCamera("foobar").GetLatestResult())