1 //
2 // SPDX-License-Identifier: BSD-3-Clause
3 // Copyright Contributors to the OpenEXR Project.
4 //
5
6 // clang-format off
7
8 #include <Python.h>
9 #include <boost/python.hpp>
10 #include <boost/format.hpp>
11 #include "PyImath.h"
12 #include "PyImathMathExc.h"
13 #include "PyImathVec.h"
14 #include "PyImathFrustum.h"
15 #include "PyImathDecorators.h"
16 #include "PyImathExport.h"
17
18 namespace PyImath{
19 using namespace boost::python;
20 using namespace IMATH_NAMESPACE;
21
22 template <class T> struct FrustumName {static const char *value;};
23 template <> const char *FrustumName<float>::value = "Frustumf";
24 template <> const char *FrustumName<double>::value = "Frustumd";
25
26 template <class T> struct FrustumTestName {static const char *value;};
27 template <> const char *FrustumTestName<float>::value = "FrustumTestf";
28 template <> const char *FrustumTestName<double>::value = "FrustumTestd";
29
30
31 template <class T>
Frustum_repr(const Frustum<T> & f)32 static std::string Frustum_repr(const Frustum<T> &f)
33 {
34 std::stringstream stream;
35 stream << FrustumName<T>::value << "(" << f.nearPlane() << ", " << f.farPlane() << ", "
36 << f.left() << ", " << f.right() << ", " << f.top() << ", "
37 << f.bottom() << ", " << f.orthographic() << ")";
38 return stream.str();
39 }
40
41 template <class T>
42 static void
modifyNearAndFar(Frustum<T> & f,T nearPlane,T farPlane)43 modifyNearAndFar(Frustum<T> &f, T nearPlane, T farPlane)
44 {
45 MATH_EXC_ON;
46 f.modifyNearAndFar (nearPlane, farPlane);
47 }
48
49 template <class T>
50 static T
fovx(Frustum<T> & f)51 fovx(Frustum<T> &f)
52 {
53 MATH_EXC_ON;
54 return f.fovx();
55 }
56
57 template <class T>
58 static T
fovy(Frustum<T> & f)59 fovy(Frustum<T> &f)
60 {
61 MATH_EXC_ON;
62 return f.fovy();
63 }
64
65 template <class T>
66 static T
aspect(Frustum<T> & f)67 aspect(Frustum<T> &f)
68 {
69 MATH_EXC_ON;
70 return f.aspect();
71 }
72
73 template <class T>
74 static Matrix44<T>
projectionMatrix(Frustum<T> & f)75 projectionMatrix(Frustum<T> &f)
76 {
77 MATH_EXC_ON;
78 return f.projectionMatrix();
79 }
80
81 template <class T>
82 static Frustum<T>
window(Frustum<T> & f,T l,T r,T b,T t)83 window (Frustum<T> &f, T l, T r, T b, T t)
84 {
85 MATH_EXC_ON;
86 return f.window(l, r, b, t);
87 }
88
89 template <class T>
90 static Line3<T>
projectScreenToRay(Frustum<T> & f,const Vec2<T> & p)91 projectScreenToRay (Frustum<T> &f, const Vec2<T> &p)
92 {
93 MATH_EXC_ON;
94 return f.projectScreenToRay(p);
95 }
96
97 template <class T>
98 static Line3<T>
projectScreenToRayTuple(Frustum<T> & f,const tuple & t)99 projectScreenToRayTuple(Frustum<T> &f, const tuple &t)
100 {
101 MATH_EXC_ON;
102 if(t.attr("__len__")() == 2)
103 {
104 Vec2<T> point;
105 point.x = extract<T>(t[0]);
106 point.y = extract<T>(t[1]);
107 return f.projectScreenToRay(point);
108 }
109 else
110 throw std::invalid_argument ( "projectScreenToRay expects tuple of length 2");
111
112 }
113
114 template <class T>
115 static Vec2<T>
projectPointToScreen(Frustum<T> & f,const Vec3<T> & p)116 projectPointToScreen (Frustum<T> &f, const Vec3<T> &p)
117 {
118 MATH_EXC_ON;
119 return f.projectPointToScreen(p);
120 }
121
122 template <class T>
123 static Vec2<T>
projectPointToScreenTuple(Frustum<T> & f,const tuple & t)124 projectPointToScreenTuple(Frustum<T> &f, const tuple &t)
125 {
126 MATH_EXC_ON;
127 if(t.attr("__len__")() == 3)
128 {
129 Vec3<T> point;
130 point.x = extract<T>(t[0]);
131 point.y = extract<T>(t[1]);
132 point.z = extract<T>(t[2]);
133 return f.projectPointToScreen(point);
134 }
135 else
136 throw std::invalid_argument ( "projectPointToScreen expects tuple of length 3");
137
138 }
139
140 template <class T>
141 static Vec2<T>
projectPointToScreenObj(Frustum<T> & f,const object & o)142 projectPointToScreenObj(Frustum<T> &f, const object &o)
143 {
144 MATH_EXC_ON;
145 Vec3<T> v;
146 if (PyImath::V3<T>::convert (o.ptr(), &v))
147 return f.projectPointToScreen(v);
148 else
149 throw std::invalid_argument ( "projectPointToScreen expects tuple of length 3");
150 }
151
152 template <class T>
153 static T
ZToDepth(Frustum<T> & f,long z,long min,long max)154 ZToDepth(Frustum<T> &f, long z, long min, long max)
155 {
156 MATH_EXC_ON;
157 return f.ZToDepth(z, min, max);
158 }
159
160 template <class T>
161 static T
normalizedZToDepth(Frustum<T> & f,T z)162 normalizedZToDepth(Frustum<T> &f, T z)
163 {
164 MATH_EXC_ON;
165 return f.normalizedZToDepth(z);
166 }
167
168 template <class T>
169 static long
DepthToZ(Frustum<T> & f,T depth,long min,long max)170 DepthToZ(Frustum<T> &f, T depth, long min, long max)
171 {
172 MATH_EXC_ON;
173 return f.DepthToZ(depth, min, max);
174 }
175
176 template <class T>
177 static T
worldRadius(Frustum<T> & f,const Vec3<T> & p,T radius)178 worldRadius(Frustum<T> &f, const Vec3<T> &p, T radius)
179 {
180 MATH_EXC_ON;
181 return f.worldRadius(p, radius);
182 }
183
184 template <class T>
185 static T
worldRadiusTuple(Frustum<T> & f,const tuple & t,T radius)186 worldRadiusTuple(Frustum<T> &f, const tuple &t, T radius)
187 {
188 MATH_EXC_ON;
189 if(t.attr("__len__")() == 3)
190 {
191 Vec3<T> point;
192 point.x = extract<T>(t[0]);
193 point.y = extract<T>(t[1]);
194 point.z = extract<T>(t[2]);
195 return f.worldRadius(point, radius);
196 }
197 else
198 throw std::invalid_argument ( "worldRadius expects tuple of length 3");
199 }
200
201 template <class T>
202 static T
screenRadius(Frustum<T> & f,const Vec3<T> & p,T radius)203 screenRadius(Frustum<T> &f, const Vec3<T> &p, T radius)
204 {
205 MATH_EXC_ON;
206 return f.screenRadius(p, radius);
207 }
208
209 template <class T>
210 static T
screenRadiusTuple(Frustum<T> & f,const tuple & t,T radius)211 screenRadiusTuple(Frustum<T> &f, const tuple &t, T radius)
212 {
213 MATH_EXC_ON;
214 if(t.attr("__len__")() == 3)
215 {
216 Vec3<T> point;
217 point.x = extract<T>(t[0]);
218 point.y = extract<T>(t[1]);
219 point.z = extract<T>(t[2]);
220 return f.screenRadius(point, radius);
221 }
222 else
223 throw std::invalid_argument ("screenRadius expects tuple of length 3");
224 }
225
226 template <class T>
227 static void
planes1(Frustum<T> & f,Plane3<T> * p)228 planes1(Frustum<T> &f, Plane3<T> *p)
229 {
230 MATH_EXC_ON;
231 f.planes(p);
232 }
233
234 template <class T>
235 static void
planes2(Frustum<T> & f,Plane3<T> * p,const Matrix44<T> & m)236 planes2(Frustum<T> &f, Plane3<T> *p, const Matrix44<T> &m)
237 {
238 MATH_EXC_ON;
239 f.planes(p, m);
240 }
241
242 template <class T>
243 static tuple
planes3(Frustum<T> & f,const Matrix44<T> & mat)244 planes3(Frustum<T> &f, const Matrix44<T> &mat)
245 {
246 MATH_EXC_ON;
247 IMATH_NAMESPACE::Plane3<T> p[6];
248 f.planes(p,mat);
249
250 tuple t = make_tuple(p[0],p[1],p[2],p[3],p[4],p[5]);
251
252 return t;
253 }
254
255 template <class T>
256 static tuple
planes4(Frustum<T> & f)257 planes4(Frustum<T> &f)
258 {
259 MATH_EXC_ON;
260 IMATH_NAMESPACE::Plane3<T> p[6];
261 f.planes(p);
262
263 tuple t = make_tuple(p[0],p[1],p[2],p[3],p[4],p[5]);
264
265 return t;
266 }
267
268 template <class T>
269 class_<Frustum<T> >
register_Frustum()270 register_Frustum()
271 {
272 void (IMATH_NAMESPACE::Frustum<T>::*set1)(T,T,T,T,T,T,bool) = &IMATH_NAMESPACE::Frustum<T>::set;
273 void (IMATH_NAMESPACE::Frustum<T>::*set2)(T,T,T,T,T) = &IMATH_NAMESPACE::Frustum<T>::set;
274 const char *name = FrustumName<T>::value;
275
276 class_< Frustum<T> > frustum_class(name,name,init<Frustum<T> >("copy construction"));
277 frustum_class
278 .def(init<>("Frustum() default construction"))
279 .def(init<T,T,T,T,T,T,bool>("Frustum(nearPlane,farPlane,left,right,top,bottom,ortho) construction"))
280 .def(init<T,T,T,T,T>("Frustum(nearPlane,farPlane,fovx,fovy,aspect) construction"))
281 .def(self == self) // NOSONAR - suppress SonarCloud bug report.
282 .def(self != self) // NOSONAR - suppress SonarCloud bug report.
283 .def("__repr__",&Frustum_repr<T>)
284 .def("set", set1,
285 "F.set(nearPlane, farPlane, left, right, top, bottom, "
286 "[ortho])\n"
287 "F.set(nearPlane, farPlane, fovx, fovy, aspect) "
288 " -- sets the entire state of "
289 "frustum F as specified. Only one of "
290 "fovx or fovy may be non-zero.")
291 .def("set", set2)
292
293 .def("modifyNearAndFar", &modifyNearAndFar<T>,
294 "F.modifyNearAndFar(nearPlane, farPlane) -- modifies "
295 "the already-valid frustum F as specified")
296
297 .def("setOrthographic", &Frustum<T>::setOrthographic,
298 "F.setOrthographic(b) -- modifies the "
299 "already-valid frustum F to be orthographic "
300 "or not")
301
302 .def("nearPlane", &Frustum<T>::nearPlane,
303 "F.nearPlane() -- returns the coordinate of the "
304 "near clipping plane of frustum F")
305
306 .def("farPlane", &Frustum<T>::farPlane,
307 "F.farPlane() -- returns the coordinate of the "
308 "far clipping plane of frustum F")
309
310 // The following two functions provide backwards compatibility
311 // with the previous API for this class.
312
313 .def("near", &Frustum<T>::nearPlane,
314 "F.near() -- returns the coordinate of the "
315 "near clipping plane of frustum F")
316
317 .def("far", &Frustum<T>::farPlane,
318 "F.far() -- returns the coordinate of the "
319 "far clipping plane of frustum F")
320
321 .def("left", &Frustum<T>::left,
322 "F.left() -- returns the left coordinate of "
323 "the near clipping window of frustum F")
324
325 .def("right", &Frustum<T>::right,
326 "F.right() -- returns the right coordinate of "
327 "the near clipping window of frustum F")
328
329 .def("top", &Frustum<T>::top,
330 "F.top() -- returns the top coordinate of "
331 "the near clipping window of frustum F")
332
333 .def("bottom", &Frustum<T>::bottom,
334 "F.bottom() -- returns the bottom coordinate "
335 "of the near clipping window of frustum F")
336
337 .def("orthographic", &Frustum<T>::orthographic,
338 "F.orthographic() -- returns whether frustum "
339 "F is orthographic or not")
340
341 .def("planes", planes1<T>,
342 "F.planes([M]) -- returns a sequence of 6 "
343 "Plane3s, the sides of the frustum F "
344 "(top, right, bottom, left, nearPlane, farPlane), "
345 "optionally transformed by the matrix M "
346 "if specified")
347 .def("planes", planes2<T>)
348 .def("planes", planes3<T>)
349 .def("planes", planes4<T>)
350
351 .def("fovx", &fovx<T>,
352 "F.fovx() -- derives and returns the "
353 "x field of view (in radians) for frustum F")
354
355 .def("fovy", &fovy<T>,
356 "F.fovy() -- derives and returns the "
357 "y field of view (in radians) for frustum F")
358
359 .def("aspect", &aspect<T>,
360 "F.aspect() -- derives and returns the "
361 "aspect ratio for frustum F")
362
363 .def("projectionMatrix", &projectionMatrix<T>,
364 "F.projectionMatrix() -- derives and returns "
365 "the projection matrix for frustum F")
366
367 .def("window", &window<T>,
368 "F.window(l,r,b,t) -- takes a rectangle in "
369 "the screen space (i.e., -1 <= l <= r <= 1, "
370 "-1 <= b <= t <= 1) of F and returns a new "
371 "Frustum whose near clipping-plane window "
372 "is that rectangle in local space")
373
374 .def("projectScreenToRay", &projectScreenToRay<T>,
375 "F.projectScreenToRay(V) -- returns a Line3 "
376 "through V, a V2 point in screen space")
377
378 .def("projectScreenToRay", &projectScreenToRayTuple<T>)
379
380 .def("projectPointToScreen", &projectPointToScreen<T>,
381 "F.projectPointToScreen(V) -- returns the "
382 "projection of V3 V into screen space")
383
384 .def("projectPointToScreen", &projectPointToScreenTuple<T>)
385
386 .def("projectPointToScreen", &projectPointToScreenObj<T>)
387
388 .def("ZToDepth", &ZToDepth<T>,
389 "F.ZToDepth(z, zMin, zMax) -- returns the "
390 "depth (Z in the local space of the "
391 "frustum F) corresponding to z (a result of "
392 "transformation by F's projection matrix) "
393 "after normalizing z to be between zMin "
394 "and zMax")
395
396 .def("normalizedZToDepth", &normalizedZToDepth<T>,
397 "F.normalizedZToDepth(z) -- returns the "
398 "depth (Z in the local space of the "
399 "frustum F) corresponding to z (a result of "
400 "transformation by F's projection matrix), "
401 "which is assumed to have been normalized "
402 "to [-1, 1]")
403
404 .def("DepthToZ", &DepthToZ<T>,
405 "F.DepthToZ(depth, zMin, zMax) -- converts "
406 "depth (Z in the local space of the frustum "
407 "F) to z (a result of transformation by F's "
408 "projection matrix) which is normalized to "
409 "[zMin, zMax]")
410
411 .def("worldRadius", &worldRadius<T>,
412 "F.worldRadius(V, r) -- returns the radius "
413 "in F's local space corresponding to the "
414 "point V and radius r in screen space")
415
416 .def("worldRadius", &worldRadiusTuple<T>)
417
418 .def("screenRadius", &screenRadius<T>,
419 "F.screenRadius(V, r) -- returns the radius "
420 "in screen space corresponding to "
421 "the point V and radius r in F's local "
422 "space")
423
424 .def("screenRadius", &screenRadiusTuple<T>)
425
426 ;
427
428 decoratecopy(frustum_class);
429
430 return frustum_class;
431 }
432
433 template <class T,class T2>
434 struct IsVisibleTask : public Task
435 {
436 const IMATH_NAMESPACE::FrustumTest<T>& frustumTest;
437 const PyImath::FixedArray<T2>& points;
438 PyImath::FixedArray<int>& results;
439
IsVisibleTaskPyImath::IsVisibleTask440 IsVisibleTask(const IMATH_NAMESPACE::FrustumTest<T>& ft, const PyImath::FixedArray<T2> &p, PyImath::FixedArray<int> &r)
441 : frustumTest(ft), points(p), results(r) {}
442
executePyImath::IsVisibleTask443 void execute(size_t start, size_t end)
444 {
445 for(size_t p = start; p < end; ++p)
446 results[p] = frustumTest.isVisible(IMATH_NAMESPACE::Vec3<T>(points[p]));
447 }
448 };
449
450 template <class T,class T2>
451 PyImath::FixedArray<int>
frustumTest_isVisible(IMATH_NAMESPACE::FrustumTest<T> & ft,const PyImath::FixedArray<T2> & points)452 frustumTest_isVisible(IMATH_NAMESPACE::FrustumTest<T>& ft, const PyImath::FixedArray<T2>& points)
453 {
454 size_t numPoints = points.len();
455 PyImath::FixedArray<int> mask(numPoints);
456
457 IsVisibleTask<T,T2> task(ft,points,mask);
458 dispatchTask(task,numPoints);
459 return mask;
460 }
461
462 template <class T>
463 class_<FrustumTest<T> >
register_FrustumTest()464 register_FrustumTest()
465 {
466 const char *name = FrustumTestName<T>::value;
467
468 bool (FrustumTest<T>::*isVisibleS)(const Sphere3<T> &) const = &FrustumTest<T>::isVisible;
469 bool (FrustumTest<T>::*isVisibleB)(const Box<Vec3<T> > &) const = &FrustumTest<T>::isVisible;
470 bool (FrustumTest<T>::*isVisibleV)(const Vec3<T> &) const = &FrustumTest<T>::isVisible;
471 bool (FrustumTest<T>::*completelyContainsS)(const Sphere3<T> &) const = &FrustumTest<T>::completelyContains;
472 bool (FrustumTest<T>::*completelyContainsB)(const Box<Vec3<T> > &) const = &FrustumTest<T>::completelyContains;
473
474 class_< FrustumTest<T> > frustumtest_class(name,name,init<const IMATH_NAMESPACE::Frustum<T>&,const IMATH_NAMESPACE::Matrix44<T>&>("create a frustum test object from a frustum and transform"));
475 frustumtest_class
476 .def("isVisible",isVisibleS)
477 .def("isVisible",isVisibleB)
478 .def("isVisible",isVisibleV)
479 .def("isVisible",&frustumTest_isVisible<T,IMATH_NAMESPACE::V3f>)
480 .def("completelyContains",completelyContainsS)
481 .def("completelyContains",completelyContainsB)
482 ;
483
484 decoratecopy(frustumtest_class);
485
486 return frustumtest_class;
487 }
488
489 template PYIMATH_EXPORT class_<Frustum<float> > register_Frustum<float>();
490 template PYIMATH_EXPORT class_<Frustum<double> > register_Frustum<double>();
491 template PYIMATH_EXPORT class_<FrustumTest<float> > register_FrustumTest<float>();
492 template PYIMATH_EXPORT class_<FrustumTest<double> > register_FrustumTest<double>();
493 }
494