|
@@ -120,10 +120,351 @@ namespace igl
|
|
|
};
|
|
|
}
|
|
|
|
|
|
+// Implementation
|
|
|
+
|
|
|
// Be sure that this is not compiled into libigl.a
|
|
|
-#ifdef IGL_HEADER_ONLY
|
|
|
-# include "MatlabWorkspace.cpp"
|
|
|
-#endif
|
|
|
+// http://stackoverflow.com/a/3318993/148668
|
|
|
+
|
|
|
+// IGL
|
|
|
+#include "igl/list_to_matrix.h"
|
|
|
+
|
|
|
+// MATLAB
|
|
|
+#include "mat.h"
|
|
|
+
|
|
|
+// STL
|
|
|
+#include <iostream>
|
|
|
+#include <algorithm>
|
|
|
+#include <vector>
|
|
|
+
|
|
|
+IGL_INLINE igl::MatlabWorkspace::MatlabWorkspace()
|
|
|
+{
|
|
|
+}
|
|
|
+
|
|
|
+IGL_INLINE igl::MatlabWorkspace::~MatlabWorkspace()
|
|
|
+{
|
|
|
+ // clean up data
|
|
|
+ clear();
|
|
|
+}
|
|
|
+
|
|
|
+IGL_INLINE void igl::MatlabWorkspace::clear()
|
|
|
+{
|
|
|
+ for_each(data.begin(),data.end(),&mxDestroyArray);
|
|
|
+ data.clear();
|
|
|
+ names.clear();
|
|
|
+}
|
|
|
+
|
|
|
+IGL_INLINE bool igl::MatlabWorkspace::write(const std::string & path) const
|
|
|
+{
|
|
|
+ using namespace std;
|
|
|
+ MATFile * mat_file = matOpen(path.c_str(), "w");
|
|
|
+ assert(names.size() == data.size());
|
|
|
+ // loop over names and data
|
|
|
+ for(int i = 0;i < (int)names.size(); i++)
|
|
|
+ {
|
|
|
+ // Put variable as LOCAL variable
|
|
|
+ int status = matPutVariable(mat_file,names[i].c_str(), data[i]);
|
|
|
+ if(status != 0)
|
|
|
+ {
|
|
|
+ cerr<<"^MatlabWorkspace::save Error: matPutVariable ("<<names[i]<<
|
|
|
+ ") failed"<<endl;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(matClose(mat_file) != 0)
|
|
|
+ {
|
|
|
+ fprintf(stderr,"Error closing file %s\n",path.c_str());
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+IGL_INLINE bool igl::MatlabWorkspace::read(const std::string & path)
|
|
|
+{
|
|
|
+ using namespace std;
|
|
|
+
|
|
|
+ MATFile * mat_file;
|
|
|
+
|
|
|
+ mat_file = matOpen(path.c_str(), "r");
|
|
|
+ if (mat_file == NULL)
|
|
|
+ {
|
|
|
+ cerr<<"Error: failed to open "<<path<<endl;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ int ndir;
|
|
|
+ const char ** dir = (const char **)matGetDir(mat_file, &ndir);
|
|
|
+ if (dir == NULL) {
|
|
|
+ cerr<<"Error reading directory of file "<< path<<endl;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ mxFree(dir);
|
|
|
+
|
|
|
+ // Must close and reopen
|
|
|
+ if(matClose(mat_file) != 0)
|
|
|
+ {
|
|
|
+ cerr<<"Error: failed to close file "<<path<<endl;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ mat_file = matOpen(path.c_str(), "r");
|
|
|
+ if (mat_file == NULL)
|
|
|
+ {
|
|
|
+ cerr<<"Error: failed to open "<<path<<endl;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /* Read in each array. */
|
|
|
+ for (int i=0; i<ndir; i++)
|
|
|
+ {
|
|
|
+ const char * name;
|
|
|
+ mxArray * mx_data = matGetNextVariable(mat_file, &name);
|
|
|
+ if (mx_data == NULL)
|
|
|
+ {
|
|
|
+ cerr<<"Error: matGetNextVariable failed in "<<path<<endl;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ const int dims = mxGetNumberOfDimensions(mx_data);
|
|
|
+ assert(dims == 2);
|
|
|
+ if(dims != 2)
|
|
|
+ {
|
|
|
+ fprintf(stderr,"Variable '%s' has %d ≠ 2 dimensions. Skipping\n",
|
|
|
+ name,dims);
|
|
|
+ mxDestroyArray(mx_data);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ // don't destroy
|
|
|
+ names.push_back(name);
|
|
|
+ data.push_back(mx_data);
|
|
|
+ }
|
|
|
+
|
|
|
+ if(matClose(mat_file) != 0)
|
|
|
+ {
|
|
|
+ cerr<<"Error: failed to close file "<<path<<endl;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+// Treat everything as a double
|
|
|
+template <typename DerivedM>
|
|
|
+IGL_INLINE igl::MatlabWorkspace& igl::MatlabWorkspace::save(
|
|
|
+ const Eigen::PlainObjectBase<DerivedM>& M,
|
|
|
+ const std::string & name)
|
|
|
+{
|
|
|
+ using namespace std;
|
|
|
+ const int m = M.rows();
|
|
|
+ const int n = M.cols();
|
|
|
+ mxArray * mx_data = mxCreateDoubleMatrix(m,n,mxREAL);
|
|
|
+ data.push_back(mx_data);
|
|
|
+ names.push_back(name);
|
|
|
+ // Copy data immediately
|
|
|
+ // Q: Won't this be incorrect for integers?
|
|
|
+ copy(M.data(),M.data()+M.size(),mxGetPr(mx_data));
|
|
|
+ return *this;
|
|
|
+}
|
|
|
+
|
|
|
+// Treat everything as a double
|
|
|
+template <typename MT>
|
|
|
+IGL_INLINE igl::MatlabWorkspace& igl::MatlabWorkspace::save(
|
|
|
+ const Eigen::SparseMatrix<MT>& M,
|
|
|
+ const std::string & name)
|
|
|
+{
|
|
|
+ using namespace std;
|
|
|
+ const int m = M.rows();
|
|
|
+ const int n = M.cols();
|
|
|
+ // THIS WILL NOT WORK FOR ROW-MAJOR
|
|
|
+ assert(n==M.outerSize());
|
|
|
+ const int nzmax = M.nonZeros();
|
|
|
+ mxArray * mx_data = mxCreateSparse(m, n, nzmax, mxREAL);
|
|
|
+ data.push_back(mx_data);
|
|
|
+ names.push_back(name);
|
|
|
+ // Copy data immediately
|
|
|
+ double * pr = mxGetPr(mx_data);
|
|
|
+ mwIndex * ir = mxGetIr(mx_data);
|
|
|
+ mwIndex * jc = mxGetJc(mx_data);
|
|
|
+
|
|
|
+ // Iterate over outside
|
|
|
+ int k = 0;
|
|
|
+ for(int j=0; j<M.outerSize();j++)
|
|
|
+ {
|
|
|
+ jc[j] = k;
|
|
|
+ // Iterate over inside
|
|
|
+ for(typename Eigen::SparseMatrix<MT>::InnerIterator it (M,j); it; ++it)
|
|
|
+ {
|
|
|
+ pr[k] = it.value();
|
|
|
+ ir[k] = it.row();
|
|
|
+ k++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ jc[M.outerSize()] = k;
|
|
|
+
|
|
|
+ return *this;
|
|
|
+}
|
|
|
+
|
|
|
+template <typename ScalarM>
|
|
|
+IGL_INLINE igl::MatlabWorkspace& igl::MatlabWorkspace::save(
|
|
|
+ const std::vector<std::vector<ScalarM> > & vM,
|
|
|
+ const std::string & name)
|
|
|
+{
|
|
|
+ Eigen::MatrixXd M;
|
|
|
+ list_to_matrix(vM,M);
|
|
|
+ return this->save(M,name);
|
|
|
+}
|
|
|
+
|
|
|
+template <typename ScalarV>
|
|
|
+IGL_INLINE igl::MatlabWorkspace& igl::MatlabWorkspace::save(
|
|
|
+ const std::vector<ScalarV> & vV,
|
|
|
+ const std::string & name)
|
|
|
+{
|
|
|
+ Eigen::MatrixXd V;
|
|
|
+ list_to_matrix(vV,V);
|
|
|
+ return this->save(V,name);
|
|
|
+}
|
|
|
+
|
|
|
+template <typename DerivedM>
|
|
|
+IGL_INLINE igl::MatlabWorkspace&
|
|
|
+ igl::MatlabWorkspace::save_index(
|
|
|
+ const Eigen::PlainObjectBase<DerivedM>& M,
|
|
|
+ const std::string & name)
|
|
|
+{
|
|
|
+ DerivedM Mp1 = M;
|
|
|
+ Mp1.array() += 1;
|
|
|
+ return this->save(Mp1,name);
|
|
|
+}
|
|
|
+
|
|
|
+template <typename ScalarM>
|
|
|
+IGL_INLINE igl::MatlabWorkspace& igl::MatlabWorkspace::save_index(
|
|
|
+ const std::vector<std::vector<ScalarM> > & vM,
|
|
|
+ const std::string & name)
|
|
|
+{
|
|
|
+ Eigen::MatrixXd M;
|
|
|
+ list_to_matrix(vM,M);
|
|
|
+ return this->save_index(M,name);
|
|
|
+}
|
|
|
+
|
|
|
+template <typename ScalarV>
|
|
|
+IGL_INLINE igl::MatlabWorkspace& igl::MatlabWorkspace::save_index(
|
|
|
+ const std::vector<ScalarV> & vV,
|
|
|
+ const std::string & name)
|
|
|
+{
|
|
|
+ Eigen::MatrixXd V;
|
|
|
+ list_to_matrix(vV,V);
|
|
|
+ return this->save_index(V,name);
|
|
|
+}
|
|
|
+
|
|
|
+template <typename DerivedM>
|
|
|
+IGL_INLINE bool igl::MatlabWorkspace::find(
|
|
|
+ const std::string & name,
|
|
|
+ Eigen::PlainObjectBase<DerivedM>& M)
|
|
|
+{
|
|
|
+ using namespace std;
|
|
|
+ const int i = std::find(names.begin(), names.end(), name)-names.begin();
|
|
|
+ if(i>=(int)names.size())
|
|
|
+ {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ assert(i<=(int)data.size());
|
|
|
+ mxArray * mx_data = data[i];
|
|
|
+ assert(!mxIsSparse(mx_data));
|
|
|
+ assert(mxGetNumberOfDimensions(mx_data) == 2);
|
|
|
+ //cout<<name<<": "<<mxGetM(mx_data)<<" "<<mxGetN(mx_data)<<endl;
|
|
|
+ const int m = mxGetM(mx_data);
|
|
|
+ const int n = mxGetN(mx_data);
|
|
|
+
|
|
|
+ // Handle vectors
|
|
|
+ if(DerivedM::IsVectorAtCompileTime)
|
|
|
+ {
|
|
|
+ assert(m==1 || n==1 || (m==0 && n==0));
|
|
|
+ M.resize(m*n);
|
|
|
+ }else
|
|
|
+ {
|
|
|
+ M.resize(m,n);
|
|
|
+ }
|
|
|
+ copy(
|
|
|
+ mxGetPr(mx_data),
|
|
|
+ mxGetPr(mx_data)+mxGetNumberOfElements(mx_data),
|
|
|
+ M.data());
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+template <typename MT>
|
|
|
+IGL_INLINE bool igl::MatlabWorkspace::find(
|
|
|
+ const std::string & name,
|
|
|
+ Eigen::SparseMatrix<MT>& M)
|
|
|
+{
|
|
|
+ using namespace std;
|
|
|
+ using namespace Eigen;
|
|
|
+ const int i = std::find(names.begin(), names.end(), name)-names.begin();
|
|
|
+ if(i>=(int)names.size())
|
|
|
+ {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ assert(i<=(int)data.size());
|
|
|
+ mxArray * mx_data = data[i];
|
|
|
+ // Handle boring case where matrix is actually an empty dense matrix
|
|
|
+ if(mxGetNumberOfElements(mx_data) == 0)
|
|
|
+ {
|
|
|
+ M.resize(0,0);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ assert(mxIsSparse(mx_data));
|
|
|
+ assert(mxGetNumberOfDimensions(mx_data) == 2);
|
|
|
+ //cout<<name<<": "<<mxGetM(mx_data)<<" "<<mxGetN(mx_data)<<endl;
|
|
|
+ const int m = mxGetM(mx_data);
|
|
|
+ const int n = mxGetN(mx_data);
|
|
|
+
|
|
|
+ // Copy data immediately
|
|
|
+ double * pr = mxGetPr(mx_data);
|
|
|
+ mwIndex * ir = mxGetIr(mx_data);
|
|
|
+ mwIndex * jc = mxGetJc(mx_data);
|
|
|
+
|
|
|
+ vector<Triplet<MT> > MIJV;
|
|
|
+ MIJV.reserve(mxGetNumberOfElements(mx_data));
|
|
|
+
|
|
|
+ // Iterate over outside
|
|
|
+ int k = 0;
|
|
|
+ for(int j=0; j<n;j++)
|
|
|
+ {
|
|
|
+ // Iterate over inside
|
|
|
+ while(k<(int)jc[j+1])
|
|
|
+ {
|
|
|
+ //cout<<ir[k]<<" "<<j<<" "<<pr[k]<<endl;
|
|
|
+ assert((int)ir[k]<m);
|
|
|
+ assert((int)j<n);
|
|
|
+ MIJV.push_back(Triplet<MT >(ir[k],j,pr[k]));
|
|
|
+ k++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ M.resize(m,n);
|
|
|
+ M.setFromTriplets(MIJV.begin(),MIJV.end());
|
|
|
+ return true;
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+template <typename DerivedM>
|
|
|
+IGL_INLINE bool igl::MatlabWorkspace::find_index(
|
|
|
+ const std::string & name,
|
|
|
+ Eigen::PlainObjectBase<DerivedM>& M)
|
|
|
+{
|
|
|
+ if(!find(name,M))
|
|
|
+ {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ M.array() -= 1;
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+//template <typename Data>
|
|
|
+//bool igl::MatlabWorkspace::save(const Data & M, const std::string & name)
|
|
|
+//{
|
|
|
+// using namespace std;
|
|
|
+// // If I don't know the type then I can't save it
|
|
|
+// cerr<<"^MatlabWorkspace::save Error: Unknown data type. "<<
|
|
|
+// name<<" not saved."<<endl;
|
|
|
+// return false;
|
|
|
+//}
|
|
|
|
|
|
#endif
|
|
|
|