22#include "pybind11/pybind11.h"
23#include "pybind11/eigen.h"
24#include "ndarray/pybind11.h"
33using namespace pybind11::literals;
39template <
typename Derived,
typename T,
int N>
40using PyCoordinateBase = py::class_<CoordinateBase<Derived, T, N>>;
43using PyCoordinateExpr = py::class_<CoordinateExpr<N>, CoordinateBase<CoordinateExpr<N>, bool, N>>;
45template <
typename T,
int N>
46using PyExtentBase = py::class_<ExtentBase<T, N>, CoordinateBase<Extent<T, N>,
T, N>>;
48template <
typename T,
int N>
49using PyExtent = py::class_<Extent<T, N>, ExtentBase<T, N>>;
51template <
typename T,
int N>
52using PyPointBase = py::class_<PointBase<T, N>, CoordinateBase<Point<T, N>,
T, N>>;
54template <
typename T,
int N>
55using PyPoint = py::class_<Point<T, N>, PointBase<T, N>>;
57template <
typename Derived,
typename T,
int N>
58void declareCoordinateBase(utils::python::WrapperCollection & wrappers,
std::string const &suffix) {
61 PyCoordinateBase<Derived, T, N>(wrappers.module,
name.c_str()),
62 [](
auto & mod,
auto & cls) {
63 cls.def(
"__getitem__", [](CoordinateBase<Derived, T, N> &self, int i) -> T {
64 return self[utils::python::cppIndex(N, i)];
66 cls.def(
"__setitem__", [](CoordinateBase<Derived, T, N> &self,
int i, T value) {
67 self[utils::python::cppIndex(N, i)] = value;
69 cls.def(
"__len__", [](CoordinateBase<Derived, T, N> &c) ->
int {
return N; });
75void declareCoordinateExpr(utils::python::WrapperCollection & wrappers,
std::string const &suffix) {
77 declareCoordinateBase<CoordinateExpr<N>, bool, N>(wrappers,
name);
79 PyCoordinateExpr<N>(wrappers.module,
name.c_str()),
80 [](
auto & mod,
auto &
cls) {
81 cls.def(py::init<bool>(),
"val"_a =
false);
85 mod.def(
"all", all<N>);
86 mod.def(
"any", any<N>);
91template <
typename T,
int N>
92void declareExtentBase(utils::python::WrapperCollection & wrappers,
std::string const &suffix) {
94 declareCoordinateBase<Extent<T, N>,
T, N>(wrappers,
"Extent" + suffix);
96 PyExtentBase<T, N>(wrappers.module,
name.c_str()),
97 [](
auto & mod,
auto &
cls) {
101 cls.def(
"eq", [](ExtentBase<T, N>
const &self, Extent<T, N> other) {
return self.eq(other); });
102 cls.def(
"ne", [](ExtentBase<T, N>
const &self, Extent<T, N> other) {
return self.ne(other); });
103 cls.def(
"lt", [](ExtentBase<T, N>
const &self, Extent<T, N> other) {
return self.lt(other); });
104 cls.def(
"le", [](ExtentBase<T, N>
const &self, Extent<T, N> other) {
return self.le(other); });
105 cls.def(
"gt", [](ExtentBase<T, N>
const &self, Extent<T, N> other) {
return self.gt(other); });
106 cls.def(
"ge", [](ExtentBase<T, N>
const &self, Extent<T, N> other) {
return self.ge(other); });
107 cls.def(
"eq", [](ExtentBase<T, N>
const &self, T other) {
return self.eq(other); });
108 cls.def(
"ne", [](ExtentBase<T, N>
const &self, T other) {
return self.ne(other); });
109 cls.def(
"lt", [](ExtentBase<T, N>
const &self, T other) {
return self.lt(other); });
110 cls.def(
"le", [](ExtentBase<T, N>
const &self, T other) {
return self.le(other); });
111 cls.def(
"gt", [](ExtentBase<T, N>
const &self, T other) {
return self.gt(other); });
112 cls.def(
"ge", [](ExtentBase<T, N>
const &self, T other) {
return self.ge(other); });
122template <
typename T,
int N>
123PyExtent<T, N> declareExtent(utils::python::WrapperCollection & wrappers,
std::string const &suffix) {
125 declareExtentBase<T, N>(wrappers, suffix);
126 return wrappers.wrapType(
127 PyExtent<T, N>(wrappers.module,
name.c_str()),
128 [](
auto & mod,
auto & cls) {
129 cls.def(py::init<T>(),
"value"_a = static_cast<T>(0));
130 cls.def(py::init<Point<int, N> const &>());
131 cls.def(py::init<Point<T, N> const &>());
132 cls.def(py::init<Extent<int, N> const &>());
133 cls.def(py::init<Extent<T, N> const &>());
134 cls.def(py::init<typename Extent<T, N>::EigenVector>());
135 cls.def(
"__neg__", [](Extent<T, N> const &self) { return -self; });
136 cls.def(
"__pos__", [](Extent<T, N>
const &self) {
return self; });
137 cls.def(
"__mul__", [](Extent<T, N>
const &self,
int other) {
return self * other; },
139 cls.def(
"__mul__", [](Extent<T, N>
const &self,
double other) {
return self * other; },
141 cls.def(
"__rmul__", [](Extent<T, N>
const &self,
int other) {
return self * other; },
143 cls.def(
"__rmul__", [](Extent<T, N>
const &self,
double other) {
return self * other; },
146 [](Extent<T, N>
const &self, Extent<int, N>
const &other) {
return self + other; },
149 [](Extent<T, N>
const &self, Extent<double, N>
const &other) {
return self + other; },
152 [](Extent<T, N>
const &self, Point<int, N>
const &other) {
153 return self + Point<T, N>(other);
157 [](Extent<T, N>
const &self, Point<double, N>
const &other) {
return self + other; },
160 [](Extent<T, N>
const &self, Extent<int, N>
const &other) {
161 return self - Extent<T, N>(other);
165 [](Extent<T, N>
const &self, Extent<double, N>
const &other) {
return self - other; },
168 [](Extent<T, N>
const &self, Extent<T, N>
const &other) {
return self == other; },
171 [](Extent<T, N>
const &self, Extent<T, N>
const &other) {
return self != other; },
173 cls.def(
"clone", [](Extent<T, N>
const &self) {
return Extent<T, N>{self}; });
180PyExtent<T, 2> declareExtent2(utils::python::WrapperCollection & wrappers,
std::string const &suffix) {
181 return wrappers.wrapType(
182 declareExtent<T, 2>(wrappers,
std::string(
"2") + suffix),
183 [](
auto & mod,
auto & cls) {
185 cls.def_property_readonly_static(
"dimensions", [](py::object ) {
return 2; });
187 cls.def(py::init<int, int>(),
"x"_a,
"y"_a);
188 cls.def(py::init<double, double>(),
"x"_a,
"y"_a);
190 auto getX = py::overload_cast<>(&Extent<T, 2>::getX, py::const_);
191 auto getY = py::overload_cast<>(&Extent<T, 2>::getY, py::const_);
192 cls.def(
"getX", getX);
193 cls.def(
"getY", getY);
194 cls.def(
"setX", &Extent<T, 2>::setX);
195 cls.def(
"setY", &Extent<T, 2>::setY);
196 cls.def_property(
"x", getX, &Extent<T, 2>::setX);
197 cls.def_property(
"y", getY, &Extent<T, 2>::setY);
204PyExtent<T, 3> declareExtent3(utils::python::WrapperCollection & wrappers,
const std::string &suffix) {
205 return wrappers.wrapType(
206 declareExtent<T, 3>(wrappers,
std::string(
"3") + suffix),
207 [](
auto & mod,
auto & cls)
mutable {
209 cls.def_property_readonly_static(
"dimensions", [](py::object ) {
return 3; });
211 cls.def(py::init<int, int, int>(),
"x"_a,
"y"_a,
"z"_a);
212 cls.def(py::init<double, double, double>(),
"x"_a,
"y"_a,
"z"_a);
214 auto getX = py::overload_cast<>(&Extent<T, 3>::getX, py::const_);
215 auto getY = py::overload_cast<>(&Extent<T, 3>::getY, py::const_);
216 auto getZ = py::overload_cast<>(&Extent<T, 3>::getZ, py::const_);
217 cls.def(
"getX", getX);
218 cls.def(
"getY", getY);
219 cls.def(
"getZ", getZ);
220 cls.def(
"setX", &Extent<T, 3>::setX);
221 cls.def(
"setY", &Extent<T, 3>::setY);
222 cls.def(
"setZ", &Extent<T, 3>::setZ);
223 cls.def_property(
"x", getX, &Extent<T, 3>::setX);
224 cls.def_property(
"y", getY, &Extent<T, 3>::setY);
225 cls.def_property(
"z", getZ, &Extent<T, 3>::setZ);
236void declareExtentOperators(utils::python::WrapperCollection & wrapper,
237 PyExtent<int, N> &clsI, PyExtent<double, N> &clsD) {
239 [clsI, clsD](
auto & mod)
mutable {
243 clsI.def(
"__floordiv__",
244 [](Extent<int, N>
const &self,
int other) -> Extent<int, N> {
245 return floor(self /
static_cast<double>(other));
249 clsI.def(
"__truediv__", [](Extent<int, N>
const &self,
double other) {
return self / other; },
251 clsD.def(
"__truediv__", [](Extent<double, N>
const &self,
double other) {
return self / other; },
254 clsI.def(
"__ifloordiv__", [](Extent<int, N> &self,
int other) -> Extent<int, N> & {
255 self =
floor(self /
static_cast<double>(other));
259 clsI.def(
"__itruediv__", [](Extent<int, N> &self,
double other) {
260 PyErr_SetString(PyExc_TypeError,
"In-place true division not supported for Extent<int,N>.");
261 throw py::error_already_set();
263 clsD.def(
"__itruediv__", [](Extent<double, N> &self,
double other) -> Extent<double, N> & {
268 clsI.def(
"__iadd__", [](Extent<int, N> &self, Extent<int, N>
const &other) -> Extent<int, N> & {
274 [](Extent<double, N> &self, Extent<double, N>
const &other) -> Extent<double, N> & {
281 [](Extent<double, N> &self, Extent<int, N>
const &other) -> Extent<double, N> & {
287 clsI.def(
"__isub__", [](Extent<int, N> &self, Extent<int, N>
const &other) -> Extent<int, N> & {
291 clsD.def(
"__isub__", [](Extent<double, N> &self, Extent<double, N>
const &other) -> Extent<double, N> & {
295 clsD.def(
"__isub__", [](Extent<double, N> &self, Extent<int, N>
const &other) -> Extent<double, N> & {
300 clsI.def(
"__imul__", [](Extent<int, N> &self,
int other) -> Extent<int, N> & {
304 clsD.def(
"__imul__", [](Extent<double, N> &self,
int other) -> Extent<double, N> & {
308 clsD.def(
"__imul__", [](Extent<double, N> &self,
double other) -> Extent<double, N> & {
314 mod.def(
"truncate", truncate<N>);
315 mod.def(
"floor", floor<N>);
316 mod.def(
"ceil", ceil<N>);
318 clsD.def(
"truncate", truncate<N>);
319 clsD.def(
"floor", floor<N>);
320 clsD.def(
"ceil", ceil<N>);
325template <
typename T,
int N>
326void declarePointBase(utils::python::WrapperCollection & wrappers,
std::string const &suffix) {
328 declareCoordinateBase<Point<T, N>,
T, N>(wrappers,
"Point" + suffix);
330 PyPointBase<T, N>(wrappers.module,
name.c_str()),
331 [](
auto & mod,
auto &
cls) {
335 cls.def(
"eq", [](PointBase<T, N>
const &self, Point<T, N>
const &rhs) {
return self.eq(rhs); });
336 cls.def(
"ne", [](PointBase<T, N>
const &self, Point<T, N>
const &rhs) {
return self.ne(rhs); });
337 cls.def(
"lt", [](PointBase<T, N>
const &self, Point<T, N>
const &rhs) {
return self.lt(rhs); });
338 cls.def(
"le", [](PointBase<T, N>
const &self, Point<T, N>
const &rhs) {
return self.le(rhs); });
339 cls.def(
"gt", [](PointBase<T, N>
const &self, Point<T, N>
const &rhs) {
return self.gt(rhs); });
340 cls.def(
"ge", [](PointBase<T, N>
const &self, Point<T, N>
const &rhs) {
return self.ge(rhs); });
341 cls.def(
"eq", [](PointBase<T, N>
const &self, T rhs) {
return self.eq(rhs); });
342 cls.def(
"ne", [](PointBase<T, N>
const &self, T rhs) {
return self.ne(rhs); });
343 cls.def(
"lt", [](PointBase<T, N>
const &self, T rhs) {
return self.lt(rhs); });
344 cls.def(
"le", [](PointBase<T, N>
const &self, T rhs) {
return self.le(rhs); });
345 cls.def(
"gt", [](PointBase<T, N>
const &self, T rhs) {
return self.gt(rhs); });
346 cls.def(
"ge", [](PointBase<T, N>
const &self, T rhs) {
return self.ge(rhs); });
348 cls.def(
"asExtent", &PointBase<T, N>::asExtent);
349 cls.def(
"shift", &PointBase<T, N>::shift);
350 cls.def(
"scale", &PointBase<T, N>::scale);
351 cls.def(
"distanceSquared", &PointBase<T, N>::distanceSquared);
352 cls.def(
"toString", &PointBase<T, N>::toString);
358template <
typename T,
int N>
359PyPoint<T, N> declarePoint(utils::python::WrapperCollection & wrappers,
std::string const &suffix) {
361 declarePointBase<T, N>(wrappers, suffix);
362 return wrappers.wrapType(
363 PyPoint<T, N>(wrappers.module,
name.c_str()),
364 [](
auto & mod,
auto & cls) {
366 cls.def(py::init<T>(),
"value"_a = static_cast<T>(0));
368 cls.def(py::init<Point<double, N> const &>());
369 cls.def(py::init<Point<int, N> const &>());
370 cls.def(py::init<Extent<T, N> const &>());
371 cls.def(py::init<typename Point<T, N>::EigenVector>());
373 cls.def(
"__add__", [](Point<T, N> const &self, Extent<double, N> &other) { return self + other; },
375 cls.def(
"__add__", [](Point<T, N>
const &self, Extent<int, N> &other) {
return self + other; },
377 cls.def(
"__sub__", [](Point<T, N>
const &self, Point<T, N> &other) {
return self - other; },
379 cls.def(
"__sub__", [](Point<T, N>
const &self, Extent<T, N> &other) {
return self - other; },
381 cls.def(
"__sub__", [](Point<T, N>
const &self, Point<double, N> &other) {
return self - other; },
383 cls.def(
"__sub__", [](Point<T, N>
const &self, Point<int, N> &other) {
return self - other; },
385 cls.def(
"__sub__", [](Point<T, N>
const &self, Extent<double, N> &other) {
return self - other; },
387 cls.def(
"__sub__", [](Point<T, N>
const &self, Extent<int, N> &other) {
return self - other; },
389 cls.def(
"__eq__", [](Point<T, N>
const &self, Point<T, N>
const &other) {
return self == other; },
391 cls.def(
"__ne__", [](Point<T, N>
const &self, Point<T, N>
const &other) {
return self != other; },
394 cls.def(
"clone", [](Point<T, N>
const &self) {
return Point<T, N>{self}; });
401PyPoint<T, 2> declarePoint2(utils::python::WrapperCollection & wrappers,
std::string const &suffix) {
402 return wrappers.wrapType(
403 declarePoint<T, 2>(wrappers,
std::string(
"2") + suffix),
404 [](
auto & mod,
auto & cls) {
406 cls.def_property_readonly_static(
"dimensions", [](py::object ) {
return 2; });
408 cls.def(py::init<int, int>(),
"x"_a,
"y"_a);
409 cls.def(py::init<double, double>(),
"x"_a,
"y"_a);
411 auto getX = py::overload_cast<>(&Point<T, 2>::getX, py::const_);
412 auto getY = py::overload_cast<>(&Point<T, 2>::getY, py::const_);
413 cls.def(
"getX", getX);
414 cls.def(
"getY", getY);
415 cls.def(
"setX", &Point<T, 2>::setX);
416 cls.def(
"setY", &Point<T, 2>::setY);
417 cls.def_property(
"x", getX, &Point<T, 2>::setX);
418 cls.def_property(
"y", getY, &Point<T, 2>::setY);
425PyPoint<T, 3> declarePoint3(utils::python::WrapperCollection & wrappers,
std::string const &suffix) {
426 return wrappers.wrapType(
427 declarePoint<T, 3>(wrappers,
std::string(
"3") + suffix),
428 [](
auto & mod,
auto & cls) {
430 cls.def_property_readonly_static(
"dimensions", [](py::object ) {
return 3; });
432 cls.def(py::init<int, int, int>(),
"x"_a,
"y"_a,
"z"_a);
433 cls.def(py::init<double, double, double>(),
"x"_a,
"y"_a,
"z"_a);
435 auto getX = py::overload_cast<>(&Point<T, 3>::getX, py::const_);
436 auto getY = py::overload_cast<>(&Point<T, 3>::getY, py::const_);
437 auto getZ = py::overload_cast<>(&Point<T, 3>::getZ, py::const_);
438 cls.def(
"getX", getX);
439 cls.def(
"getY", getY);
440 cls.def(
"getZ", getZ);
441 cls.def(
"setX", &Point<T, 3>::setX);
442 cls.def(
"setY", &Point<T, 3>::setY);
443 cls.def(
"setZ", &Point<T, 3>::setZ);
444 cls.def_property(
"x", getX, &Point<T, 3>::setX);
445 cls.def_property(
"y", getY, &Point<T, 3>::setY);
446 cls.def_property(
"z", getZ, &Point<T, 3>::setZ);
457void declarePointOperators(utils::python::WrapperCollection & wrappers,
458 PyPoint<int, N> &clsI, PyPoint<double, N> &clsD) {
460 [clsI, clsD](
auto & mod)
mutable {
461 clsI.def(
"__iadd__", [](Point<int, N> &self, Extent<int, N>
const &other) {
465 clsD.def(
"__iadd__", [](Point<double, N> &self, Extent<int, N>
const &other) {
469 clsD.def(
"__iadd__", [](Point<double, N> &self, Extent<double, N>
const &other) {
473 clsI.def(
"__isub__", [](Point<int, N> &self, Extent<int, N>
const &other) {
477 clsD.def(
"__isub__", [](Point<double, N> &self, Extent<int, N>
const &other) {
481 clsD.def(
"__isub__", [](Point<double, N> &self, Extent<double, N>
const &other) {
495 declareCoordinateExpr<2>(wrappers,
"2");
496 declareCoordinateExpr<3>(wrappers,
"3");
498 auto clsExtent2I = declareExtent2<int>(wrappers,
"I");
499 auto clsExtent2D = declareExtent2<double>(wrappers,
"D");
501 auto clsExtent3I = declareExtent3<int>(wrappers,
"I");
502 auto clsExtent3D = declareExtent3<double>(wrappers,
"D");
504 auto clsPoint2I = declarePoint2<int>(wrappers,
"I");
505 auto clsPoint2D = declarePoint2<double>(wrappers,
"D");
507 auto clsPoint3I = declarePoint3<int>(wrappers,
"I");
508 auto clsPoint3D = declarePoint3<double>(wrappers,
"D");
510 declareExtentOperators(wrappers, clsExtent2I, clsExtent2D);
511 declareExtentOperators(wrappers, clsExtent3I, clsExtent3D);
512 declarePointOperators(wrappers, clsPoint2I, clsPoint2D);
513 declarePointOperators(wrappers, clsPoint3I, clsPoint3D);
table::Key< std::string > name
CoordinateExpr not_() const noexcept
CoordinateExpr and_(CoordinateExpr const &rhs) const noexcept
CoordinateExpr or_(CoordinateExpr const &rhs) const noexcept
T computeNorm() const
Return the L2 norm of the Extent (sqrt(x^2 + y^2 + ...)).
Point< T, N > asPoint() const noexcept(Super::IS_ELEMENT_NOTHROW_COPYABLE)
Cast this object to an Extent of the same numeric type and dimensionality.
T computeSquaredNorm() const
Return the squared L2 norm of the Extent (x^2 + y^2 + ...).
void wrapCoordinates(utils::python::WrapperCollection &wrappers)