Browse Source

fixed deprecated types in cotmatrix
improved matlabinterface to support sending sparse matrices to matlab
added matlab example for the tutorial


Former-commit-id: d23c7f1fbc39fc5a50f42e0ee9748853940bbeff

Daniele Panozzo 11 years ago
parent
commit
7b133fc555

+ 2 - 2
include/igl/cotmatrix.cpp

@@ -23,9 +23,9 @@ IGL_INLINE void igl::cotmatrix(
 {
   using namespace igl;
   using namespace Eigen;
-  Eigen::DynamicSparseMatrix<double> foo;
+  Eigen::SparseMatrix<double> foo;
 
-  DynamicSparseMatrix<Scalar, RowMajor> dyn_L (V.rows(), V.rows());
+  SparseMatrix<Scalar, RowMajor> dyn_L (V.rows(), V.rows());
   Matrix<int,Dynamic,2> edges;
   int simplex_size = F.cols();
   // 3 for triangles, 4 for tets

+ 81 - 46
include/igl/matlab/matlabinterface.cpp

@@ -1,15 +1,15 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
+//
 // Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
-// 
-// This Source Code Form is subject to the terms of the Mozilla Public License 
-// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
 // obtain one at http://mozilla.org/MPL/2.0/.
 #include <igl/matlab/matlabinterface.h>
 
 // Implementation
 
-// Init the MATLAB engine 
+// Init the MATLAB engine
 // (no need to call it directly since it is automatically invoked by any other command)
 IGL_INLINE void igl::mlinit(Engine** mlengine)
 {
@@ -28,15 +28,15 @@ IGL_INLINE void igl::mlsetmatrix(Engine** mlengine, std::string name, const Eige
 {
   if (*mlengine == 0)
     mlinit(mlengine);
-  
+
   mxArray *A = mxCreateDoubleMatrix(M.rows(), M.cols(), mxREAL);
   double *pM = mxGetPr(A);
-  
+
   int c = 0;
   for(int j=0; j<M.cols();++j)
     for(int i=0; i<M.rows();++i)
       pM[c++] = double(M(i,j));
-  
+
   engPutVariable(*mlengine, name.c_str(), A);
   mxDestroyArray(A);
 }
@@ -46,15 +46,15 @@ IGL_INLINE void igl::mlsetmatrix(Engine** mlengine, std::string name, const Eige
 {
   if (*mlengine == 0)
     mlinit(mlengine);
-  
+
   mxArray *A = mxCreateDoubleMatrix(M.rows(), M.cols(), mxREAL);
   double *pM = mxGetPr(A);
-  
+
   int c = 0;
   for(int j=0; j<M.cols();++j)
     for(int i=0; i<M.rows();++i)
       pM[c++] = double(M(i,j));
-  
+
   engPutVariable(*mlengine, name.c_str(), A);
   mxDestroyArray(A);
 }
@@ -64,15 +64,15 @@ IGL_INLINE void igl::mlsetmatrix(Engine** mlengine, std::string name, const Eige
 {
   if (*mlengine == 0)
     mlinit(mlengine);
-  
+
   mxArray *A = mxCreateDoubleMatrix(M.rows(), M.cols(), mxREAL);
   double *pM = mxGetPr(A);
-  
+
   int c = 0;
   for(int j=0; j<M.cols();++j)
     for(int i=0; i<M.rows();++i)
       pM[c++] = double(M(i,j))+1;
-  
+
   engPutVariable(*mlengine, name.c_str(), A);
   mxDestroyArray(A);
 }
@@ -82,15 +82,15 @@ IGL_INLINE void igl::mlsetmatrix(Engine** mlengine, std::string name, const Eige
 {
   if (*mlengine == 0)
     mlinit(mlengine);
-  
+
   mxArray *A = mxCreateDoubleMatrix(M.rows(), M.cols(), mxREAL);
   double *pM = mxGetPr(A);
-  
+
   int c = 0;
   for(int j=0; j<M.cols();++j)
     for(int i=0; i<M.rows();++i)
       pM[c++] = double(M(i,j))+1;
-  
+
   engPutVariable(*mlengine, name.c_str(), A);
   mxDestroyArray(A);
 }
@@ -100,11 +100,11 @@ IGL_INLINE void igl::mlgetmatrix(Engine** mlengine, std::string name, Eigen::Mat
 {
   if (*mlengine == 0)
     mlinit(mlengine);
-  
+
   unsigned long m = 0;
   unsigned long n = 0;
   std::vector<double> t;
-  
+
   mxArray *ary = engGetVariable(*mlengine, name.c_str());
   if (ary == NULL)
   {
@@ -117,7 +117,7 @@ IGL_INLINE void igl::mlgetmatrix(Engine** mlengine, std::string name, Eigen::Mat
     m = mxGetM(ary);
     n = mxGetN(ary);
     M = Eigen::MatrixXd(m,n);
-    
+
     double *pM = mxGetPr(ary);
 
     int c = 0;
@@ -125,7 +125,7 @@ IGL_INLINE void igl::mlgetmatrix(Engine** mlengine, std::string name, Eigen::Mat
       for(int i=0; i<M.rows();++i)
         M(i,j) = pM[c++];
   }
-  
+
   mxDestroyArray(ary);
 }
 
@@ -133,11 +133,11 @@ IGL_INLINE void igl::mlgetmatrix(Engine** mlengine, std::string name, Eigen::Mat
 {
   if (*mlengine == 0)
     mlinit(mlengine);
-  
+
   unsigned long m = 0;
   unsigned long n = 0;
   std::vector<double> t;
-  
+
   mxArray *ary = engGetVariable(*mlengine, name.c_str());
   if (ary == NULL)
   {
@@ -150,15 +150,15 @@ IGL_INLINE void igl::mlgetmatrix(Engine** mlengine, std::string name, Eigen::Mat
     m = mxGetM(ary);
     n = mxGetN(ary);
     M = Eigen::MatrixXf(m,n);
-    
+
     double *pM = mxGetPr(ary);
-    
+
     int c = 0;
     for(int j=0; j<M.cols();++j)
       for(int i=0; i<M.rows();++i)
         M(i,j) = pM[c++];
   }
-  
+
   mxDestroyArray(ary);
 }
 
@@ -167,11 +167,11 @@ IGL_INLINE void igl::mlgetmatrix(Engine** mlengine, std::string name, Eigen::Mat
 {
   if (*mlengine == 0)
     mlinit(mlengine);
-  
+
   unsigned long m = 0;
   unsigned long n = 0;
   std::vector<double> t;
-  
+
   mxArray *ary = engGetVariable(*mlengine, name.c_str());
   if (ary == NULL)
   {
@@ -184,15 +184,15 @@ IGL_INLINE void igl::mlgetmatrix(Engine** mlengine, std::string name, Eigen::Mat
     m = mxGetM(ary);
     n = mxGetN(ary);
     M = Eigen::MatrixXi(m,n);
-    
+
     double *pM = mxGetPr(ary);
-    
+
     int c = 0;
     for(int j=0; j<M.cols();++j)
       for(int i=0; i<M.rows();++i)
         M(i,j) = int(pM[c++])-1;
   }
-  
+
   mxDestroyArray(ary);
 }
 
@@ -201,11 +201,11 @@ IGL_INLINE void igl::mlgetmatrix(Engine** mlengine, std::string name, Eigen::Mat
 {
   if (*mlengine == 0)
     mlinit(mlengine);
-  
+
   unsigned long m = 0;
   unsigned long n = 0;
   std::vector<double> t;
-  
+
   mxArray *ary = engGetVariable(*mlengine, name.c_str());
   if (ary == NULL)
   {
@@ -218,15 +218,15 @@ IGL_INLINE void igl::mlgetmatrix(Engine** mlengine, std::string name, Eigen::Mat
     m = mxGetM(ary);
     n = mxGetN(ary);
     M = Eigen::Matrix<unsigned int, Eigen::Dynamic, Eigen::Dynamic >(m,n);
-    
+
     double *pM = mxGetPr(ary);
-    
+
     int c = 0;
     for(int j=0; j<M.cols();++j)
       for(int i=0; i<M.rows();++i)
         M(i,j) = (unsigned int)(pM[c++])-1;
   }
-  
+
   mxDestroyArray(ary);
 }
 
@@ -236,7 +236,7 @@ IGL_INLINE void igl::mlsetscalar(Engine** mlengine, std::string name, double s)
 {
   if (*mlengine == 0)
     mlinit(mlengine);
-  
+
   Eigen::MatrixXd M(1,1);
   M(0,0) = s;
   mlsetmatrix(mlengine, name, M);
@@ -247,7 +247,7 @@ IGL_INLINE double igl::mlgetscalar(Engine** mlengine, std::string name)
 {
   if (*mlengine == 0)
     mlinit(mlengine);
-  
+
   Eigen::MatrixXd M;
   mlgetmatrix(mlengine, name,M);
   return M(0,0);
@@ -258,15 +258,15 @@ IGL_INLINE std::string igl::mleval(Engine** mlengine, std::string code)
 {
   if (*mlengine == 0)
     mlinit(mlengine);
-  
+
   const char *matlab_code = code.c_str();
   const int BUF_SIZE = 4096*4096;
   // allocate on the heap to avoid running out of stack
   std::string bufauto(BUF_SIZE+1, '\0');
   char *buf = &bufauto[0];
-  
+
   assert(matlab_code != NULL);
-  
+
   // Use RAII ensure that on leaving this scope, the output buffer is
   // always nullified (to prevent Matlab from accessing memory that might
   // have already been deallocated).
@@ -275,21 +275,56 @@ IGL_INLINE std::string igl::mleval(Engine** mlengine, std::string code)
     cleanup(Engine *ep) : m_ep(ep) { }
     ~cleanup() { engOutputBuffer(m_ep, NULL, 0); }
   } cleanup_obj(*mlengine);
-  
+
   if (buf != NULL)
     engOutputBuffer(*mlengine, buf, BUF_SIZE);
-  
+
   int res = engEvalString(*mlengine, matlab_code);
-  
+
   if (res != 0) {
     std::ostringstream oss;
     oss << "ERROR: Matlab command failed with error code " << res << ".\n";
     return oss.str();
   }
-  
+
   if (buf[0] == '>' && buf[1] == '>' && buf[2] == ' ')
     buf += 3;
   if (buf[0] == '\n') ++buf;
-  
+
   return std::string(buf);
 }
+
+// Send a sparse matrix
+IGL_INLINE void igl::mlsetmatrix(Engine** mlengine, std::string name, const Eigen::SparseMatrix<double>& M)
+{
+  int count = 0;
+//  // Count non-zero
+//  for (unsigned k=0; k<M.outerSize(); ++k)
+//    for (Eigen::SparseMatrix<double>::InnerIterator it(M,k); it; ++it)
+//      if (it.value() != 0)
+//        ++count;
+  
+  Eigen::MatrixXd T(M.nonZeros(),3);
+  for (unsigned k=0; k<M.outerSize(); ++k)
+  {
+    for (Eigen::SparseMatrix<double>::InnerIterator it(M,k); it; ++it)
+    {
+      T(count,0) = it.row();
+      T(count,1) = it.col();
+      T(count,2) = it.value();
+      ++count;
+    }
+  }
+
+  T.col(0) = T.col(0).array()+1;
+  T.col(1) = T.col(1).array()+1;
+
+  mlsetmatrix(mlengine,"temp93765",T);
+  
+  std::string temp = name + " = sparse(temp93765(:,1),temp93765(:,2),temp93765(:,3),"
+                          + std::to_string(M.rows()) + ","
+                          + std::to_string(M.cols()) + ");";
+  
+  mleval(mlengine,temp);
+  mleval(mlengine,"clear temp93765");
+}

+ 21 - 17
include/igl/matlab/matlabinterface.h

@@ -1,9 +1,9 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
-// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
-// 
-// This Source Code Form is subject to the terms of the Mozilla Public License 
-// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+//
+// Copyright (C) 2013 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
 // obtain one at http://mozilla.org/MPL/2.0/.
 #ifndef IGL_MATLAB_INTERFACE_H
 #define IGL_MATLAB_INTERFACE_H
@@ -21,6 +21,7 @@
 // PATH = /opt/local/bin:/opt/local/sbin:/Applications/MATLAB_R2011a.app/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/texbin:/usr/X11/bin
 
 #include <Eigen/Core>
+#include <Eigen/Sparse>
 #include <string>
 
 #include <complex>
@@ -31,48 +32,51 @@
 
 #include "engine.h"  // Matlab engine header
 
-namespace igl 
+namespace igl
 {
-  // Init the MATLAB engine 
+  // Init the MATLAB engine
   // (no need to call it directly since it is automatically invoked by any other command)
   IGL_INLINE void mlinit(Engine** engine);
-  
+
   // Closes the MATLAB engine
   IGL_INLINE void mlclose(Engine** engine);
-  
+
   // Send a matrix to MATLAB
   IGL_INLINE void mlsetmatrix(Engine** engine, std::string name, const Eigen::MatrixXd& M);
-  
+
   // Send a matrix to MATLAB
   IGL_INLINE void mlsetmatrix(Engine** engine, std::string name, const Eigen::MatrixXf& M);
 
   // Send a matrix to MATLAB
   IGL_INLINE void mlsetmatrix(Engine** engine, std::string name, const Eigen::MatrixXi& M);
-  
+
   // Send a matrix to MATLAB
   IGL_INLINE void mlsetmatrix(Engine** mlengine, std::string name, const Eigen::Matrix<unsigned int, Eigen::Dynamic, Eigen::Dynamic >& M);
-  
+
   // Receive a matrix from MATLAB
   IGL_INLINE void mlgetmatrix(Engine** engine, std::string name, Eigen::MatrixXd& M);
-  
+
   // Receive a matrix from MATLAB
   IGL_INLINE void mlgetmatrix(Engine** engine, std::string name, Eigen::MatrixXf& M);
 
   // Receive a matrix from MATLAB
   IGL_INLINE void mlgetmatrix(Engine** engine, std::string name, Eigen::MatrixXi& M);
-  
+
   // Receive a matrix from MATLAB
   IGL_INLINE void mlgetmatrix(Engine** mlengine, std::string name, Eigen::Matrix<unsigned int, Eigen::Dynamic, Eigen::Dynamic >& M);
 
   // Send a single scalar to MATLAB
   IGL_INLINE void mlsetscalar(Engine** engine, std::string name, double s);
-  
+
   // Receive a single scalar from MATLAB
   IGL_INLINE double mlgetscalar(Engine** engine, std::string name);
-  
+
   // Execute arbitrary MATLAB code and return the MATLAB output
   IGL_INLINE std::string mleval(Engine** engine, std::string code);
-  
+
+  // Send a sparse matrix to MATLAB
+  IGL_INLINE void mlsetmatrix(Engine** mlengine, std::string name, const Eigen::SparseMatrix<double>& M);
+
 }
 
 // Be sure that this is not compiled into libigl.a

+ 20 - 0
tutorial/106_Matlab/CMakeLists.txt

@@ -0,0 +1,20 @@
+cmake_minimum_required(VERSION 2.6)
+project(106_Matlab)
+
+include("../CMakeLists.shared")
+
+find_package(MATLAB REQUIRED)
+include_directories( ${MATLAB_INCLUDE_DIR} )
+
+set(SOURCES
+${PROJECT_SOURCE_DIR}/main.cpp
+)
+
+if(APPLE)
+  set(CMAKE_EXE_LINKER_FLAGS "-rpath ${MATLAB_INCLUDE_DIR}/../../bin/maci64"})
+endif (APPLE) #APPLE
+
+#message(FATAL_ERROR ${CMAKE_EXE_LINKER_FLAGS})
+
+add_executable(106_Matlab ${SOURCES} ${SHARED_SOURCES})
+target_link_libraries(106_Matlab ${SHARED_LIBRARIES} ${MATLAB_LIBRARIES})

+ 82 - 0
tutorial/106_Matlab/main.cpp

@@ -0,0 +1,82 @@
+#define IGL_HEADER_ONLY
+#include <igl/readOFF.h>
+#include <igl/matlab/matlabinterface.h>
+#include <igl/viewer/Viewer.h>
+#include <igl/jet.h>
+#include <igl/cotmatrix.h>
+
+// Base mesh
+Eigen::MatrixXd V;
+Eigen::MatrixXi F;
+
+// Matlab instance
+Engine* engine;
+
+// Eigenvectors of the laplacian
+Eigen::MatrixXd EV;
+
+void plotEV(igl::Viewer& viewer, int id)
+{
+  Eigen::VectorXd v = EV.col(id);
+  v = v.array() - v.minCoeff();
+  v = v.array() / v.maxCoeff();
+
+  // Map to colors using jet colorramp
+  Eigen::MatrixXd C(V.rows(),3);
+  for (unsigned i=0; i<V.rows(); ++i)
+  {
+    double r,g,b;
+    igl::jet(v(i),r,g,b);
+    C.row(i) << r,g,b;
+  }
+
+  viewer.draw_colors(C);
+}
+
+// This function is called every time a keyboard button is pressed
+bool key_down(igl::Viewer& viewer, unsigned char key, int modifier)
+{
+  if (key >= '1' && key <= '9')
+    plotEV(viewer,(key - '1') + 1);
+
+  return false;
+}
+
+int main(int argc, char *argv[])
+{
+  // Load a mesh in OFF format
+  igl::readOFF("../shared/3holes.off", V, F);
+
+  // Launch MATLAB
+  igl::mlinit(&engine);
+
+  // Compute the discrete Laplacian operator
+  Eigen::SparseMatrix<double> L;
+  igl::cotmatrix(V,F,L);
+
+  // Send Laplacian matrix to matlab
+  igl::mlsetmatrix(&engine,"L",L);
+
+  // Plot the laplacian matri using matlab spy
+  igl::mleval(&engine,"spy(L)");
+
+  // Extract the first 10 eigenvectors
+  igl::mleval(&engine,"[EV,~] = eigs(-L,10,'sm')");
+
+  // Plot the size of EV (only for demostration purposes)
+  std::cerr << igl::mleval(&engine,"size(EV)") << std::endl;
+
+  // Retrieve the result
+  igl::mlgetmatrix(&engine,"EV",EV);
+
+  // Plot the mesh
+  igl::Viewer viewer;
+  viewer.callback_key_down = &key_down;
+  viewer.draw_mesh(V, F);
+
+  // Plot the first non-trivial eigenvector
+  plotEV(viewer,1);
+
+  // Launch the viewer
+  viewer.launch();
+}

+ 10 - 0
tutorial/106_Matlab/run.sh

@@ -0,0 +1,10 @@
+# Make sure that matlab can be launched from the commandline
+# if it is not the case use the following commands:
+# cd /usr/local/bin
+# sudo ln -s /Applications/MATLAB_R2012b.app/bin/matlab
+
+# Tested on MAC only
+
+DYLD_LIBRARY_PATH=/Applications/MATLAB_R2012b.app/bin/maci64/
+
+./build/106_Matlab

+ 1 - 0
tutorial/shared/3holes.off.REMOVED.git-id

@@ -0,0 +1 @@
+e677b373d990a5ee037947ed5cdce68542637afa