Imported Upstream version 3.1.9
[platform/upstream/Imath.git] / src / python / PyImath / PyImathPlane.cpp
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 #define BOOST_BIND_GLOBAL_PLACEHOLDERS
10 #include <boost/python.hpp>
11 #include <boost/python/make_constructor.hpp>
12 #include <boost/format.hpp>
13 #include "PyImath.h"
14 #include "PyImathVec.h"
15 #include "PyImathMathExc.h"
16 #include "PyImathPlane.h"
17 #include "PyImathDecorators.h"
18 #include "PyImathExport.h"
19
20 namespace PyImath{
21 using namespace boost::python;
22 using namespace IMATH_NAMESPACE;
23
24 template <class T> struct PlaneName {static const char *value;};
25 template <> const char *PlaneName<float>::value = "Plane3f";
26 template <> const char *PlaneName<double>::value = "Plane3d";
27
28 template <class T>
29 static Plane3<T> *Plane3_construct_default()
30 {
31     Vec3<T> normal(T (1), T (0), T (0));
32     return new Plane3<T>(normal, T (0));
33 }
34
35 template <class T>
36 static Plane3<T> *Plane3_plane_construct(const object &planeObj)
37 {
38     MATH_EXC_ON;
39     extract < Plane3<float> > ef (planeObj);
40     extract < Plane3<double> > ed (planeObj);
41
42     Plane3<T> *p = 0;
43
44     if (ef.check())
45     {
46         Plane3<float> efp = ef();
47         p = new Plane3<T>;
48         p->normal = efp.normal;
49         p->distance = efp.distance;
50     }
51
52     else if (ed.check())
53     {
54         Plane3<double> edp = ed();
55         p = new Plane3<T>;
56         p->normal = edp.normal;
57         p->distance = edp.distance;
58     }
59
60     else
61     {
62       throw std::invalid_argument ("invalid parameter passed to Plane constructor");
63     }
64     
65     return p;
66 }
67
68 template <class T>
69 static Plane3<T> *Plane3_tuple_constructor1(const tuple &t, T distance)
70 {
71     MATH_EXC_ON;
72     if(t.attr("__len__")() == 3)
73     {
74         Vec3<T> normal;
75         normal.x = extract<T>(t[0]);
76         normal.y = extract<T>(t[1]);
77         normal.z = extract<T>(t[2]);
78         
79         return new Plane3<T>(normal, distance);
80     }
81     else
82         throw std::domain_error ("Plane3 expects tuple of length 3");
83 }
84
85 template <class T>
86 static Plane3<T> *Plane3_tuple_constructor2(const tuple &t0, const tuple &t1)
87 {
88     MATH_EXC_ON;
89     if(t0.attr("__len__")() == 3 && t1.attr("__len__")() == 3)
90     {
91         Vec3<T> point, normal;
92         point.x = extract<T>(t0[0]);
93         point.y = extract<T>(t0[1]);
94         point.z = extract<T>(t0[2]);
95         
96         normal.x = extract<T>(t1[0]);
97         normal.y = extract<T>(t1[1]);
98         normal.z = extract<T>(t1[2]);
99         
100         return new Plane3<T>(point, normal);
101     }
102     else
103         throw std::domain_error ("Plane3 expects tuples of length 3");
104 }
105
106 template <class T>
107 static Plane3<T> *Plane3_tuple_constructor3(const tuple &t0, const tuple &t1, const tuple &t2)
108 {
109     MATH_EXC_ON;
110     if(t0.attr("__len__")() == 3 && t1.attr("__len__")() == 3 && t2.attr("__len__")() == 3)
111     {
112         Vec3<T> point0, point1, point2;
113         point0.x = extract<T>(t0[0]);
114         point0.y = extract<T>(t0[1]);
115         point0.z = extract<T>(t0[2]);
116         
117         point1.x = extract<T>(t1[0]);
118         point1.y = extract<T>(t1[1]);
119         point1.z = extract<T>(t1[2]);
120
121         point2.x = extract<T>(t2[0]);
122         point2.y = extract<T>(t2[1]);
123         point2.z = extract<T>(t2[2]); 
124         
125         return new Plane3<T>(point0, point1, point2);
126     }
127     else
128         throw std::domain_error ("Plane3 expects tuple of length 3");
129 }
130
131 template <class T>
132 static Plane3<T>
133 mul (const Plane3<T> &plane, const Matrix44<T> &M)
134 {
135     MATH_EXC_ON;
136     return plane * M;
137 }
138
139 template <class T>
140 static void
141 set1 (Plane3<T> &plane, const Vec3<T> &v, T t)
142 {
143     MATH_EXC_ON;
144     plane.set (v, t);
145 }
146
147 template <class T>
148 static void
149 set2 (Plane3<T> &plane, const Vec3<T> &v1, const Vec3<T> &v2)
150 {
151     MATH_EXC_ON;
152     plane.set (v1, v2);
153 }
154
155 template <class T>
156 static void
157 set3 (Plane3<T> &plane, const Vec3<T> &v1, const Vec3<T> &v2, const Vec3<T> &v3)
158 {
159     MATH_EXC_ON;
160     plane.set (v1, v2, v3);
161 }
162
163 template <class T>
164 static std::string Plane3_str(const Plane3<T> &plane)
165 {
166     std::stringstream stream;
167
168     typename return_by_value::apply <Vec3<float> >::type converter;
169     handle<> normH (converter (plane.normal));
170     handle<> normRepr (PYUTIL_OBJECT_REPR (normH.get()));
171     std::string normalReprStr = extract<std::string> (normRepr.get());
172
173     stream << PlaneName<T>::value << "(" << normalReprStr << ", " 
174            << plane.distance << ")";
175     return stream.str();
176 }
177
178 // Non-specialized repr is same as str
179 template <class T>
180 static std::string Plane3_repr(const Plane3<T> &plane)
181 {
182     return Plane3_str(plane);
183 }
184
185 // Specialization for float to full precision
186 template <>
187 std::string Plane3_repr(const Plane3<float> &plane)
188 {
189     typename return_by_value::apply <Vec3<float> >::type converter;
190
191     handle<> normH (converter (plane.normal));
192     handle<> normRepr (PYUTIL_OBJECT_REPR (normH.get()));
193     std::string normalReprStr = extract<std::string> (normRepr.get());
194
195     return (boost::format("%s(%s, %.9g)")
196                         % PlaneName<float>::value
197                         % normalReprStr.c_str()
198                         % plane.distance).str();
199 }
200
201 // Specialization for double to full precision
202 template <>
203 std::string Plane3_repr(const Plane3<double> &plane)
204 {
205     typename return_by_value::apply <Vec3<double> >::type converter;
206
207     handle<> normH (converter (plane.normal));
208     handle<> normRepr (PYUTIL_OBJECT_REPR (normH.get()));
209     std::string normalReprStr = extract<std::string> (normRepr.get());
210
211     return (boost::format("%s(%s, %.17g)")
212                         % PlaneName<double>::value
213                         % normalReprStr.c_str()
214                         % plane.distance).str();
215 }
216
217
218 template <class T>
219 static T
220 distance(Plane3<T> &plane)
221 {
222     return plane.distance;
223 }
224
225 template <class T>
226 static Vec3<T>
227 normal(Plane3<T> &plane)
228 {
229     return plane.normal;
230 }
231
232 template <class T>
233 static void
234 setNormal(Plane3<T> &plane, const Vec3<T> &normal)
235 {
236     MATH_EXC_ON;
237     plane.normal = normal.normalized();
238 }
239
240 template <class T>
241 static void
242 setDistance(Plane3<T> &plane, const T &distance)
243 {
244     plane.distance = distance;
245 }
246
247 template <class T, class S>
248 static object intersectT(const Plane3<T> &plane, const Line3<S> &line)
249 {
250     MATH_EXC_ON;
251     T param;
252     Line3<T> l;
253     l.pos = line.pos;
254     l.dir = line.dir;
255
256     if(plane.intersectT(l, param))
257         return object(param);
258     
259     return object();
260 }
261
262 template <class T>
263 static bool
264 intersect2(const Plane3<T> &plane, const Line3<T> &line, Vec3<T> &intersection)
265 {
266     MATH_EXC_ON;
267     return plane.intersect(line, intersection);
268 }
269
270 template <class T, class S>
271 static object
272 intersect1(const Plane3<T> &plane, const Line3<S> &line)
273 {
274     MATH_EXC_ON;
275     Vec3<T> intersection;
276     Line3<T> l;
277     l.pos = line.pos;
278     l.dir = line.dir;
279     if(plane.intersect(l, intersection))
280         return object(intersection);
281     
282     return object();
283     
284 }
285
286 template <class T>
287 static void
288 setTuple1(Plane3<T> &plane, const tuple &t, T distance)
289 {
290     MATH_EXC_ON;
291     if(t.attr("__len__")() == 3)
292     {
293         Vec3<T> normal;
294         normal.x = extract<T>(t[0]);
295         normal.y = extract<T>(t[1]);
296         normal.z = extract<T>(t[2]);
297         
298         plane.set(normal, distance);
299     }
300     else
301         throw std::domain_error ("Plane3 expects tuple of length 3");    
302 }
303
304 template <class T>
305 static void
306 setTuple2(Plane3<T> &plane, const tuple &t0, const tuple &t1)
307 {
308     MATH_EXC_ON;
309     if(t0.attr("__len__")() == 3 && t1.attr("__len__")() == 3)
310     {
311         Vec3<T> point, normal;
312         point.x = extract<T>(t0[0]);
313         point.y = extract<T>(t0[1]);
314         point.z = extract<T>(t0[2]);
315         
316         normal.x = extract<T>(t1[0]);
317         normal.y = extract<T>(t1[1]);
318         normal.z = extract<T>(t1[2]);
319         
320         plane.set(point, normal);
321     }
322     else
323         throw std::domain_error ("Plane3 expects tuples of length 3");
324 }
325
326 template <class T>
327 static void
328 setTuple3(Plane3<T> &plane, const tuple &t0, const tuple &t1, const tuple &t2)
329 {
330     MATH_EXC_ON;
331     if(t0.attr("__len__")() == 3 && t1.attr("__len__")() == 3 && t2.attr("__len__")() == 3)
332     {
333         Vec3<T> point0, point1, point2;
334         point0.x = extract<T>(t0[0]);
335         point0.y = extract<T>(t0[1]);
336         point0.z = extract<T>(t0[2]);
337         
338         point1.x = extract<T>(t1[0]);
339         point1.y = extract<T>(t1[1]);
340         point1.z = extract<T>(t1[2]);
341
342         point2.x = extract<T>(t2[0]);
343         point2.y = extract<T>(t2[1]);
344         point2.z = extract<T>(t2[2]); 
345         
346         plane.set(point0, point1, point2);
347     }
348     else
349         throw std::domain_error ("Plane3 expects tuple of length 3");
350 }
351
352 template <class T>
353 static Vec3<T>
354 reflectPoint(Plane3<T> &plane, const Vec3<T> &p)
355 {
356     MATH_EXC_ON;
357     return plane.reflectPoint(p);
358 }
359
360 template <class T>
361 static Vec3<T>
362 reflectPointTuple(Plane3<T> &plane, const tuple &t)
363 {
364     MATH_EXC_ON;
365     Vec3<T> point;
366     if(t.attr("__len__")() == 3)
367     {
368         point.x = extract<T>(t[0]);
369         point.y = extract<T>(t[1]);
370         point.z = extract<T>(t[2]); 
371         
372         return plane.reflectPoint(point);
373     }
374     else
375         throw std::domain_error ("Plane3 expects tuple of length 3");
376 }
377
378 template <class T>
379 static T
380 distanceTo(Plane3<T> &plane, const Vec3<T> &v)
381 {
382     MATH_EXC_ON;
383     return plane.distanceTo(v);
384 }
385
386 template <class T>
387 static T
388 distanceToTuple(Plane3<T> &plane, const tuple &t)
389 {
390     MATH_EXC_ON;
391     Vec3<T> point;
392     if(t.attr("__len__")() == 3)
393     {
394         point.x = extract<T>(t[0]);
395         point.y = extract<T>(t[1]);
396         point.z = extract<T>(t[2]); 
397         
398         return plane.distanceTo(point);
399     }
400     else
401         throw std::domain_error ("Plane3 expects tuple of length 3");    
402 }
403
404 template <class T>
405 static Vec3<T>
406 reflectVector(Plane3<T> &plane, const Vec3<T> &v)
407 {
408     MATH_EXC_ON;
409     return plane.reflectVector(v);
410 }
411
412 template <class T>
413 static Vec3<T>
414 reflectVectorTuple(Plane3<T> &plane, const tuple &t)
415 {
416     MATH_EXC_ON;
417     Vec3<T> point;
418     if(t.attr("__len__")() == 3)
419     {
420         point.x = extract<T>(t[0]);
421         point.y = extract<T>(t[1]);
422         point.z = extract<T>(t[2]); 
423         
424         return plane.reflectVector(point);
425     }
426     else
427         throw std::domain_error ("Plane3 expects tuple of length 3");
428 }
429
430 template <class T>
431 static bool
432 equal(const Plane3<T> &p1, const Plane3<T> &p2)
433 {
434     if(p1.normal == p2.normal && p1.distance == p2.distance)
435         return true;
436     else
437         return false;
438 }
439
440 template <class T>
441 static bool
442 notequal(const Plane3<T> &p1, const Plane3<T> &p2)
443 {
444     if(p1.normal != p2.normal || p1.distance != p2.distance)
445         return true;
446     else
447         return false;
448 }
449
450 template <class T>
451 static Plane3<T>
452 negate(const Plane3<T> &plane)
453 {
454     MATH_EXC_ON;
455     Plane3<T> p;
456     p.set(-plane.normal, -plane.distance);
457     
458     return p;
459 }
460
461
462
463 template <class T>
464 class_<Plane3<T> >
465 register_Plane()
466 {
467     const char *name = PlaneName<T>::value;
468     
469     class_< Plane3<T> > plane_class(name);
470     plane_class
471         .def("__init__",make_constructor(Plane3_construct_default<T>),"initialize normal to  (1,0,0), distance to 0")
472         .def("__init__",make_constructor(Plane3_tuple_constructor1<T>))
473         .def("__init__",make_constructor(Plane3_tuple_constructor2<T>))
474         .def("__init__",make_constructor(Plane3_tuple_constructor3<T>))
475         .def("__init__",make_constructor(Plane3_plane_construct<T>))
476         .def(init<const Vec3<T> &, T>("Plane3(normal, distance) construction"))
477         .def(init<const Vec3<T> &, const Vec3<T> &>("Plane3(point, normal) construction"))
478         .def(init<const Vec3<T> &, const Vec3<T> &, const Vec3<T> &>("Plane3(point1, point2, point3) construction"))
479         .def("__eq__", &equal<T>)
480         .def("__ne__", &notequal<T>)
481         .def("__mul__", &mul<T>)
482         .def("__neg__", &negate<T>)
483         .def("__str__", &Plane3_str<T>)
484         .def("__repr__", &Plane3_repr<T>)
485         
486         .def_readwrite("normal", &Plane3<T>::normal)
487         .def_readwrite("distance", &Plane3<T>::distance)
488         
489         .def("normal", &normal<T>, "normal()",
490              "pl.normal() -- returns the normal of plane pl")
491              
492         .def("distance", &distance<T>, "distance()",
493                  "pl.distance() -- returns the signed distance\n"
494                          "of plane pl from the coordinate origin")
495         
496         .def("setNormal", &setNormal<T>, "setNormal()",
497                  "pl.setNormal(n) -- sets the normal of plane\n"
498                          "pl to n.normalized()")
499              
500         .def("setDistance", &setDistance<T>, "setDistance()",
501                  "pl.setDistance(d) -- sets the signed distance\n"
502                          "of plane pl from the coordinate origin to d")
503              
504         .def("set", &set1<T>, "set()",
505                  "pl.set(n,d) -- sets the normal and the signed\n"
506                          "   distance of plane pl to n and d\n"
507                          "\n"
508                          "pl.set(p,n) -- sets the normal of plane pl to\n"
509                          "   n.normalized() and adjusts the distance of\n"
510                          "   pl from the coordinate origin so that pl\n"
511                          "   passes through point p\n"
512                          "\n"
513                          "pl.set(p1,p2,p3) -- sets the normal of plane pl\n"
514                          "   to (p2-p1)%(p3-p1)).normalized(), and adjusts\n"
515                          "   the distance of pl from the coordinate origin\n"
516                          "   so that pl passes through points p1, p2 and p3")
517              
518         .def("set", &set2<T>, "set()")
519         .def("set", &set3<T>, "set()")
520         
521         .def("set", &setTuple1<T>, "set()")
522         .def("set", &setTuple2<T>, "set()")
523         .def("set", &setTuple3<T>, "set()")        
524         
525         .def("intersect", &intersect2<T>,
526                  "pl.intersect(ln, pt) -- returns true if the line intersects\n"
527              "the plane, false if it doesn't.  The point where plane\n"
528                          "pl and line ln intersect is stored in pt")
529              
530         .def("intersect", &intersect1<T,float>,
531                  "pl.intersect(ln) -- returns the point where plane\n"
532                          "pl and line ln intersect, or None if pl and ln do\n"
533                          "not intersect")
534         .def("intersect", &intersect1<T,double>,
535                  "pl.intersect(ln) -- returns the point where plane\n"
536                          "pl and line ln intersect, or None if pl and ln do\n"
537                          "not intersect")
538              
539         .def("intersectT", &intersectT<T, float>,
540              "pl.intersectT(ln) -- computes the intersection,\n"
541                          "i, of plane pl and line ln, and returns t, so that\n"
542                          "ln.pos() + t * ln.dir() == i.\n"
543                          "If pl and ln do not intersect, pl.intersectT(ln)\n"
544                          "returns None.\n") 
545              
546         .def("intersectT", &intersectT<T,double>)
547              
548         .def("distanceTo", &distanceTo<T>, "distanceTo()",
549                  "pl.distanceTo(p) -- returns the signed distance\n"
550                          "between plane pl and point p (positive if p is\n"
551                          "on the side of pl where the pl's normal points)\n")
552         
553         .def("distanceTo", &distanceToTuple<T>)
554              
555         .def("reflectPoint", &reflectPoint<T>, "reflectPoint()",
556                  "pl.reflectPoint(p) -- returns the image,\n"
557                          "q, of point p after reflection on plane pl:\n"
558                          "the distance between p and q is twice the\n"
559                          "distance between p and pl, and the line from\n"
560                          "p to q is parallel to pl's normal.")
561              
562         .def("reflectPoint", &reflectPointTuple<T>)
563              
564         .def("reflectVector", &reflectVector<T>, "reflectVector()",
565                  "pl.reflectVector(v) -- returns the direction\n"
566                          "of a ray with direction v after reflection on\n"
567                          "plane pl")
568         .def("reflectVector", &reflectVectorTuple<T>)
569         
570         ;
571
572     decoratecopy(plane_class);
573
574     return plane_class;
575 }
576
577 template PYIMATH_EXPORT class_<Plane3<float> > register_Plane<float>();
578 template PYIMATH_EXPORT class_<Plane3<double> > register_Plane<double>();
579
580 } //namespace PyIMath