dust3d/third_party/libigl/include/igl/matlab/matlabinterface.cpp

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");
}