/////////////////////////////////////////////////////////////////////////// // // Copyright (c) 1998-2011, Industrial Light & Magic, a division of Lucas // Digital Ltd. LLC // // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Industrial Light & Magic nor the names of // its contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // /////////////////////////////////////////////////////////////////////////// #include #include #include "PyImathDecorators.h" #include #include #include #include #include #include #include #include #include #include // XXX incomplete array wrapping, docstrings missing namespace PyImath { template <> const char *PyImath::QuatfArray::name() { return "QuatfArray"; } template <> const char *PyImath::QuatdArray::name() { return "QuatdArray"; } } namespace PyImath { using namespace boost::python; using namespace IMATH_NAMESPACE; template struct QuatName { static const char *value; }; template<> const char *QuatName::value = "Quatf"; template<> const char *QuatName::value = "Quatd"; template static std::string Quat_str(const Quat &v) { std::stringstream stream; stream << QuatName::value << "(" << v[0] << ", " << v[1] << ", " << v[2] << ", " << v[3] << ")"; return stream.str(); } // Non-specialized repr is same as str template static std::string Quat_repr(const Quat &v) { return Quat_str(v); } // Specialization for float to full precision template <> std::string Quat_repr(const Quat &v) { return (boost::format("%s(%.9g, %.9g, %.9g, %.9g)") % QuatName::value % v[0] % v[1] % v[2] % v[3]).str(); } // Specialization for double to full precision template <> std::string Quat_repr(const Quat &v) { return (boost::format("%s(%.17g, %.17g, %.17g, %.17g)") % QuatName::value % v[0] % v[1] % v[2] % v[3]).str(); } template static Quat & invert(Quat &quat) { MATH_EXC_ON; return quat.invert(); } template static Quat inverse(Quat &quat) { MATH_EXC_ON; return quat.inverse(); } template static Quat & normalize(Quat &quat) { MATH_EXC_ON; return quat.normalize(); } template static Quat normalized(Quat &quat) { MATH_EXC_ON; return quat.normalized(); } template static T length (Quat &quat) { MATH_EXC_ON; return quat.length(); } template static Quat & setAxisAngle(Quat &quat, const Vec3 &axis, T radians) { MATH_EXC_ON; return quat.setAxisAngle(axis, radians); } template static Quat & setRotation(Quat &quat, const Vec3 &from, const Vec3 &to) { MATH_EXC_ON; return quat.setRotation(from, to); } template static T angle (Quat &quat) { MATH_EXC_ON; return quat.angle(); } template static Vec3 axis (Quat &quat) { MATH_EXC_ON; return quat.axis(); } template static Matrix33 toMatrix33 (Quat &quat) { MATH_EXC_ON; return quat.toMatrix33(); } template static Matrix44 toMatrix44 (Quat &quat) { MATH_EXC_ON; return quat.toMatrix44(); } template static Quat log(Quat &quat) { MATH_EXC_ON; return quat.log(); } template static Quat exp(Quat &quat) { MATH_EXC_ON; return quat.exp(); } template static void setR(Quat &quat, const double &r) { quat.r = r; } template static void setV(Quat &quat, const Vec3 &v) { quat.v = v; } template static void extract(Quat &quat, const Matrix44 &mat) { MATH_EXC_ON; Quat q = IMATH_NAMESPACE::extractQuat(mat); quat.r = q.r; quat.v = q.v; } template static T scalar(Quat &quat) { return quat.r; } template static Vec3 vector(Quat &quat) { return quat.v; } template static Quat slerp(const Quat &quat, const Quat &other, T t) { MATH_EXC_ON; return IMATH_NAMESPACE::slerp (quat, other, t); } template static const Quat & imul (Quat &quat, const Quat &other) { MATH_EXC_ON; return quat *= other; } template static const Quat & imulT (Quat &quat, T t) { MATH_EXC_ON; return quat *= t; } template static const Quat & idiv (Quat &quat, const Quat &other) { MATH_EXC_ON; return quat /= other; } template static const Quat & idivT (Quat &quat, T t) { MATH_EXC_ON; return quat /= t; } template static const Quat & iadd (Quat &quat, const Quat &other) { MATH_EXC_ON; return quat += other; } template static const Quat & isub (Quat &quat, const Quat &other) { MATH_EXC_ON; return quat -= other; } template static Matrix33 rmulM33(Quat &quat, Matrix33 &m) { MATH_EXC_ON; return m * quat; } template static Matrix33 mulM33(Quat &quat, Matrix33 &m) { MATH_EXC_ON; return quat * m; } template static Quat mul(Quat &quat, Quat &other) { MATH_EXC_ON; return quat * other; } template static Quat div(Quat &quat, Quat &other) { MATH_EXC_ON; return quat / other; } template static Quat divT(Quat &quat, T t) { MATH_EXC_ON; return quat / t; } template static Quat mulT(Quat &quat, T t) { MATH_EXC_ON; return quat * t; } template static Quat add(Quat &quat, Quat &other) { MATH_EXC_ON; return quat + other; } template static Quat sub(Quat &quat, Quat &other) { MATH_EXC_ON; return quat - other; } template static Quat neg(Quat &quat) { MATH_EXC_ON; return -quat; } template static Quat conj(Quat &quat) { MATH_EXC_ON; return ~quat; } template static T dot(Quat &quat, Quat &other) { MATH_EXC_ON; return quat ^ other; } template static Vec3 rmulVec3(Quat &quat, const Vec3 &v) { MATH_EXC_ON; return v * quat.toMatrix44(); } template static FixedArray< Vec3 > rmulVec3Array(Quat &quat, const FixedArray< Vec3 > &a) { MATH_EXC_ON; Matrix44 m = quat.toMatrix44(); size_t len = a.len(); FixedArray< Vec3 > r(len); for (size_t i = 0; i < len; i++) r[i] = a[i] * m; return r; } template static Quat * quatConstructor1(const Euler &euler) { MATH_EXC_ON; return new Quat(euler.toQuat()); } template static Quat * quatConstructor2(const Matrix33 &mat) { MATH_EXC_ON; return new Quat(Euler(mat).toQuat()); } template static Quat * quatConstructor3(const Matrix44 &mat) { MATH_EXC_ON; return new Quat(Euler(mat).toQuat()); } template class_ > register_Quat() { class_ > quat_class(QuatName::value, QuatName::value,init >("copy construction")); quat_class .def(init<>("imath Quat initialization") ) .def(init >("imath Quat copy initialization") ) .def(init >("imath Quat copy initialization") ) .def(init("make Quat from components") ) .def(init >("make Quat from components") ) .def("__init__", make_constructor(quatConstructor1)) .def("__init__", make_constructor(quatConstructor2)) .def("__init__", make_constructor(quatConstructor3)) .def("identity",&Quat::identity) .def("invert",&invert,return_internal_reference<>(), "q.invert() -- inverts quaternion q\n" "(modifying q); returns q") .def("inverse",&inverse, "q.inverse() -- returns the inverse of\n" "quaternion q; q is not modified\n") .def("normalize",&normalize,return_internal_reference<>(), "q.normalize() -- normalizes quaternion q\n" "(modifying q); returns q") .def("normalized",&normalized, "q.normalized() -- returns a normalized version\n" "of quaternion q; q is not modified\n") .def("length",&length) .def("setAxisAngle",&setAxisAngle,return_internal_reference<>(), "q.setAxisAngle(x,r) -- sets the value of\n" "quaternion q so that q represents a rotation\n" "of r radians around axis x") .def("setRotation",&setRotation,return_internal_reference<>(), "q.setRotation(v,w) -- sets the value of\n" "quaternion q so that rotating vector v by\n" "q produces vector w") .def("angle",&angle, "q.angle() -- returns the rotation angle\n" "(in radians) represented by quaternion q") .def("axis",&axis, "q.axis() -- returns the rotation axis\n" "represented by quaternion q") .def("toMatrix33",&toMatrix33, "q.toMatrix33() -- returns a 3x3 matrix that\n" "represents the same rotation as quaternion q") .def("toMatrix44",&toMatrix44, "q.toMatrix44() -- returns a 4x4 matrix that\n" "represents the same rotation as quaternion q") .def("log",&log) .def("exp",&exp) .def_readwrite("v",&Quat::v) .def_readwrite("r",&Quat::r) .def("v", &vector, "q.v() -- returns the v (vector) component\n" "of quaternion q") .def("r", &scalar, "q.r() -- returns the r (scalar) component\n" "of quaternion q") .def("setR", &setR, "q.setR(s) -- sets the r (scalar) component\n" "of quaternion q to s") .def("setV", &setV, "q.setV(w) -- sets the v (vector) component\n" "of quaternion q to w") .def("extract", &extract, "q.extract(m) -- extracts the rotation component\n" "from 4x4 matrix m and stores the result in q") .def("slerp", &slerp, "q.slerp(p,t) -- performs sperical linear\n" "interpolation between quaternions q and p:\n" "q.slerp(p,0) returns q; q.slerp(p,1) returns p.\n" "q and p must be normalized\n") .def("__str__",Quat_str) .def("__repr__",Quat_repr) .def ("__imul__", &imul, return_internal_reference<>()) .def ("__imul__", &imulT, return_internal_reference<>()) .def ("__idiv__", idiv, return_internal_reference<>()) .def ("__idiv__", &idivT, return_internal_reference<>()) .def ("__itruediv__", idiv, return_internal_reference<>()) .def ("__itruediv__", &idivT, return_internal_reference<>()) .def ("__iadd__", &iadd, return_internal_reference<>()) .def ("__isub__", &isub, return_internal_reference<>()) .def(self == self) .def(self != self) .def ("__rmul__", &rmulM33) .def ("__mul__", &mulM33) .def ("__mul__", &mul) .def ("__div__", &div) .def ("__div__", &divT) .def ("__truediv__", &div) .def ("__truediv__", &divT) .def ("__mul__", &mulT) .def ("__rmul__", &mulT) .def ("__add__", &add) .def ("__sub__", &sub) .def ("__neg__", &neg) .def ("__invert__", &conj) .def ("__xor__", &dot) .def ("__rmul__", &rmulVec3) .def ("__rmul__", &rmulVec3Array) ; decoratecopy(quat_class); return quat_class; } // XXX fixme - template this // really this should get generated automatically... template static FixedArray QuatArray_get(FixedArray > &qa) { return FixedArray( &(qa[0].r)+index, qa.len(), 4*qa.stride(), qa.handle()); } template struct QuatArray_SetRotationTask : public Task { const FixedArray > &from; const FixedArray > &to; FixedArray > &result; QuatArray_SetRotationTask (const FixedArray > &fromIn, const FixedArray > &toIn, FixedArray > &resultIn) : from (fromIn), to (toIn), result (resultIn) {} void execute (size_t start, size_t end) { for (size_t i = start; i < end; ++i) result[i].setRotation (from[i], to[i]); } }; template static void QuatArray_setRotation (FixedArray > &va, const FixedArray > &from, const FixedArray > &to) { MATH_EXC_ON; size_t len = va.match_dimension(from); va.match_dimension(to); QuatArray_SetRotationTask task (from, to, va); dispatchTask (task, len); } template struct QuatArray_OrientToVectors : public Task { const FixedArray > &forward; const FixedArray > &up; FixedArray > &result; bool alignForward; QuatArray_OrientToVectors (const FixedArray > &forwardIn, const FixedArray > &upIn, FixedArray > &resultIn, bool alignForwardIn) : forward (forwardIn), up (upIn), result (resultIn), alignForward (alignForwardIn) {} void execute (size_t start, size_t end) { Vec3 f(0), u(0); Euler eu(0,0,0); const Vec3 fRef(1,0,0); for (size_t i = start; i < end; ++i) { if (alignForward) { f = forward[i].normalized(); u = up[i] - f.dot(up[i])*f; u.normalize(); } else { u = up[i].normalized(); f = forward[i] - u.dot(forward[i])*u; f.normalize(); } extractEulerXYZ (rotationMatrixWithUpDir (fRef, f, u), eu); result[i] = eu.toQuat(); } } }; template static void QuatArray_orientToVectors (FixedArray > &va, const FixedArray > &forward, const FixedArray > &up, bool alignForward) { MATH_EXC_ON; size_t len = va.match_dimension(forward); va.match_dimension(up); QuatArray_OrientToVectors task (forward, up, va, alignForward); dispatchTask (task, len); } template struct QuatArray_Axis : public Task { const FixedArray > &va; FixedArray > &result; QuatArray_Axis (const FixedArray > &vaIn, FixedArray > &resultIn) : va (vaIn), result (resultIn) {} void execute (size_t start, size_t end) { for (size_t i = start; i < end; ++i) result[i] = va[i].axis(); } }; template static FixedArray > QuatArray_axis(const FixedArray > &va) { MATH_EXC_ON; size_t len = va.len(); FixedArray > retval (Py_ssize_t(len), UNINITIALIZED); QuatArray_Axis task (va, retval); dispatchTask (task, len); return retval; } template struct QuatArray_Angle : public Task { const FixedArray > &va; FixedArray &result; QuatArray_Angle (const FixedArray > &vaIn, FixedArray &resultIn) : va (vaIn), result (resultIn) {} void execute (size_t start, size_t end) { for (size_t i = start; i < end; ++i) result[i] = va[i].angle(); } }; template static FixedArray QuatArray_angle(const FixedArray > &va) { MATH_EXC_ON; size_t len = va.len(); FixedArray retval (Py_ssize_t(len), UNINITIALIZED); QuatArray_Angle task (va, retval); dispatchTask (task, len); return retval; } template struct QuatArray_RmulVec3 : public Task { const FixedArray > &a; const Vec3 &v; FixedArray > &r; QuatArray_RmulVec3 (const FixedArray > &aIn, const Vec3 &vIn, FixedArray > &rIn) : a (aIn), v (vIn), r (rIn) {} void execute(size_t start, size_t end) { for (size_t i = start; i < end; ++i) { Matrix44 m = a[i].toMatrix44(); r[i] = v * m; } } }; template static FixedArray< Vec3 > QuatArray_rmulVec3 (const FixedArray< IMATH_NAMESPACE::Quat > &a, const Vec3 &v) { MATH_EXC_ON; size_t len = a.len(); FixedArray< Vec3 > r (Py_ssize_t(len), UNINITIALIZED); QuatArray_RmulVec3 task (a, v, r); dispatchTask (task, len); return r; } template struct QuatArray_RmulVec3Array : public Task { const FixedArray > &a; const FixedArray > &b; FixedArray > &r; QuatArray_RmulVec3Array (const FixedArray > &aIn, const FixedArray > &bIn, FixedArray > &rIn) : a (aIn), b (bIn), r (rIn) {} void execute(size_t start, size_t end) { for (size_t i = start; i < end; ++i) { Matrix44 m = a[i].toMatrix44(); r[i] = b[i] * m; } } }; template static FixedArray< Vec3 > QuatArray_rmulVec3Array (const FixedArray< IMATH_NAMESPACE::Quat > &a, const FixedArray< Vec3 > &b) { MATH_EXC_ON; size_t len = a.match_dimension(b); FixedArray< Vec3 > r (Py_ssize_t(len), UNINITIALIZED); QuatArray_RmulVec3Array task (a, b, r); dispatchTask (task, len); return r; } template struct QuatArray_SetAxisAngle : public Task { const FixedArray > &axis; const FixedArray &angles; FixedArray > &quats; QuatArray_SetAxisAngle (const FixedArray > &axisIn, const FixedArray &anglesIn, FixedArray > &quatsIn) : axis (axisIn), angles (anglesIn), quats (quatsIn) {} void execute(size_t start, size_t end) { for (size_t i = start; i < end; ++i) { quats[i].setAxisAngle (axis[i], angles[i]); } } }; template static void QuatArray_setAxisAngle (FixedArray< IMATH_NAMESPACE::Quat > &quats, const FixedArray< IMATH_NAMESPACE::Vec3 > &axis, const FixedArray &angles) { MATH_EXC_ON; size_t len = quats.match_dimension(axis); quats.match_dimension(angles); QuatArray_SetAxisAngle task (axis, angles, quats); dispatchTask (task, len); } template struct QuatArray_SetEulerXYZ : public Task { const FixedArray > &rot; FixedArray > &quats; QuatArray_SetEulerXYZ (const FixedArray > &rotIn, FixedArray > &quatsIn) : rot (rotIn), quats (quatsIn) {} void execute (size_t start, size_t end) { for (size_t i = start; i < end; ++i) { Eulerf e(rot[i]); quats[i] = e.toQuat(); } } }; template static void QuatArray_setEulerXYZ (FixedArray< IMATH_NAMESPACE::Quat > &quats, const FixedArray< IMATH_NAMESPACE::Vec3 > &rot) { MATH_EXC_ON; size_t len = quats.match_dimension(rot); QuatArray_SetEulerXYZ task (rot, quats); dispatchTask (task, len); } template struct QuatArray_Mul : public Task { const FixedArray > &q1; const FixedArray > &q2; FixedArray > &result; QuatArray_Mul (const FixedArray > &q1In, const FixedArray > &q2In, FixedArray > &resultIn) : q1 (q1In), q2 (q2In), result (resultIn) {} void execute (size_t start, size_t end) { for (size_t i = start; i < end; ++i) { result[i] = q1[i] * q2[i]; } } }; template static FixedArray< IMATH_NAMESPACE::Quat > QuatArray_mul(const FixedArray< IMATH_NAMESPACE::Quat > &q1, const FixedArray< IMATH_NAMESPACE::Quat > &q2) { MATH_EXC_ON; size_t len = q1.match_dimension(q2); FixedArray< IMATH_NAMESPACE::Quat > result (Py_ssize_t(len), UNINITIALIZED); QuatArray_Mul task (q1, q2, result); dispatchTask (task, len); return result; } template struct QuatArray_QuatConstructor1 : public Task { const FixedArray > &euler; FixedArray > &result; QuatArray_QuatConstructor1 (const FixedArray > &eulerIn, FixedArray > &resultIn) : euler (eulerIn), result (resultIn) {} void execute (size_t start, size_t end) { for (size_t i = start; i < end; ++i) { result[i] = euler[i].toQuat(); } } }; template static FixedArray > * QuatArray_quatConstructor1(const FixedArray > &e) { MATH_EXC_ON; size_t len = e.len(); FixedArray >* result = new FixedArray > (Py_ssize_t(len), UNINITIALIZED); QuatArray_QuatConstructor1 task (e, *result); dispatchTask (task, len); return result; } template class_ > > register_QuatArray() { class_ > > quatArray_class = FixedArray >::register_("Fixed length array of IMATH_NAMESPACE::Quat"); quatArray_class .add_property("r",&QuatArray_get) .add_property("x",&QuatArray_get) .add_property("y",&QuatArray_get) .add_property("z",&QuatArray_get) .def("setRotation", &QuatArray_setRotation, "set rotation angles for each quat", (args("from", "to"))) .def("orientToVectors", &QuatArray_orientToVectors, "Sets the orientations to match the given forward and up vectors, " "matching the forward vector exactly if 'alignForward' is True, matching " "the up vector exactly if 'alignForward' is False. If the vectors are " "already orthogonal, both vectors will be matched exactly.", (args("forward", "up", "alignForward"))) .def("axis", &QuatArray_axis, "get rotation axis for each quat") .def("angle", &QuatArray_angle, "get rotation angle about the axis returned by axis() for each quat") .def("setAxisAngle", &QuatArray_setAxisAngle, "set the quaternion arrays from a given axis and angle", (args("axis", "angle"))) .def("setEulerXYZ", &QuatArray_setEulerXYZ, "set the quaternion arrays from a given euler XYZ angle vector", (args("euler"))) .def("__mul__", &QuatArray_mul) .def("__rmul__", &QuatArray_rmulVec3) .def("__rmul__", &QuatArray_rmulVec3Array) .def("__init__", make_constructor(QuatArray_quatConstructor1)) ; add_comparison_functions(quatArray_class); decoratecopy(quatArray_class); return quatArray_class; } template PYIMATH_EXPORT class_ > register_Quat(); template PYIMATH_EXPORT class_ > register_Quat(); template PYIMATH_EXPORT class_ > > register_QuatArray(); template PYIMATH_EXPORT class_ > > register_QuatArray(); template<> PYIMATH_EXPORT IMATH_NAMESPACE::Quat FixedArrayDefaultValue >::value() { return IMATH_NAMESPACE::Quat(); } template<> PYIMATH_EXPORT IMATH_NAMESPACE::Quat FixedArrayDefaultValue >::value() { return IMATH_NAMESPACE::Quat(); } }