331 lines
7.8 KiB
C++
331 lines
7.8 KiB
C++
// 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
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#include <igl/matlab/matlabinterface.h>
|
|
|
|
// Implementation
|
|
|
|
// Init the MATLAB engine
|
|
// (no need to call it directly since it is automatically invoked by any other command)
|
|
IGL_INLINE void igl::matlab::mlinit(Engine** mlengine)
|
|
{
|
|
*mlengine = engOpen("\0");
|
|
}
|
|
|
|
// Closes the MATLAB engine
|
|
IGL_INLINE void igl::matlab::mlclose(Engine** mlengine)
|
|
{
|
|
engClose(*mlengine);
|
|
*mlengine = 0;
|
|
}
|
|
|
|
// Send a matrix to MATLAB
|
|
IGL_INLINE void igl::matlab::mlsetmatrix(Engine** mlengine, std::string name, const Eigen::MatrixXd& M)
|
|
{
|
|
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);
|
|
}
|
|
|
|
// Send a matrix to MATLAB
|
|
IGL_INLINE void igl::matlab::mlsetmatrix(Engine** mlengine, std::string name, const Eigen::MatrixXf& M)
|
|
{
|
|
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);
|
|
}
|
|
|
|
// Send a matrix to MATLAB
|
|
IGL_INLINE void igl::matlab::mlsetmatrix(Engine** mlengine, std::string name, const Eigen::MatrixXi& M)
|
|
{
|
|
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);
|
|
}
|
|
|
|
// Send a matrix to MATLAB
|
|
IGL_INLINE void igl::matlab::mlsetmatrix(Engine** mlengine, std::string name, const Eigen::Matrix<unsigned int, Eigen::Dynamic, Eigen::Dynamic >& M)
|
|
{
|
|
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);
|
|
}
|
|
|
|
// Receive a matrix from MATLAB
|
|
IGL_INLINE void igl::matlab::mlgetmatrix(Engine** mlengine, std::string name, Eigen::MatrixXd& M)
|
|
{
|
|
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)
|
|
{
|
|
m = 0;
|
|
n = 0;
|
|
M = Eigen::MatrixXd(0,0);
|
|
}
|
|
else
|
|
{
|
|
m = mxGetM(ary);
|
|
n = mxGetN(ary);
|
|
M = Eigen::MatrixXd(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);
|
|
}
|
|
|
|
IGL_INLINE void igl::matlab::mlgetmatrix(Engine** mlengine, std::string name, Eigen::MatrixXf& M)
|
|
{
|
|
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)
|
|
{
|
|
m = 0;
|
|
n = 0;
|
|
M = Eigen::MatrixXf(0,0);
|
|
}
|
|
else
|
|
{
|
|
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);
|
|
}
|
|
|
|
// Receive a matrix from MATLAB
|
|
IGL_INLINE void igl::matlab::mlgetmatrix(Engine** mlengine, std::string name, Eigen::MatrixXi& M)
|
|
{
|
|
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)
|
|
{
|
|
m = 0;
|
|
n = 0;
|
|
M = Eigen::MatrixXi(0,0);
|
|
}
|
|
else
|
|
{
|
|
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);
|
|
}
|
|
|
|
// Receive a matrix from MATLAB
|
|
IGL_INLINE void igl::matlab::mlgetmatrix(Engine** mlengine, std::string name, Eigen::Matrix<unsigned int, Eigen::Dynamic, Eigen::Dynamic >& M)
|
|
{
|
|
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)
|
|
{
|
|
m = 0;
|
|
n = 0;
|
|
M = Eigen::Matrix<unsigned int, Eigen::Dynamic, Eigen::Dynamic >(0,0);
|
|
}
|
|
else
|
|
{
|
|
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);
|
|
}
|
|
|
|
|
|
// Send a single scalar to MATLAB
|
|
IGL_INLINE void igl::matlab::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);
|
|
}
|
|
|
|
// Receive a single scalar from MATLAB
|
|
IGL_INLINE double igl::matlab::mlgetscalar(Engine** mlengine, std::string name)
|
|
{
|
|
if (*mlengine == 0)
|
|
mlinit(mlengine);
|
|
|
|
Eigen::MatrixXd M;
|
|
mlgetmatrix(mlengine, name,M);
|
|
return M(0,0);
|
|
}
|
|
|
|
// Execute arbitrary MATLAB code and return the MATLAB output
|
|
IGL_INLINE std::string igl::matlab::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).
|
|
struct cleanup {
|
|
Engine *m_ep;
|
|
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::matlab::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<(unsigned)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");
|
|
}
|