diff --git a/python/modules/py_igl_viewer.cpp b/python/modules/py_igl_viewer.cpp index a6cd41a3a..0644be340 100644 --- a/python/modules/py_igl_viewer.cpp +++ b/python/modules/py_igl_viewer.cpp @@ -188,9 +188,15 @@ py::class_ viewercore_class(me, "ViewerCore"); }) .def_readwrite("lighting_factor",&igl::viewer::ViewerCore::lighting_factor) - .def_readwrite("model_zoom",&igl::viewer::ViewerCore::model_zoom) + .def_property("trackball_angle", + [](const igl::viewer::ViewerCore& core) {return Eigen::Quaterniond(core.trackball_angle.cast());}, + [](igl::viewer::ViewerCore& core, const Eigen::Quaterniond& q) + { + core.trackball_angle = Eigen::Quaternionf(q.cast()); + }) + .def_property("model_translation", [](const igl::viewer::ViewerCore& core) {return Eigen::MatrixXd(core.model_translation.cast());}, [](igl::viewer::ViewerCore& core, const Eigen::MatrixXd& v) @@ -316,13 +322,13 @@ py::class_ viewercore_class(me, "ViewerCore"); // UI Enumerations py::class_ viewer_class(me, "Viewer"); - #ifdef IGL_VIEWER_WITH_NANOGUI - py::object fh = (py::object) py::module::import("nanogui").attr("FormHelper"); - py::class_ form_helper_class(me, "FormHelper", fh); +// #ifdef IGL_VIEWER_WITH_NANOGUI +// py::object fh = (py::object) py::module::import("nanogui").attr("FormHelper"); +// py::class_ form_helper_class(me, "FormHelper", fh); - py::object screen = (py::object) py::module::import("nanogui").attr("Screen"); - py::class_ screen_class(me, "Screen", screen); - #endif +// py::object screen = (py::object) py::module::import("nanogui").attr("Screen"); +// py::class_ screen_class(me, "Screen", screen); +// #endif py::enum_(viewer_class, "MouseButton") .value("Left", igl::viewer::Viewer::MouseButton::Left) diff --git a/python/modules/py_typedefs.cpp b/python/modules/py_typedefs.cpp new file mode 100644 index 000000000..d2132c5cc --- /dev/null +++ b/python/modules/py_typedefs.cpp @@ -0,0 +1,12 @@ +py::class_(m, "RotationList") + .def(py::init<>()) + .def("pop_back", &RotationList::pop_back) + /* There are multiple versions of push_back(), etc. Select the right ones. */ + .def("append", (void (RotationList::*)(const Eigen::Quaterniond &)) &RotationList::push_back) + .def("back", (Eigen::Quaterniond &(RotationList::*)()) &RotationList::back) + .def("__len__", [](const RotationList &v) { return v.size(); }) + .def("__getitem__", [](const RotationList &v, int b) { return v.at(b); }) + .def("__setitem__", [](RotationList &v, int b, Eigen::Quaterniond &c) { return v.at(b) = c; }) + .def("__iter__", [](RotationList &v) { + return py::make_iterator(v.begin(), v.end()); +}, py::keep_alive<0, 1>()); diff --git a/python/modules/py_typedefs.h b/python/modules/py_typedefs.h new file mode 100644 index 000000000..2e92f3767 --- /dev/null +++ b/python/modules/py_typedefs.h @@ -0,0 +1,5 @@ +typedef std::vector > RotationList; +PYBIND11_MAKE_OPAQUE(RotationList); + +//typedef std::vector TranslationList; +//PYBIND11_MAKE_OPAQUE(TranslationList); diff --git a/python/modules/py_vector.cpp b/python/modules/py_vector.cpp index 8be4e5c86..82e6aeb1b 100644 --- a/python/modules/py_vector.cpp +++ b/python/modules/py_vector.cpp @@ -68,7 +68,7 @@ py::class_ bind_eigen_2(py::module &m, const char *name, }) .def("__init__", [](Type &m, py::buffer b) { py::buffer_info info = b.request(); - if (info.format != py::format_descriptor::value()) + if (info.format != py::format_descriptor::value) throw std::runtime_error("Incompatible buffer format!"); if (info.ndim == 1) { new (&m) Type(info.shape[0], 1); @@ -319,7 +319,7 @@ py::class_ bind_eigen_2(py::module &m, const char *name, m.data(), /* Pointer to buffer */ sizeof(Scalar), /* Size of one scalar */ /* Python struct-style format descriptor */ - py::format_descriptor::value(), + py::format_descriptor::value, 2, /* Number of dimensions */ { (size_t) m.rows(), /* Buffer dimensions */ (size_t) m.cols() }, @@ -735,6 +735,9 @@ void python_export_vector(py::module &m) { .def("conjugate",[](Eigen::Quaterniond& q) { return q.conjugate(); }) + .def("normalize",[](Eigen::Quaterniond& q) { + return q.normalize(); + }) .def("slerp",[](Eigen::Quaterniond& q, double & t, Eigen::Quaterniond other) { return q.slerp(t, other); }) diff --git a/python/py_igl.cpp b/python/py_igl.cpp index d4e15c7e5..459d69808 100644 --- a/python/py_igl.cpp +++ b/python/py_igl.cpp @@ -1,6 +1,7 @@ #include #include "python_shared.h" +#include "modules/py_typedefs.h" #include #include @@ -85,6 +86,8 @@ void python_export_igl(py::module &m) { +#include "modules/py_typedefs.cpp" + #include "py_igl/py_AABB.cpp" #include "py_igl/py_ARAPEnergyType.cpp" #include "py_igl/py_MeshBooleanType.cpp" diff --git a/python/py_igl/py_directed_edge_orientations.cpp b/python/py_igl/py_directed_edge_orientations.cpp index df76b1b1c..9a87ef75d 100644 --- a/python/py_igl/py_directed_edge_orientations.cpp +++ b/python/py_igl/py_directed_edge_orientations.cpp @@ -3,15 +3,10 @@ m.def("directed_edge_orientations", [] ( const Eigen::MatrixXd& C, const Eigen::MatrixXi& E, - py::list Q + RotationList& Q ) { - std::vector > Ql; - igl::directed_edge_orientations(C, E, Ql); - for (auto item : Ql) { - py::object obj = py::cast(item); - Q.append(obj); - } + return igl::directed_edge_orientations(C, E, Q); }, __doc_igl_directed_edge_orientations, py::arg("C"), py::arg("E"), py::arg("Q")); diff --git a/python/py_igl/py_dqs.cpp b/python/py_igl/py_dqs.cpp index 1163e0d9d..cf6696202 100644 --- a/python/py_igl/py_dqs.cpp +++ b/python/py_igl/py_dqs.cpp @@ -4,7 +4,7 @@ m.def("dqs", [] ( const Eigen::MatrixXd& V, const Eigen::MatrixXd& W, - const std::vector > & vQ, + const RotationList& vQ, const std::vector & vT, Eigen::MatrixXd& U ) diff --git a/python/py_igl/py_forward_kinematics.cpp b/python/py_igl/py_forward_kinematics.cpp index cbdc9ee0c..d42f15df5 100644 --- a/python/py_igl/py_forward_kinematics.cpp +++ b/python/py_igl/py_forward_kinematics.cpp @@ -19,18 +19,13 @@ m.def("forward_kinematics", [] const Eigen::MatrixXd& C, const Eigen::MatrixXi& BE, const Eigen::MatrixXi& P, - const std::vector > dQ, - py::list vQ, + const RotationList& dQ, + RotationList& vQ, py::list vT ) { - std::vector > vQl; std::vector vTl; - igl::forward_kinematics(C, BE, P, dQ, vQl, vTl); - for (auto item : vQl) { - py::object obj = py::cast(item); - vQ.append(obj); - } + igl::forward_kinematics(C, BE, P, dQ, vQ, vTl); for (auto item : vTl) { py::object obj = py::cast(Eigen::MatrixXd(item)); vT.append(obj); diff --git a/python/scripts/py_igl.mako b/python/scripts/py_igl.mako index c6a8f66db..0d5d309ec 100644 --- a/python/scripts/py_igl.mako +++ b/python/scripts/py_igl.mako @@ -1,6 +1,7 @@ #include #include "python_shared.h" +#include "modules/py_typedefs.h" % for f in functions: #include @@ -9,6 +10,8 @@ void python_export_igl(py::module &m) { +#include "modules/py_typedefs.cpp" + % for f in functions: #include "py_igl/py_${f}.cpp" % endfor diff --git a/python/tutorial/404_DualQuaternionSkinning.py b/python/tutorial/404_DualQuaternionSkinning.py index 994c9ce83..26029ad2d 100755 --- a/python/tutorial/404_DualQuaternionSkinning.py +++ b/python/tutorial/404_DualQuaternionSkinning.py @@ -14,7 +14,7 @@ check_dependencies(dependencies) def pre_draw(viewer): - global recompute, anim_t, poses, C, BE, P, U + global recompute, anim_t, poses, C, BE, P, U, M, anim_t_dir if recompute: # Find pose interval @@ -23,12 +23,12 @@ def pre_draw(viewer): t = anim_t - math.floor(anim_t) # Interpolate pose and identity - anim_pose = [] + anim_pose = igl.RotationList() for e in range(len(poses[begin])): anim_pose.append(poses[begin][e].slerp(t, poses[end][e])) # Propogate relative rotations via FK to retrieve absolute transformations - vQ = [] + vQ = igl.RotationList() vT = [] igl.forward_kinematics(C, BE, P, anim_pose, vQ, vT) dim = C.cols() @@ -62,14 +62,23 @@ def pre_draw(viewer): def key_down(viewer, key, mods): - global recompute, use_dqs + global recompute, use_dqs, animation recompute = True if key == ord('D') or key == ord('d'): use_dqs = not use_dqs - return True + viewer.core.is_animating = False + animation = False + if use_dqs: + print("Switched to Dual Quaternion Skinning") + else: + print("Switched to Linear Blend Skinning") elif key == ord(' '): - viewer.core.is_animating = not viewer.core.is_animating - return True + if animation: + viewer.core.is_animating = False + animation = False + else: + viewer.core.is_animating = True + animation = True return False @@ -93,6 +102,7 @@ if __name__ == "__main__": anim_t_dir = 0.015 use_dqs = False recompute = True + animation = False # Flag needed as there is some synchronization problem with viewer.core.is_animating poses = [[]] @@ -102,7 +112,7 @@ if __name__ == "__main__": # retrieve parents for forward kinematics igl.directed_edge_parents(BE, P) - rest_pose = [] + rest_pose = igl.RotationList() igl.directed_edge_orientations(C, BE, rest_pose) poses = [[igl.eigen.Quaterniond.Identity() for i in range(4)] for j in range(4)] @@ -121,7 +131,7 @@ if __name__ == "__main__": viewer.core.show_lines = False viewer.core.show_overlay_depth = False viewer.core.line_width = 1 - # viewer.core.trackball_angle.normalize() + viewer.core.trackball_angle.normalize() viewer.callback_pre_draw = pre_draw viewer.callback_key_down = key_down viewer.core.is_animating = False