LSST Applications g070148d5b3+33e5256705,g0d53e28543+25c8b88941,g0da5cf3356+2dd1178308,g1081da9e2a+62d12e78cb,g17e5ecfddb+7e422d6136,g1c76d35bf8+ede3a706f7,g295839609d+225697d880,g2e2c1a68ba+cc1f6f037e,g2ffcdf413f+853cd4dcde,g38293774b4+62d12e78cb,g3b44f30a73+d953f1ac34,g48ccf36440+885b902d19,g4b2f1765b6+7dedbde6d2,g5320a0a9f6+0c5d6105b6,g56b687f8c9+ede3a706f7,g5c4744a4d9+ef6ac23297,g5ffd174ac0+0c5d6105b6,g6075d09f38+66af417445,g667d525e37+2ced63db88,g670421136f+2ced63db88,g71f27ac40c+2ced63db88,g774830318a+463cbe8d1f,g7876bc68e5+1d137996f1,g7985c39107+62d12e78cb,g7fdac2220c+0fd8241c05,g96f01af41f+368e6903a7,g9ca82378b8+2ced63db88,g9d27549199+ef6ac23297,gabe93b2c52+e3573e3735,gb065e2a02a+3dfbe639da,gbc3249ced9+0c5d6105b6,gbec6a3398f+0c5d6105b6,gc9534b9d65+35b9f25267,gd01420fc67+0c5d6105b6,geee7ff78d7+a14128c129,gf63283c776+ede3a706f7,gfed783d017+0c5d6105b6,w.2022.47
LSST Data Management Base Package
Loading...
Searching...
No Matches
_coordinates.cc
Go to the documentation of this file.
1/*
2 * Developed for the LSST Data Management System.
3 * This product includes software developed by the LSST Project
4 * (https://www.lsst.org).
5 * See the COPYRIGHT file at the top-level directory of this distribution
6 * for details of code ownership.
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22#include "pybind11/pybind11.h"
23#include "pybind11/eigen.h"
24#include "ndarray/pybind11.h"
25
26#include "lsst/geom/Point.h"
27#include "lsst/geom/Extent.h"
30#include "lsst/utils/python.h"
31
32namespace py = pybind11;
33using namespace pybind11::literals;
34
35namespace lsst {
36namespace geom {
37namespace {
38
39template <typename Derived, typename T, int N>
40using PyCoordinateBase = py::class_<CoordinateBase<Derived, T, N>>;
41
42template <int N>
43using PyCoordinateExpr = py::class_<CoordinateExpr<N>, CoordinateBase<CoordinateExpr<N>, bool, N>>;
44
45template <typename T, int N>
46using PyExtentBase = py::class_<ExtentBase<T, N>, CoordinateBase<Extent<T, N>, T, N>>;
47
48template <typename T, int N>
49using PyExtent = py::class_<Extent<T, N>, ExtentBase<T, N>>;
50
51template <typename T, int N>
52using PyPointBase = py::class_<PointBase<T, N>, CoordinateBase<Point<T, N>, T, N>>;
53
54template <typename T, int N>
55using PyPoint = py::class_<Point<T, N>, PointBase<T, N>>;
56
57template <typename Derived, typename T, int N>
58void declareCoordinateBase(utils::python::WrapperCollection & wrappers, std::string const &suffix) {
59 static std::string const name = "CoordinateBase" + suffix;
60 wrappers.wrapType(
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)];
65 });
66 cls.def("__setitem__", [](CoordinateBase<Derived, T, N> &self, int i, T value) {
67 self[utils::python::cppIndex(N, i)] = value;
68 });
69 cls.def("__len__", [](CoordinateBase<Derived, T, N> &c) -> int { return N; });
70 }
71 );
72}
73
74template <int N>
75void declareCoordinateExpr(utils::python::WrapperCollection & wrappers, std::string const &suffix) {
76 static std::string const name = "CoordinateExpr" + suffix;
77 declareCoordinateBase<CoordinateExpr<N>, bool, N>(wrappers, name);
78 wrappers.wrapType(
79 PyCoordinateExpr<N>(wrappers.module, name.c_str()),
80 [](auto & mod, auto & cls) {
81 cls.def(py::init<bool>(), "val"_a = false);
82 cls.def("and_", &CoordinateExpr<N>::and_);
83 cls.def("or_", &CoordinateExpr<N>::or_);
84 cls.def("not_", &CoordinateExpr<N>::not_);
85 mod.def("all", all<N>);
86 mod.def("any", any<N>);
87 }
88 );
89}
90
91template <typename T, int N>
92void declareExtentBase(utils::python::WrapperCollection & wrappers, std::string const &suffix) {
93 static std::string const name = "ExtentBase" + suffix;
94 declareCoordinateBase<Extent<T, N>, T, N>(wrappers, "Extent" + suffix);
95 wrappers.wrapType(
96 PyExtentBase<T, N>(wrappers.module, name.c_str()),
97 [](auto & mod, auto & cls) {
98 // These are not the usual Python double-underscore operators - they do elementwise comparisons,
99 // returning a CoordinateExpr object with boolean x and y values. NumPy examples to the contrary
100 // notwithstanding, true Python comparison operators are expected to return scalar bools.
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); });
113
114 cls.def("asPoint", &ExtentBase<T, N>::asPoint);
115 cls.def("computeNorm", &ExtentBase<T, N>::computeNorm);
116 cls.def("computeSquaredNorm", &ExtentBase<T, N>::computeSquaredNorm);
117 }
118 );
119}
120
121// Common functionality for all Extents, including declaring base classes.
122template <typename T, int N>
123PyExtent<T, N> declareExtent(utils::python::WrapperCollection & wrappers, std::string const &suffix) {
124 static std::string const name = "Extent" + 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; },
138 py::is_operator());
139 cls.def("__mul__", [](Extent<T, N> const &self, double other) { return self * other; },
140 py::is_operator());
141 cls.def("__rmul__", [](Extent<T, N> const &self, int other) { return self * other; },
142 py::is_operator());
143 cls.def("__rmul__", [](Extent<T, N> const &self, double other) { return self * other; },
144 py::is_operator());
145 cls.def("__add__",
146 [](Extent<T, N> const &self, Extent<int, N> const &other) { return self + other; },
147 py::is_operator());
148 cls.def("__add__",
149 [](Extent<T, N> const &self, Extent<double, N> const &other) { return self + other; },
150 py::is_operator());
151 cls.def("__add__",
152 [](Extent<T, N> const &self, Point<int, N> const &other) {
153 return self + Point<T, N>(other);
154 },
155 py::is_operator());
156 cls.def("__add__",
157 [](Extent<T, N> const &self, Point<double, N> const &other) { return self + other; },
158 py::is_operator());
159 cls.def("__sub__",
160 [](Extent<T, N> const &self, Extent<int, N> const &other) {
161 return self - Extent<T, N>(other);
162 },
163 py::is_operator());
164 cls.def("__sub__",
165 [](Extent<T, N> const &self, Extent<double, N> const &other) { return self - other; },
166 py::is_operator());
167 cls.def("__eq__",
168 [](Extent<T, N> const &self, Extent<T, N> const &other) { return self == other; },
169 py::is_operator());
170 cls.def("__ne__",
171 [](Extent<T, N> const &self, Extent<T, N> const &other) { return self != other; },
172 py::is_operator());
173 cls.def("clone", [](Extent<T, N> const &self) { return Extent<T, N>{self}; });
174 }
175 );
176}
177
178// Add functionality only found in N=2 Extents (and delgate to declareExtent for the rest)
179template <typename T>
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) {
184 /* Members types and enums */
185 cls.def_property_readonly_static("dimensions", [](py::object /* cls */) { return 2; });
186 /* Constructors */
187 cls.def(py::init<int, int>(), "x"_a, "y"_a);
188 cls.def(py::init<double, double>(), "x"_a, "y"_a);
189 /* Members */
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);
198 }
199 );
200}
201
202// Add functionality only found in N=3 Extents (and delgate to declareExtent for the rest)
203template <typename T>
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 {
208 /* Member types and enums */
209 cls.def_property_readonly_static("dimensions", [](py::object /* cls */) { return 3; });
210 /* Constructors */
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);
213 /* Members */
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);
226 }
227 );
228}
229
230// Declare mixed-type and type-overloaded operators for Extent with dimension
231// N for both int and double. Because pybind11 tries operators (like any
232// overload) `in order', int has to come before double in any overloaded
233// operators that dispatch on a scalar, and hence they have to be defined here
234// instead of declareExtent.
235template <int N>
236void declareExtentOperators(utils::python::WrapperCollection & wrapper,
237 PyExtent<int, N> &clsI, PyExtent<double, N> &clsD) {
238 wrapper.wrap(
239 [clsI, clsD](auto & mod) mutable {
240 // Python's integer division works differently than C++'s for negative numbers - Python
241 // uses floor (rounds towards more negative), while C++ truncates (rounds towards zero).
242 // Therefore one needs to be careful in the definition of division operators.
243 clsI.def("__floordiv__",
244 [](Extent<int, N> const &self, int other) -> Extent<int, N> {
245 return floor(self / static_cast<double>(other));
246 },
247 py::is_operator());
248
249 clsI.def("__truediv__", [](Extent<int, N> const &self, double other) { return self / other; },
250 py::is_operator());
251 clsD.def("__truediv__", [](Extent<double, N> const &self, double other) { return self / other; },
252 py::is_operator());
253
254 clsI.def("__ifloordiv__", [](Extent<int, N> &self, int other) -> Extent<int, N> & {
255 self = floor(self / static_cast<double>(other));
256 return self;
257 });
258
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();
262 });
263 clsD.def("__itruediv__", [](Extent<double, N> &self, double other) -> Extent<double, N> & {
264 self /= other;
265 return self;
266 });
267
268 clsI.def("__iadd__", [](Extent<int, N> &self, Extent<int, N> const &other) -> Extent<int, N> & {
269 self += other;
270 return self;
271 });
272 clsD.def(
273 "__iadd__",
274 [](Extent<double, N> &self, Extent<double, N> const &other) -> Extent<double, N> & {
275 self += other;
276 return self;
277 }
278 );
279 clsD.def(
280 "__iadd__",
281 [](Extent<double, N> &self, Extent<int, N> const &other) -> Extent<double, N> & {
282 self += other;
283 return self;
284 }
285 );
286
287 clsI.def("__isub__", [](Extent<int, N> &self, Extent<int, N> const &other) -> Extent<int, N> & {
288 self -= other;
289 return self;
290 });
291 clsD.def("__isub__", [](Extent<double, N> &self, Extent<double, N> const &other) -> Extent<double, N> & {
292 self -= other;
293 return self;
294 });
295 clsD.def("__isub__", [](Extent<double, N> &self, Extent<int, N> const &other) -> Extent<double, N> & {
296 self -= other;
297 return self;
298 });
299
300 clsI.def("__imul__", [](Extent<int, N> &self, int other) -> Extent<int, N> & {
301 self *= other;
302 return self;
303 });
304 clsD.def("__imul__", [](Extent<double, N> &self, int other) -> Extent<double, N> & {
305 self *= other;
306 return self;
307 });
308 clsD.def("__imul__", [](Extent<double, N> &self, double other) -> Extent<double, N> & {
309 self *= other;
310 return self;
311 });
312
313 // Operator-like free functions
314 mod.def("truncate", truncate<N>);
315 mod.def("floor", floor<N>);
316 mod.def("ceil", ceil<N>);
317 // And method versions, since Python doens't have ADL
318 clsD.def("truncate", truncate<N>);
319 clsD.def("floor", floor<N>);
320 clsD.def("ceil", ceil<N>);
321 }
322 );
323}
324
325template <typename T, int N>
326void declarePointBase(utils::python::WrapperCollection & wrappers, std::string const &suffix) {
327 static std::string const name = "PointBase" + suffix;
328 declareCoordinateBase<Point<T, N>, T, N>(wrappers, "Point" + suffix);
329 wrappers.wrapType(
330 PyPointBase<T, N>(wrappers.module, name.c_str()),
331 [](auto & mod, auto & cls) {
332 // These are not the usual Python double-underscore operators - they do elementwise comparisons,
333 // returning a CoordinateExpr object with boolean x and y values. NumPy examples to the contrary
334 // notwithstanding, true Python comparison operators are expected to return scalar bools.
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); });
347 /* Members */
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);
353 }
354 );
355}
356
357// Common functionality
358template <typename T, int N>
359PyPoint<T, N> declarePoint(utils::python::WrapperCollection & wrappers, std::string const &suffix) {
360 static std::string const name = "Point" + 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) {
365 /* Constructors */
366 cls.def(py::init<T>(), "value"_a = static_cast<T>(0));
367 // Note that we can't use T here because both types are needed
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>());
372 /* Operators */
373 cls.def("__add__", [](Point<T, N> const &self, Extent<double, N> &other) { return self + other; },
374 py::is_operator());
375 cls.def("__add__", [](Point<T, N> const &self, Extent<int, N> &other) { return self + other; },
376 py::is_operator());
377 cls.def("__sub__", [](Point<T, N> const &self, Point<T, N> &other) { return self - other; },
378 py::is_operator());
379 cls.def("__sub__", [](Point<T, N> const &self, Extent<T, N> &other) { return self - other; },
380 py::is_operator());
381 cls.def("__sub__", [](Point<T, N> const &self, Point<double, N> &other) { return self - other; },
382 py::is_operator());
383 cls.def("__sub__", [](Point<T, N> const &self, Point<int, N> &other) { return self - other; },
384 py::is_operator());
385 cls.def("__sub__", [](Point<T, N> const &self, Extent<double, N> &other) { return self - other; },
386 py::is_operator());
387 cls.def("__sub__", [](Point<T, N> const &self, Extent<int, N> &other) { return self - other; },
388 py::is_operator());
389 cls.def("__eq__", [](Point<T, N> const &self, Point<T, N> const &other) { return self == other; },
390 py::is_operator());
391 cls.def("__ne__", [](Point<T, N> const &self, Point<T, N> const &other) { return self != other; },
392 py::is_operator());
393 /* Members */
394 cls.def("clone", [](Point<T, N> const &self) { return Point<T, N>{self}; });
395 }
396 );
397}
398
399// Add functionality only found in N=2 Points
400template <typename T>
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) {
405 /* Member types and enums */
406 cls.def_property_readonly_static("dimensions", [](py::object /* cls */) { return 2; });
407 /* Constructors */
408 cls.def(py::init<int, int>(), "x"_a, "y"_a);
409 cls.def(py::init<double, double>(), "x"_a, "y"_a);
410 /* Members */
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);
419 }
420 );
421}
422
423// Add functionality only found in N=3 Points
424template <typename T>
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) {
429 /* Member types and enums */
430 cls.def_property_readonly_static("dimensions", [](py::object /* cls */) { return 3; });
431 /* Constructors */
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);
434 /* Members */
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);
447 }
448 );
449}
450
451// Declare mixed-type and type-overloaded operators for Point with dimension
452// N for both int and double. Because pybind11 tries operators (like any
453// overload) `in order', int has to come before double in any overloaded
454// operators that dispatch on a scalar, and hence they have to be defined here
455// instead of declareExtent.
456template <int N>
457void declarePointOperators(utils::python::WrapperCollection & wrappers,
458 PyPoint<int, N> &clsI, PyPoint<double, N> &clsD) {
459 wrappers.wrap(
460 [clsI, clsD](auto & mod) mutable {
461 clsI.def("__iadd__", [](Point<int, N> &self, Extent<int, N> const &other) {
462 self += other;
463 return &self;
464 });
465 clsD.def("__iadd__", [](Point<double, N> &self, Extent<int, N> const &other) {
466 self += other;
467 return &self;
468 });
469 clsD.def("__iadd__", [](Point<double, N> &self, Extent<double, N> const &other) {
470 self += other;
471 return &self;
472 });
473 clsI.def("__isub__", [](Point<int, N> &self, Extent<int, N> const &other) {
474 self -= other;
475 return &self;
476 });
477 clsD.def("__isub__", [](Point<double, N> &self, Extent<int, N> const &other) {
478 self -= other;
479 return &self;
480 });
481 clsD.def("__isub__", [](Point<double, N> &self, Extent<double, N> const &other) {
482 self -= other;
483 return &self;
484 });
485 }
486 );
487}
488
489} // anonymous
490
491void wrapCoordinates(utils::python::WrapperCollection & wrappers) {
492 // Only the interface-level classes are defined here, and these functions
493 // call others to define their base classes, since those are never shared.
494
495 declareCoordinateExpr<2>(wrappers, "2");
496 declareCoordinateExpr<3>(wrappers, "3");
497
498 auto clsExtent2I = declareExtent2<int>(wrappers, "I");
499 auto clsExtent2D = declareExtent2<double>(wrappers, "D");
500
501 auto clsExtent3I = declareExtent3<int>(wrappers, "I");
502 auto clsExtent3D = declareExtent3<double>(wrappers, "D");
503
504 auto clsPoint2I = declarePoint2<int>(wrappers, "I");
505 auto clsPoint2D = declarePoint2<double>(wrappers, "D");
506
507 auto clsPoint3I = declarePoint3<int>(wrappers, "I");
508 auto clsPoint3D = declarePoint3<double>(wrappers, "D");
509
510 declareExtentOperators(wrappers, clsExtent2I, clsExtent2D);
511 declareExtentOperators(wrappers, clsExtent3I, clsExtent3D);
512 declarePointOperators(wrappers, clsPoint2I, clsPoint2D);
513 declarePointOperators(wrappers, clsPoint3I, clsPoint3D);
514
515}
516
517} // namespace geom
518} // namespace lsst
table::Key< std::string > name
Definition: Amplifier.cc:116
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 + ...)).
Definition: Extent.h:70
Point< T, N > asPoint() const noexcept(Super::IS_ELEMENT_NOTHROW_COPYABLE)
Cast this object to an Extent of the same numeric type and dimensionality.
Definition: Extent.cc:89
T computeSquaredNorm() const
Return the squared L2 norm of the Extent (x^2 + y^2 + ...).
Definition: Extent.h:67
T floor(T... args)
void wrapCoordinates(utils::python::WrapperCollection &wrappers)