Program Listing for File pybind11Kquantities.h#
↰ Return to documentation for file (include/Karana/Math/pybind11Kquantities.h)
/*
* Copyright (c) 2024-2026 Karana Dynamics Pty Ltd. All rights reserved.
*
* NOTICE TO USER:
*
* This source code and/or documentation (the "Licensed Materials") is
* the confidential and proprietary information of Karana Dynamics Inc.
* Use of these Licensed Materials is governed by the terms and conditions
* of a separate software license agreement between Karana Dynamics and the
* Licensee ("License Agreement"). Unless expressly permitted under that
* agreement, any reproduction, modification, distribution, or disclosure
* of the Licensed Materials, in whole or in part, to any third party
* without the prior written consent of Karana Dynamics is strictly prohibited.
*
* THE LICENSED MATERIALS ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND.
* KARANA DYNAMICS DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
* BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-INFRINGEMENT, AND
* FITNESS FOR A PARTICULAR PURPOSE.
*
* IN NO EVENT SHALL KARANA DYNAMICS BE LIABLE FOR ANY DAMAGES WHATSOEVER,
* INCLUDING BUT NOT LIMITED TO LOSS OF PROFITS, DATA, OR USE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, WHETHER IN CONTRACT, TORT,
* OR OTHERWISE ARISING OUT OF OR IN CONNECTION WITH THE LICENSED MATERIALS.
*
* U.S. Government End Users: The Licensed Materials are a "commercial item"
* as defined at 48 C.F.R. 2.101, and are provided to the U.S. Government
* only as a commercial end item under the terms of this license.
*
* Any use of the Licensed Materials in individual or commercial software must
* include, in the user documentation and internal source code comments,
* this Notice, Disclaimer, and U.S. Government Use Provision.
*/
#pragma once
#include "Karana/Math/Defs.h"
#include <format>
#include <pybind11/eigen.h>
#include <pybind11/pybind11.h>
namespace py = pybind11;
namespace km = Karana::Math;
namespace Karana::Math {
/**
* @struct FloatQuantityHelper
* @brief Simple wrapper struct to bring Length into pybind11.
*/
struct FloatQuantityHelper {
/**
* @brief Default constructor. Used by pybind11 caster.
*/
FloatQuantityHelper(){};
/**
* @brief Constructor with Length value as a double.
*
* @param v The value to store.
*/
FloatQuantityHelper(double v)
: value(v){};
/// The value expressed as a double.
double value;
/**
* @brief Conversion operator to double.
*
* @return The internal value.
*/
operator double() const { return value; }
};
/**
* @struct Length
* @brief Simple wrapper struct to bring Length into pybind11.
*/
struct Length : FloatQuantityHelper {};
/**
* @struct Angle
* @brief Simple wrapper struct to bring Angle into pybind11.
*/
struct Angle : FloatQuantityHelper {};
/**
* @struct Vec3QuantityHelper
* @brief Simple wrapper struct to bring Vec3 quantities into pybind11.
*/
struct Vec3QuantityHelper {
/**
* @brief Default constructor. Used by pybind11 caster.
*/
Vec3QuantityHelper(){};
/**
* @brief Constructor with Length value as a double.
*
* @param v The value to store.
*/
Vec3QuantityHelper(Vec3 v)
: value(v){};
/// The value expressed as a double.
Vec3 value;
/**
* @brief Conversion operator to double.
*
* @return The internal value.
*/
operator Vec3() const { return value; }
};
/**
* @struct Length3
* @brief Simple wrapper struct to bring Length3 into pybind11.
*/
struct Length3 : Vec3QuantityHelper {};
} // namespace Karana::Math
namespace pybind11::detail {
#define FLOAT_QUANTITY(cpp_type, py_type, quantity_name) \
template <> struct type_caster<cpp_type> { \
public: \
PYBIND11_TYPE_CASTER(cpp_type, \
pybind11::detail::io_name("Union[typing.SupportsFloat|" #py_type "]", \
#py_type)); \
\
/* Conversion from Python -> C++ */ \
bool load(py::handle src, bool) { \
if (!src) \
return false; \
\
/* Imports for conversion */ \
py::object py_quantity = py::module_::import("pint").attr("Quantity"); \
py::object py_length = \
py::module_::import("Karana.Math.Kquantities").attr(#quantity_name); \
\
py::object obj = py::reinterpret_borrow<py::object>(src); \
\
if (py::isinstance(obj, py_quantity)) { \
if (py::cast<bool>(obj.attr("check")(py_length))) { \
/* It's a quantity, convert to double */ \
value.value = py::cast<double>(obj.attr("to_base_units")().attr("m")); \
} else { \
throw py::type_error( \
std::format("Expected a " #quantity_name " quantity, but got units of {}", \
py::cast<std::string>(py::str(obj.attr("u"))))); \
} \
} else { \
/* Assume it's a regular float */ \
value.value = py::cast<double>(obj); \
} \
\
return true; \
} \
\
/* Conversion C++ -> Python is double -> Quantity */ \
static py::handle cast(cpp_type src, py::return_value_policy, py::handle) { \
py::object kq = py::module_::import("Karana.Math.Kquantities"); \
py::object res = \
py::float_(src.value) * kq.attr("getDefaultUnits")(kq.attr(#quantity_name)); \
return res.release(); \
} \
};
FLOAT_QUANTITY(Karana::Math::Length, Karana.Math.Ktyping.Length, length);
FLOAT_QUANTITY(Karana::Math::Angle, Karana.Math.Ktyping.Angle, angle);
#define VEC3_QUANTITY(cpp_type, py_type, quantity_name) \
template <> struct type_caster<Karana::Math::Length3> { \
public: \
PYBIND11_TYPE_CASTER(Karana::Math::Length3, \
pybind11::detail::io_name("Union[numpy.typing.ArrayLike|" #py_type \
"]", \
#py_type)); \
\
/* Conversion from Python -> C++ */ \
bool load(py::handle src, bool) { \
\
if (!src) \
return false; \
\
/* Imports for conversion */ \
py::object py_quantity = py::module_::import("pint").attr("Quantity"); \
py::object py_length = \
py::module_::import("Karana.Math.Kquantities").attr(#quantity_name); \
\
py::object obj = py::reinterpret_borrow<py::object>(src); \
\
if (py::isinstance(obj, py_quantity)) { \
\
if (py::cast<bool>(obj.attr("check")(py_length))) { \
\
/* It's a quantity, convert to double */ \
value.value = py::cast<km::Vec3>(obj.attr("to_base_units")().attr("m")); \
} else { \
\
throw py::type_error( \
std::format("Expected a Length3 quantity, but got units of {}", \
py::cast<std::string>(py::str(obj.attr("u"))))); \
} \
\
} else { \
\
/* Assume it's a regular Vec3 */ \
value.value = py::cast<km::Vec3>(obj); \
} \
return true; \
} \
\
/* Conversion C++ -> Python is Vec3 -> Quantity */ \
static py::handle cast(Karana::Math::Length3 src, py::return_value_policy, py::handle) { \
\
py::object kq = py::module_::import("Karana.Math.Kquantities"); \
\
py::object res = \
py::cast(src.value) * kq.attr("getDefaultUnits")(kq.attr(#quantity_name)); \
return res.release(); \
} \
};
VEC3_QUANTITY(Karana::Math::Length3, Karana.Math.Ktyping.Length3, length);
} // namespace pybind11::detail