diff --git a/python/104_Colors.py b/python/104_Colors.py new file mode 100755 index 000000000..7f4be8c95 --- /dev/null +++ b/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() diff --git a/python/202_GaussianCurvature.py b/python/202_GaussianCurvature.py index da89b4b81..40ef9610b 100644 --- a/python/202_GaussianCurvature.py +++ b/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='') diff --git a/python/py_igl/py_gaussian_curvature.cpp b/python/py_igl/py_gaussian_curvature.cpp index e2bf30c55..39204df2b 100644 --- a/python/py_igl/py_gaussian_curvature.cpp +++ b/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); diff --git a/python/py_igl/py_jet.cpp b/python/py_igl/py_jet.cpp index e532fa353..2e714005c 100644 --- a/python/py_igl/py_jet.cpp +++ b/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")); diff --git a/python/py_igl/py_parula.cpp b/python/py_igl/py_parula.cpp index e88e17b8c..7b97212a2 100644 --- a/python/py_igl/py_parula.cpp +++ b/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")); diff --git a/python/py_igl/py_per_face_normals.cpp b/python/py_igl/py_per_face_normals.cpp index 622cd7546..cc21929a7 100644 --- a/python/py_igl/py_per_face_normals.cpp +++ b/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")); diff --git a/python/py_igl/py_principal_curvature.cpp b/python/py_igl/py_principal_curvature.cpp index e345474e3..cd6e671ab 100644 --- a/python/py_igl/py_principal_curvature.cpp +++ b/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 ) diff --git a/python/py_igl_viewer.cpp b/python/py_igl_viewer.cpp index 6c0913983..d7e560e30 100644 --- a/python/py_igl_viewer.cpp +++ b/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_ 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_ 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()); + }) + + // // 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_(me, "Viewer") .def(py::init<>()) .def_readwrite("data", &igl::viewer::Viewer::data) diff --git a/python/py_vector.cpp b/python/py_vector.cpp index cfc4bc4e1..641b8172f 100644 --- a/python/py_vector.cpp +++ b/python/py_vector.cpp @@ -3,223 +3,223 @@ #include "python.h" -template 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::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 -py::class_ bind_eigen_1_3(py::module &m, const char *name, - py::object parent = py::object()) { - typedef typename Type::Scalar Scalar; - - py::class_ vector(m, name, parent); - vector - /* Constructors */ - .def(py::init<>()) - .def(py::init()) - .def(py::init()) - .def("__init__", [](Type &v, const std::vector &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::value(), - 1, { (size_t) 3 }, - { sizeof(Scalar) } - ); - }); - return vector; -} - -/// Creates Python bindings for a dynamic Eigen order-1 tensor (i.e. a vector) -template -py::class_ 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_ vector(m, name, parent); - - vector - /* Constructors */ - .def(py::init<>()) - .def(py::init()) - .def("__init__", [](Type &v, const std::vector &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::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::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(Eigen::Map>(m.data(),r,c)); - }) - ; - return vector; -} +// template 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::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 +// py::class_ bind_eigen_1_3(py::module &m, const char *name, +// py::object parent = py::object()) { +// typedef typename Type::Scalar Scalar; +// +// py::class_ vector(m, name, parent); +// vector +// /* Constructors */ +// .def(py::init<>()) +// .def(py::init()) +// .def(py::init()) +// .def("__init__", [](Type &v, const std::vector &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::value(), +// 1, { (size_t) 3 }, +// { sizeof(Scalar) } +// ); +// }); +// return vector; +// } +// +// /// Creates Python bindings for a dynamic Eigen order-1 tensor (i.e. a vector) +// template +// py::class_ 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_ vector(m, name, parent); +// +// vector +// /* Constructors */ +// .def(py::init<>()) +// .def(py::init()) +// .def("__init__", [](Type &v, const std::vector &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::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::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(Eigen::Map>(m.data(),r,c)); +// }) +// ; +// return vector; +// } /// Creates Python bindings for a dynamic Eigen order-2 tensor (i.e. a matrix) template @@ -266,6 +266,19 @@ py::class_ 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(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(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 (me, "VectorXd"); - py::implicitly_convertible(); - py::implicitly_convertible(); + // bind_eigen_1 (me, "VectorXd"); + // py::implicitly_convertible(); + // py::implicitly_convertible(); /* Bindings for VectorXi */ - bind_eigen_1 (me, "VectorXi"); - py::implicitly_convertible(); - py::implicitly_convertible(); + // bind_eigen_1 (me, "VectorXi"); + // py::implicitly_convertible(); + // py::implicitly_convertible(); /* Bindings for MatrixXd */ bind_eigen_2 (me, "MatrixXd"); @@ -584,24 +597,24 @@ void python_export_vector(py::module &m) { py::implicitly_convertible(); py::implicitly_convertible(); - /* Bindings for Vector3d */ - auto vector3 = bind_eigen_1_3(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::implicitly_convertible(); + // /* Bindings for Vector3d */ + // auto vector3 = bind_eigen_1_3(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::implicitly_convertible(); /* Bindings for SparseMatrix */ bind_eigen_sparse_2< Eigen::SparseMatrix > (me, "SparseMatrixd"); diff --git a/python/python.cpp b/python/python.cpp index 2141ec027..a3ceeb0b7 100644 --- a/python/python.cpp +++ b/python/python.cpp @@ -3,6 +3,30 @@ #include #include +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 &); diff --git a/python/python.h b/python/python.h index f79df2f76..7faa96902 100644 --- a/python/python.h +++ b/python/python.h @@ -9,4 +9,11 @@ #include "py_doc.h" +#include + +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;