Browse Source

switched to MatrixXd for all wrappers, updated pybind11

Former-commit-id: 332266c0900080866cedfccc7fef38772f5dd1e8
Daniele Panozzo 9 years ago
parent
commit
ea90d493ec

+ 24 - 0
python/104_Colors.py

@@ -0,0 +1,24 @@
+import igl
+
+V = igl.eigen.MatrixXd()
+F = igl.eigen.MatrixXi()
+C = igl.eigen.MatrixXd()
+
+# Load a mesh in OFF format
+igl.readOFF("../tutorial/shared/screwdriver.off", V, F)
+
+# Plot the mesh
+viewer = igl.viewer.Viewer()
+viewer.data.set_mesh(V, F)
+
+# Use the z coordinate as a scalar field over the surface
+Z = V.col(2);
+
+# Compute per-vertex colors
+igl.jet(Z,True,C)
+
+# Add per-vertex colors
+viewer.data.set_colors(C)
+
+# Launch the viewer
+viewer.launch()

+ 1 - 1
python/202_GaussianCurvature.py

@@ -6,7 +6,7 @@ F = igl.eigen.MatrixXi()
 igl.readOFF("../tutorial/shared/bumpy.off",V,F);
 
 # Compute Gaussian curvature
-K = igl.eigen.VectorXd();
+K = igl.eigen.MatrixXd();
 igl.gaussian_curvature(V,F,K);
 
 print("igl::gaussian_curvature: \n", K, sep='')

+ 1 - 1
python/py_igl/py_gaussian_curvature.cpp

@@ -2,7 +2,7 @@ m.def("gaussian_curvature", []
 (
   const Eigen::MatrixXd& V,
   const Eigen::MatrixXi& F,
-  Eigen::VectorXd& K
+  Eigen::MatrixXd& K
 )
 {
   return igl::gaussian_curvature(V,F,K);

+ 2 - 1
python/py_igl/py_jet.cpp

@@ -1,10 +1,11 @@
 m.def("jet", []
 (
-  const Eigen::VectorXd& Z,
+  const Eigen::MatrixXd& Z,
   const bool normalize,
   Eigen::MatrixXd& C
 )
 {
+  assert_is_VectorXd("Z",Z);
   return igl::jet(Z,normalize,C);
 }, __doc_igl_jet,
 py::arg("Z"), py::arg("normalize"), py::arg("C"));

+ 4 - 2
python/py_igl/py_parula.cpp

@@ -1,22 +1,24 @@
 m.def("parula", []
 (
-  const Eigen::VectorXd& Z,
+  const Eigen::MatrixXd& Z,
   const bool normalize,
   Eigen::MatrixXd& C
 )
 {
+  assert_is_VectorXd("Z",Z);
   return igl::parula(Z,normalize,C);
 }, __doc_igl_parula,
 py::arg("Z"), py::arg("normalize"), py::arg("C"));
 
 m.def("parula", []
 (
-  const Eigen::VectorXd& Z,
+  const Eigen::MatrixXd& Z,
   const double min_Z,
   const double max_Z,
   Eigen::MatrixXd& C
 )
 {
+  assert_is_VectorXd("Z",Z);
   return igl::parula(Z,min_Z,max_Z,C);
 }, __doc_igl_parula,
 py::arg("Z"), py::arg("min_Z"), py::arg("max_Z"), py::arg("C"));

+ 2 - 1
python/py_igl/py_per_face_normals.cpp

@@ -2,10 +2,11 @@ m.def("per_face_normals", []
 (
   const Eigen::MatrixXd& V,
   const Eigen::MatrixXi& F,
-  const Eigen::VectorXd& Z,
+  const Eigen::MatrixXd& Z,
   Eigen::MatrixXd& N
 )
 {
+  assert_is_VectorXd("Z",Z);
   return igl::per_face_normals(V,F,Z,N);
 }, __doc_igl_per_face_normals,
 py::arg("V"), py::arg("F"), py::arg("Z"), py::arg("N"));

+ 2 - 2
python/py_igl/py_principal_curvature.cpp

@@ -4,8 +4,8 @@ m.def("principal_curvature", []
   const Eigen::MatrixXi& F,
   Eigen::MatrixXd& PD1,
   Eigen::MatrixXd& PD2,
-  Eigen::VectorXd& PV1,
-  Eigen::VectorXd& PV2,
+  Eigen::MatrixXd& PV1,
+  Eigen::MatrixXd& PV2,
   unsigned radius,
   bool useKring
 )

+ 97 - 1
python/py_igl_viewer.cpp

@@ -11,23 +11,119 @@ void python_export_igl_viewer(py::module &m)
   py::module me = m.def_submodule(
     "viewer", "Mesh viewer");
 
+/////////////////////// DATA
+
     py::class_<igl::viewer::ViewerData> viewerdata_class(me, "ViewerData");
     viewerdata_class
     .def(py::init<>())
     .def("set_mesh", &igl::viewer::ViewerData::set_mesh)
+    .def("set_colors", &igl::viewer::ViewerData::set_colors)
     .def("clear", &igl::viewer::ViewerData::clear)
     ;
 
+
+//////////////////////// CORE
+
     py::class_<igl::viewer::ViewerCore> viewercore_class(me, "ViewerCore");
     viewercore_class
     .def(py::init<>())
     //.def("align_camera_center", [](igl::viewer::ViewerCore& core, const Eigen::MatrixXd& V, const Eigen::MatrixXi& F){return core.align_camera_center(V,F);})
+    .def("init", &igl::viewer::ViewerCore::init)
+    .def("shut", &igl::viewer::ViewerCore::shut)
+    //.def("InitSerialization", &igl::viewer::ViewerCore::InitSerialization)
     .def("align_camera_center",
        (void (igl::viewer::ViewerCore::*) (const Eigen::MatrixXd &, const Eigen::MatrixXi &)) &igl::viewer::ViewerCore::align_camera_center
     )
-    .def("init", &igl::viewer::ViewerCore::init)
+
+    .def("align_camera_center",
+       (void (igl::viewer::ViewerCore::*) (const Eigen::MatrixXd &)) &igl::viewer::ViewerCore::align_camera_center
+    )
+
+    .def("clear_framebuffers",&igl::viewer::ViewerCore::clear_framebuffers)
+    .def("draw",&igl::viewer::ViewerCore::draw)
+    .def("draw_buffer",&igl::viewer::ViewerCore::draw_buffer)
+
+    .def_readwrite("textrenderer",&igl::viewer::ViewerCore::textrenderer)
+    .def_readwrite("shininess",&igl::viewer::ViewerCore::shininess)
+
+    .def_property("background_color",
+    [](const igl::viewer::ViewerCore& core) {return Eigen::MatrixXd(core.background_color);},
+    [](igl::viewer::ViewerCore& core, const Eigen::MatrixXd& v)
+    {
+      assert_is_Vector3d("background_color",v);
+      core.background_color = Vector3f(v.cast<float>());
+    })
+
+    // // Colors
+    // Eigen::Vector3f background_color;
+    // Eigen::Vector3f line_color;
+    //
+    // // Lighting
+    // Eigen::Vector3f light_position;
+    // float lighting_factor;
+    //
+    // // Trackball angle (quaternion)
+    // enum RotationType
+    // {
+    //   ROTATION_TYPE_TRACKBALL = 0,
+    //   ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP = 1,
+    //   NUM_ROTATION_TYPES = 2
+    // } rotation_type;
+    // Eigen::Quaternionf trackball_angle;
+    //
+    // // Model viewing parameters
+    // float model_zoom;
+    // Eigen::Vector3f model_translation;
+    //
+    // // Model viewing paramters (uv coordinates)
+    // float model_zoom_uv;
+    // Eigen::Vector3f model_translation_uv;
+    //
+    // // Camera parameters
+    // float camera_zoom;
+    // bool orthographic;
+    // Eigen::Vector3f camera_eye;
+    // Eigen::Vector3f camera_up;
+    // Eigen::Vector3f camera_center;
+    // float camera_view_angle;
+    // float camera_dnear;
+    // float camera_dfar;
+    //
+    // // Visualization options
+    // bool show_overlay;
+    // bool show_overlay_depth;
+    // bool show_texture;
+    // bool show_faces;
+    // bool show_lines;
+    // bool show_vertid;
+    // bool show_faceid;
+    // bool invert_normals;
+    // bool depth_test;
+    //
+    // // Point size / line width
+    // float point_size;
+    // float line_width;
+    //
+    // // Animation
+    // bool is_animating;
+    // double animation_max_fps;
+    //
+    // // Caches the two-norm between the min/max point of the bounding box
+    // float object_scale;
+    //
+    // // Viewport size
+    // Eigen::Vector4f viewport;
+    //
+    // // Save the OpenGL transformation matrices used for the previous rendering pass
+    // Eigen::Matrix4f view;
+    // Eigen::Matrix4f model;
+    // Eigen::Matrix4f proj;
+
+    ///
     ;
 
+///////////////////////// VIEWER
+
     py::class_<igl::viewer::Viewer>(me, "Viewer")
     .def(py::init<>())
     .def_readwrite("data", &igl::viewer::Viewer::data)

+ 254 - 241
python/py_vector.cpp

@@ -3,223 +3,223 @@
 
 #include "python.h"
 
-template <typename Type> void init_fixed_from_buffer_3(Type &v, py::buffer &b) {
-    typedef typename Type::Scalar Scalar;
-
-    py::buffer_info info = b.request();
-    if (info.format != py::format_descriptor<Scalar>::value())
-        throw std::runtime_error("Incompatible buffer format!");
-    if (!((info.ndim == 1 && info.strides[0] == sizeof(Scalar)) ||
-          (info.ndim == 2 &&
-              ((info.shape[0] == 1 && info.strides[0] == sizeof(Scalar) &&
-                info.shape[1] == 3) ||
-               (info.shape[1] == 1 && info.strides[1] == sizeof(Scalar) &&
-                info.shape[0] == 3)))))
-        throw std::runtime_error("Incompatible buffer dimension!");
-
-    memcpy(v.data(), info.ptr, sizeof(Scalar) * 3);
-}
-
-/// Creates Python bindings for an Eigen order-1 tensor of size 3 (i.e. a vector/normal/point)
-template <typename Type>
-py::class_<Type> bind_eigen_1_3(py::module &m, const char *name,
-                                py::object parent = py::object()) {
-    typedef typename Type::Scalar Scalar;
-
-    py::class_<Type> vector(m, name, parent);
-    vector
-        /* Constructors */
-        .def(py::init<>())
-        .def(py::init<Scalar>())
-        .def(py::init<Scalar, Scalar, Scalar>())
-        .def("__init__", [](Type &v, const std::vector<Scalar> &v2) {
-            if (v2.size() != 3)
-                throw std::runtime_error("Incompatible size!");
-            memcpy(v.data(), &v2[0], sizeof(Scalar) * 3);
-        })
-        .def("__init__", [](Type &v, py::buffer b) {
-            init_fixed_from_buffer_3(v, b);
-        })
-
-        /* Initialization */
-        .def("setConstant", [](Type &m, Scalar value) { m.setConstant(value); })
-        .def("setZero", [](Type &m) { m.setZero(); })
-
-        /* Arithmetic operators (def_cast forcefully casts the result back to a
-           Matrix to avoid type issues with Eigen's crazy expression templates) */
-        .def_cast(-py::self)
-        .def_cast(py::self + py::self)
-        .def_cast(py::self - py::self)
-        .def_cast(py::self * Scalar())
-        .def_cast(py::self / Scalar())
-        .def_cast(py::self += py::self)
-        .def_cast(py::self -= py::self)
-        .def_cast(py::self *= Scalar())
-        .def_cast(py::self /= Scalar())
-
-        /* Comparison operators */
-        .def(py::self == py::self)
-        .def(py::self != py::self)
-
-        /* Python protocol implementations */
-        .def("__len__", [](const Type &) { return (int) 3; })
-        .def("__repr__", [](const Type &v) {
-            std::ostringstream oss;
-            oss << v;
-            return oss.str();
-        })
-        .def("__getitem__", [](const Type &c, int i) {
-            if (i < 0 || i >= 3)
-                throw py::index_error();
-            return c[i];
-         })
-        .def("__setitem__", [](Type &c, int i, Scalar v) {
-             if (i < 0 || i >= 3)
-                 throw py::index_error();
-            c[i] = v;
-         })
-
-        /* Buffer access for interacting with NumPy */
-        .def_buffer([](Type &m) -> py::buffer_info {
-            return py::buffer_info(
-                m.data(),        /* Pointer to buffer */
-                sizeof(Scalar),  /* Size of one scalar */
-                /* Python struct-style format descriptor */
-                py::format_descriptor<Scalar>::value(),
-                1, { (size_t) 3 },
-                { sizeof(Scalar) }
-            );
-        });
-    return vector;
-}
-
-/// Creates Python bindings for a dynamic Eigen order-1 tensor (i.e. a vector)
-template <typename Type>
-py::class_<Type> bind_eigen_1(py::module &m, const char *name,
-                              py::object parent = py::object()) {
-    typedef typename Type::Scalar Scalar;
-
-    /* Many Eigen functions are templated and can't easily be referenced using
-       a function pointer, thus a big portion of the binding code below
-       instantiates Eigen code using small anonymous wrapper functions */
-    py::class_<Type> vector(m, name, parent);
-
-    vector
-        /* Constructors */
-        .def(py::init<>())
-        .def(py::init<size_t>())
-        .def("__init__", [](Type &v, const std::vector<Scalar> &v2) {
-            new (&v) Type(v2.size());
-            memcpy(v.data(), &v2[0], sizeof(Scalar) * v2.size());
-        })
-        .def("__init__", [](Type &v, py::buffer b) {
-            py::buffer_info info = b.request();
-            if (info.format != py::format_descriptor<Scalar>::value()) {
-                throw std::runtime_error("Incompatible buffer format!");
-            } else if (info.ndim == 1 && info.strides[0] == sizeof(Scalar)) {
-                new (&v) Type(info.shape[0]);
-                memcpy(v.data(), info.ptr, sizeof(Scalar) * info.shape[0]);
-            } else if (info.ndim == 2 && ((info.shape[0] == 1 && info.strides[0] == sizeof(Scalar))
-                                       || (info.shape[1] == 1 && info.strides[1] == sizeof(Scalar)))) {
-                new (&v) Type(info.shape[0] * info.shape[1]);
-                memcpy(v.data(), info.ptr, sizeof(Scalar) * info.shape[0] * info.shape[1]);
-            } else {
-                throw std::runtime_error("Incompatible buffer dimension!");
-            }
-        })
-
-        /* Size query functions */
-        .def("size", [](const Type &m) { return m.size(); })
-        .def("cols", [](const Type &m) { return m.cols(); })
-        .def("rows", [](const Type &m) { return m.rows(); })
-
-        /* Initialization */
-        .def("setZero", [](Type &m) { m.setZero(); })
-        .def("setConstant", [](Type &m, Scalar value) { m.setConstant(value); })
-
-        /* Resizing */
-        .def("resize", [](Type &m, size_t s0) { m.resize(s0); })
-        .def("resizeLike", [](Type &m, const Type &m2) { m.resizeLike(m2); })
-        .def("conservativeResize", [](Type &m, size_t s0) { m.conservativeResize(s0); })
-
-        /* Component-wise operations */
-        .def("cwiseAbs", &Type::cwiseAbs)
-        .def("cwiseAbs2", &Type::cwiseAbs2)
-        .def("cwiseSqrt", &Type::cwiseSqrt)
-        .def("cwiseInverse", &Type::cwiseInverse)
-        .def("cwiseMin", [](const Type &m1, const Type &m2) -> Type { return m1.cwiseMin(m2); })
-        .def("cwiseMax", [](const Type &m1, const Type &m2) -> Type { return m1.cwiseMax(m2); })
-        .def("cwiseMin", [](const Type &m1, Scalar s) -> Type { return m1.cwiseMin(s); })
-        .def("cwiseMax", [](const Type &m1, Scalar s) -> Type { return m1.cwiseMax(s); })
-        .def("cwiseProduct", [](const Type &m1, const Type &m2) -> Type { return m1.cwiseProduct(m2); })
-        .def("cwiseQuotient", [](const Type &m1, const Type &m2) -> Type { return m1.cwiseQuotient(m2); })
-
-        /* Arithmetic operators (def_cast forcefully casts the result back to a
-           Type to avoid type issues with Eigen's crazy expression templates) */
-        .def_cast(-py::self)
-        .def_cast(py::self + py::self)
-        .def_cast(py::self - py::self)
-        .def_cast(py::self * Scalar())
-        .def_cast(py::self / Scalar())
-
-        .def("__rmul__", [](const Type& a, const Scalar& b)
-        {
-          return Type(b * a);
-        })
-
-
-        /* Arithmetic in-place operators */
-        .def_cast(py::self += py::self)
-        .def_cast(py::self -= py::self)
-        .def_cast(py::self *= py::self)
-        .def_cast(py::self *= Scalar())
-        .def_cast(py::self /= Scalar())
-
-        /* Comparison operators */
-        .def(py::self == py::self)
-        .def(py::self != py::self)
-
-        /* Python protocol implementations */
-        .def("__repr__", [](const Type &v) {
-            std::ostringstream oss;
-            oss << v.transpose();
-            return oss.str();
-        })
-        .def("__getitem__", [](const Type &m, size_t i) {
-            if (i >= (size_t) m.size())
-                throw py::index_error();
-            return m[i];
-         })
-        .def("__setitem__", [](Type &m, size_t i, Scalar v) {
-            if (i >= (size_t) m.size())
-                throw py::index_error();
-            m[i] = v;
-         })
-
-        /* Buffer access for interacting with NumPy */
-        .def_buffer([](Type &m) -> py::buffer_info {
-            return py::buffer_info(
-                m.data(),                /* Pointer to buffer */
-                sizeof(Scalar),          /* Size of one scalar */
-                /* Python struct-style format descriptor */
-                py::format_descriptor<Scalar>::value(),
-                1,                       /* Number of dimensions */
-                { (size_t) m.size() },   /* Buffer dimensions */
-                { sizeof(Scalar) }       /* Strides (in bytes) for each index */
-            );
-         })
-
-        /* Static initializers */
-        .def_static("Zero", [](size_t n) { return Type(Type::Zero(n)); })
-        .def_static("Ones", [](size_t n) { return Type(Type::Ones(n)); })
-        .def_static("Constant", [](size_t n, Scalar value) { return Type(Type::Constant(n, value)); })
-        .def("MapMatrix", [](const Type& m, size_t r, size_t c)
-        {
-          return Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic>(Eigen::Map<const Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic>>(m.data(),r,c));
-        })
-        ;
-    return vector;
-}
+// template <typename Type> void init_fixed_from_buffer_3(Type &v, py::buffer &b) {
+//     typedef typename Type::Scalar Scalar;
+//
+//     py::buffer_info info = b.request();
+//     if (info.format != py::format_descriptor<Scalar>::value())
+//         throw std::runtime_error("Incompatible buffer format!");
+//     if (!((info.ndim == 1 && info.strides[0] == sizeof(Scalar)) ||
+//           (info.ndim == 2 &&
+//               ((info.shape[0] == 1 && info.strides[0] == sizeof(Scalar) &&
+//                 info.shape[1] == 3) ||
+//                (info.shape[1] == 1 && info.strides[1] == sizeof(Scalar) &&
+//                 info.shape[0] == 3)))))
+//         throw std::runtime_error("Incompatible buffer dimension!");
+//
+//     memcpy(v.data(), info.ptr, sizeof(Scalar) * 3);
+// }
+//
+// /// Creates Python bindings for an Eigen order-1 tensor of size 3 (i.e. a vector/normal/point)
+// template <typename Type>
+// py::class_<Type> bind_eigen_1_3(py::module &m, const char *name,
+//                                 py::object parent = py::object()) {
+//     typedef typename Type::Scalar Scalar;
+//
+//     py::class_<Type> vector(m, name, parent);
+//     vector
+//         /* Constructors */
+//         .def(py::init<>())
+//         .def(py::init<Scalar>())
+//         .def(py::init<Scalar, Scalar, Scalar>())
+//         .def("__init__", [](Type &v, const std::vector<Scalar> &v2) {
+//             if (v2.size() != 3)
+//                 throw std::runtime_error("Incompatible size!");
+//             memcpy(v.data(), &v2[0], sizeof(Scalar) * 3);
+//         })
+//         .def("__init__", [](Type &v, py::buffer b) {
+//             init_fixed_from_buffer_3(v, b);
+//         })
+//
+//         /* Initialization */
+//         .def("setConstant", [](Type &m, Scalar value) { m.setConstant(value); })
+//         .def("setZero", [](Type &m) { m.setZero(); })
+//
+//         /* Arithmetic operators (def_cast forcefully casts the result back to a
+//            Matrix to avoid type issues with Eigen's crazy expression templates) */
+//         .def_cast(-py::self)
+//         .def_cast(py::self + py::self)
+//         .def_cast(py::self - py::self)
+//         .def_cast(py::self * Scalar())
+//         .def_cast(py::self / Scalar())
+//         .def_cast(py::self += py::self)
+//         .def_cast(py::self -= py::self)
+//         .def_cast(py::self *= Scalar())
+//         .def_cast(py::self /= Scalar())
+//
+//         /* Comparison operators */
+//         .def(py::self == py::self)
+//         .def(py::self != py::self)
+//
+//         /* Python protocol implementations */
+//         .def("__len__", [](const Type &) { return (int) 3; })
+//         .def("__repr__", [](const Type &v) {
+//             std::ostringstream oss;
+//             oss << v;
+//             return oss.str();
+//         })
+//         .def("__getitem__", [](const Type &c, int i) {
+//             if (i < 0 || i >= 3)
+//                 throw py::index_error();
+//             return c[i];
+//          })
+//         .def("__setitem__", [](Type &c, int i, Scalar v) {
+//              if (i < 0 || i >= 3)
+//                  throw py::index_error();
+//             c[i] = v;
+//          })
+//
+//         /* Buffer access for interacting with NumPy */
+//         .def_buffer([](Type &m) -> py::buffer_info {
+//             return py::buffer_info(
+//                 m.data(),        /* Pointer to buffer */
+//                 sizeof(Scalar),  /* Size of one scalar */
+//                 /* Python struct-style format descriptor */
+//                 py::format_descriptor<Scalar>::value(),
+//                 1, { (size_t) 3 },
+//                 { sizeof(Scalar) }
+//             );
+//         });
+//     return vector;
+// }
+//
+// /// Creates Python bindings for a dynamic Eigen order-1 tensor (i.e. a vector)
+// template <typename Type>
+// py::class_<Type> bind_eigen_1(py::module &m, const char *name,
+//                               py::object parent = py::object()) {
+//     typedef typename Type::Scalar Scalar;
+//
+//     /* Many Eigen functions are templated and can't easily be referenced using
+//        a function pointer, thus a big portion of the binding code below
+//        instantiates Eigen code using small anonymous wrapper functions */
+//     py::class_<Type> vector(m, name, parent);
+//
+//     vector
+//         /* Constructors */
+//         .def(py::init<>())
+//         .def(py::init<size_t>())
+//         .def("__init__", [](Type &v, const std::vector<Scalar> &v2) {
+//             new (&v) Type(v2.size());
+//             memcpy(v.data(), &v2[0], sizeof(Scalar) * v2.size());
+//         })
+//         .def("__init__", [](Type &v, py::buffer b) {
+//             py::buffer_info info = b.request();
+//             if (info.format != py::format_descriptor<Scalar>::value()) {
+//                 throw std::runtime_error("Incompatible buffer format!");
+//             } else if (info.ndim == 1 && info.strides[0] == sizeof(Scalar)) {
+//                 new (&v) Type(info.shape[0]);
+//                 memcpy(v.data(), info.ptr, sizeof(Scalar) * info.shape[0]);
+//             } else if (info.ndim == 2 && ((info.shape[0] == 1 && info.strides[0] == sizeof(Scalar))
+//                                        || (info.shape[1] == 1 && info.strides[1] == sizeof(Scalar)))) {
+//                 new (&v) Type(info.shape[0] * info.shape[1]);
+//                 memcpy(v.data(), info.ptr, sizeof(Scalar) * info.shape[0] * info.shape[1]);
+//             } else {
+//                 throw std::runtime_error("Incompatible buffer dimension!");
+//             }
+//         })
+//
+//         /* Size query functions */
+//         .def("size", [](const Type &m) { return m.size(); })
+//         .def("cols", [](const Type &m) { return m.cols(); })
+//         .def("rows", [](const Type &m) { return m.rows(); })
+//
+//         /* Initialization */
+//         .def("setZero", [](Type &m) { m.setZero(); })
+//         .def("setConstant", [](Type &m, Scalar value) { m.setConstant(value); })
+//
+//         /* Resizing */
+//         .def("resize", [](Type &m, size_t s0) { m.resize(s0); })
+//         .def("resizeLike", [](Type &m, const Type &m2) { m.resizeLike(m2); })
+//         .def("conservativeResize", [](Type &m, size_t s0) { m.conservativeResize(s0); })
+//
+//         /* Component-wise operations */
+//         .def("cwiseAbs", &Type::cwiseAbs)
+//         .def("cwiseAbs2", &Type::cwiseAbs2)
+//         .def("cwiseSqrt", &Type::cwiseSqrt)
+//         .def("cwiseInverse", &Type::cwiseInverse)
+//         .def("cwiseMin", [](const Type &m1, const Type &m2) -> Type { return m1.cwiseMin(m2); })
+//         .def("cwiseMax", [](const Type &m1, const Type &m2) -> Type { return m1.cwiseMax(m2); })
+//         .def("cwiseMin", [](const Type &m1, Scalar s) -> Type { return m1.cwiseMin(s); })
+//         .def("cwiseMax", [](const Type &m1, Scalar s) -> Type { return m1.cwiseMax(s); })
+//         .def("cwiseProduct", [](const Type &m1, const Type &m2) -> Type { return m1.cwiseProduct(m2); })
+//         .def("cwiseQuotient", [](const Type &m1, const Type &m2) -> Type { return m1.cwiseQuotient(m2); })
+//
+//         /* Arithmetic operators (def_cast forcefully casts the result back to a
+//            Type to avoid type issues with Eigen's crazy expression templates) */
+//         .def_cast(-py::self)
+//         .def_cast(py::self + py::self)
+//         .def_cast(py::self - py::self)
+//         .def_cast(py::self * Scalar())
+//         .def_cast(py::self / Scalar())
+//
+//         .def("__rmul__", [](const Type& a, const Scalar& b)
+//         {
+//           return Type(b * a);
+//         })
+//
+//
+//         /* Arithmetic in-place operators */
+//         .def_cast(py::self += py::self)
+//         .def_cast(py::self -= py::self)
+//         .def_cast(py::self *= py::self)
+//         .def_cast(py::self *= Scalar())
+//         .def_cast(py::self /= Scalar())
+//
+//         /* Comparison operators */
+//         .def(py::self == py::self)
+//         .def(py::self != py::self)
+//
+//         /* Python protocol implementations */
+//         .def("__repr__", [](const Type &v) {
+//             std::ostringstream oss;
+//             oss << v.transpose();
+//             return oss.str();
+//         })
+//         .def("__getitem__", [](const Type &m, size_t i) {
+//             if (i >= (size_t) m.size())
+//                 throw py::index_error();
+//             return m[i];
+//          })
+//         .def("__setitem__", [](Type &m, size_t i, Scalar v) {
+//             if (i >= (size_t) m.size())
+//                 throw py::index_error();
+//             m[i] = v;
+//          })
+//
+//         /* Buffer access for interacting with NumPy */
+//         .def_buffer([](Type &m) -> py::buffer_info {
+//             return py::buffer_info(
+//                 m.data(),                /* Pointer to buffer */
+//                 sizeof(Scalar),          /* Size of one scalar */
+//                 /* Python struct-style format descriptor */
+//                 py::format_descriptor<Scalar>::value(),
+//                 1,                       /* Number of dimensions */
+//                 { (size_t) m.size() },   /* Buffer dimensions */
+//                 { sizeof(Scalar) }       /* Strides (in bytes) for each index */
+//             );
+//          })
+//
+//         /* Static initializers */
+//         .def_static("Zero", [](size_t n) { return Type(Type::Zero(n)); })
+//         .def_static("Ones", [](size_t n) { return Type(Type::Ones(n)); })
+//         .def_static("Constant", [](size_t n, Scalar value) { return Type(Type::Constant(n, value)); })
+//         .def("MapMatrix", [](const Type& m, size_t r, size_t c)
+//         {
+//           return Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic>(Eigen::Map<const Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic>>(m.data(),r,c));
+//         })
+//         ;
+//     return vector;
+// }
 
 /// Creates Python bindings for a dynamic Eigen order-2 tensor (i.e. a matrix)
 template <typename Type>
@@ -266,6 +266,19 @@ py::class_<Type> bind_eigen_2(py::module &m, const char *name,
         .def("cols", [](const Type &m) { return m.cols(); })
         .def("rows", [](const Type &m) { return m.rows(); })
 
+        /* Extract rows and colums */
+        .def("col", [](const Type &m, int i) {
+            if (i<0 || i>=m.cols())
+              throw std::runtime_error("Column index out of bound.");
+            return Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic>(m.col(i));
+        })
+        .def("row", [](const Type &m, int i) {
+            if (i<0 || i>=m.rows())
+              throw std::runtime_error("Row index out of bound.");
+            return Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic>(m.row(i));
+        })
+
+
         /* Initialization */
         .def("setZero", [](Type &m) { m.setZero(); })
         .def("setIdentity", [](Type &m) { m.setIdentity(); })
@@ -565,14 +578,14 @@ void python_export_vector(py::module &m) {
     "eigen", "Wrappers for Eigen types");
 
     /* Bindings for VectorXd */
-    bind_eigen_1<Eigen::VectorXd> (me, "VectorXd");
-    py::implicitly_convertible<py::buffer, Eigen::VectorXd>();
-    py::implicitly_convertible<double, Eigen::VectorXd>();
+    // bind_eigen_1<Eigen::VectorXd> (me, "VectorXd");
+    // py::implicitly_convertible<py::buffer, Eigen::VectorXd>();
+    // py::implicitly_convertible<double, Eigen::VectorXd>();
 
     /* Bindings for VectorXi */
-    bind_eigen_1<Eigen::VectorXi> (me, "VectorXi");
-    py::implicitly_convertible<py::buffer, Eigen::VectorXi>();
-    py::implicitly_convertible<double, Eigen::VectorXi>();
+    // bind_eigen_1<Eigen::VectorXi> (me, "VectorXi");
+    // py::implicitly_convertible<py::buffer, Eigen::VectorXi>();
+    // py::implicitly_convertible<double, Eigen::VectorXi>();
 
     /* Bindings for MatrixXd */
     bind_eigen_2<Eigen::MatrixXd> (me, "MatrixXd");
@@ -584,24 +597,24 @@ void python_export_vector(py::module &m) {
     py::implicitly_convertible<py::buffer, Eigen::MatrixXi>();
     py::implicitly_convertible<double, Eigen::MatrixXi>();
 
-    /* Bindings for Vector3d */
-    auto vector3 = bind_eigen_1_3<Eigen::Vector3d>(me, "Vector3d");
-    vector3
-        .def("norm", [](const Eigen::Vector3d &v) { return v.norm(); })
-        .def("squaredNorm", [](const Eigen::Vector3d &v) { return v.squaredNorm(); })
-        .def("normalize", [](Eigen::Vector3d &v) { v.normalize(); })
-        .def("normalized", [](const Eigen::Vector3d &v) -> Eigen::Vector3d { return v.normalized(); })
-        .def("dot", [](const Eigen::Vector3d &v1, const Eigen::Vector3d &v2) { return v1.dot(v2); })
-        .def("cross", [](const Eigen::Vector3d &v1, const Eigen::Vector3d &v2) -> Eigen::Vector3d { return v1.cross(v2); })
-        .def_property("x", [](const Eigen::Vector3d &v) -> double { return v.x(); },
-                           [](Eigen::Vector3d &v, double x) { v.x() = x; }, "X coordinate")
-        .def_property("y", [](const Eigen::Vector3d &v) -> double { return v.y(); },
-                           [](Eigen::Vector3d &v, double y) { v.y() = y; }, "Y coordinate")
-        .def_property("z", [](const Eigen::Vector3d &v) -> double { return v.z(); },
-                           [](Eigen::Vector3d &v, double z) { v.z() = z; }, "Z coordinate");
-
-    py::implicitly_convertible<py::buffer, Eigen::Vector3d>();
-    py::implicitly_convertible<double, Eigen::Vector3d>();
+    // /* Bindings for Vector3d */
+    // auto vector3 = bind_eigen_1_3<Eigen::Vector3d>(me, "Vector3d");
+    // vector3
+    //     .def("norm", [](const Eigen::Vector3d &v) { return v.norm(); })
+    //     .def("squaredNorm", [](const Eigen::Vector3d &v) { return v.squaredNorm(); })
+    //     .def("normalize", [](Eigen::Vector3d &v) { v.normalize(); })
+    //     .def("normalized", [](const Eigen::Vector3d &v) -> Eigen::Vector3d { return v.normalized(); })
+    //     .def("dot", [](const Eigen::Vector3d &v1, const Eigen::Vector3d &v2) { return v1.dot(v2); })
+    //     .def("cross", [](const Eigen::Vector3d &v1, const Eigen::Vector3d &v2) -> Eigen::Vector3d { return v1.cross(v2); })
+    //     .def_property("x", [](const Eigen::Vector3d &v) -> double { return v.x(); },
+    //                        [](Eigen::Vector3d &v, double x) { v.x() = x; }, "X coordinate")
+    //     .def_property("y", [](const Eigen::Vector3d &v) -> double { return v.y(); },
+    //                        [](Eigen::Vector3d &v, double y) { v.y() = y; }, "Y coordinate")
+    //     .def_property("z", [](const Eigen::Vector3d &v) -> double { return v.z(); },
+    //                        [](Eigen::Vector3d &v, double z) { v.z() = z; }, "Z coordinate");
+    //
+    // py::implicitly_convertible<py::buffer, Eigen::Vector3d>();
+    // py::implicitly_convertible<double, Eigen::Vector3d>();
 
     /* Bindings for SparseMatrix<double> */
     bind_eigen_sparse_2< Eigen::SparseMatrix<double> > (me, "SparseMatrixd");

+ 24 - 0
python/python.cpp

@@ -3,6 +3,30 @@
 #include <string>
 #include <fstream>
 
+void assert_is_VectorXd(const std::string name, const Eigen::MatrixXd& v)
+{
+  if (v.cols() != 1)
+    throw std::runtime_error(name + " must be a column vector.");
+}
+
+void assert_is_RowVectorXd(const std::string name, const Eigen::MatrixXd& v)
+{
+  if (v.rows() != 1)
+    throw std::runtime_error(name + " must be a row vector.");
+}
+
+void assert_is_Vector3d(const std::string name, const Eigen::MatrixXd& v)
+{
+  if ((v.cols() != 1) || (v.rows() != 3))
+    throw std::runtime_error(name + " must be a column vector with 3 entries.");
+}
+
+void assert_is_RowVector3d(const std::string name, const Eigen::MatrixXd& v)
+{
+  if ((v.cols() != 3) || (v.rows() != 1))
+    throw std::runtime_error(name + " must be a row vector with 3 entries.");
+}
+
 extern void python_export_vector(py::module &);
 extern void python_export_igl(py::module &);
 extern void python_export_igl_viewer(py::module &);

+ 7 - 0
python/python.h

@@ -9,4 +9,11 @@
 
 #include "py_doc.h"
 
+#include <Eigen/Dense>
+
+void assert_is_VectorXd(const std::string name, const Eigen::MatrixXd& v);
+void assert_is_RowVectorXd(const std::string name, const Eigen::MatrixXd& v);
+void assert_is_Vector3d(const std::string name, const Eigen::MatrixXd& v);
+void assert_is_RowVector3d(const std::string name, const Eigen::MatrixXd& v);
+
 namespace py = pybind;