mirror of
https://github.com/QIDITECH/QIDISlicer.git
synced 2026-02-05 10:21:52 +03:00
update bundled_deps
This commit is contained in:
579
bundled_deps/libigl/igl/matlab/MatlabWorkspace.h
Normal file
579
bundled_deps/libigl/igl/matlab/MatlabWorkspace.h
Normal file
@@ -0,0 +1,579 @@
|
||||
// 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/.
|
||||
#ifndef IGL_MATLAB_MATLAB_WORKSPACE_H
|
||||
#define IGL_MATLAB_MATLAB_WORKSPACE_H
|
||||
|
||||
#include <Eigen/Dense>
|
||||
#include <Eigen/Sparse>
|
||||
|
||||
#include <mat.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace matlab
|
||||
{
|
||||
// It would be really great to replicate this for a simple XML-based
|
||||
// workspace.
|
||||
//
|
||||
// Class which contains data of a matlab workspace which can be written to a
|
||||
// .mat file and loaded from matlab
|
||||
//
|
||||
// This depends on matlab at compile time (though it shouldn't necessarily
|
||||
// have to) but it does not depend on running the matlab engine at run-time.
|
||||
//
|
||||
// Known bugs: Treats all matrices as doubles (this may actually be desired
|
||||
// for some "index" matrices since matlab's sparse command takes doubles
|
||||
// rather than int class matrices). It is of course not desired when dealing
|
||||
// with logicals or uint's for images.
|
||||
class MatlabWorkspace
|
||||
{
|
||||
private:
|
||||
// KNOWN BUG: Why not use a map? Any reason to allow duplicate names?
|
||||
//
|
||||
// List of names
|
||||
std::vector<std::string> names;
|
||||
// List of data pointers
|
||||
std::vector<mxArray*> data;
|
||||
public:
|
||||
MatlabWorkspace();
|
||||
~MatlabWorkspace();
|
||||
// Clear names and data of variables in workspace
|
||||
inline void clear();
|
||||
// Save current list of variables
|
||||
//
|
||||
// Inputs:
|
||||
// path path to .mat file
|
||||
// Returns true on success, false on failure
|
||||
inline bool write(const std::string & path) const;
|
||||
// Load list of variables from .mat file
|
||||
//
|
||||
// Inputs:
|
||||
// path path to .mat file
|
||||
// Returns true on success, false on failure
|
||||
inline bool read(const std::string & path);
|
||||
// Assign data to a variable name in the workspace
|
||||
//
|
||||
// Template:
|
||||
// DerivedM eigen matrix (e.g. MatrixXd)
|
||||
// Inputs:
|
||||
// M data (usually a matrix)
|
||||
// name variable name to save into work space
|
||||
// Returns true on success, false on failure
|
||||
//
|
||||
// Known Bugs: Assumes Eigen is using column major ordering
|
||||
template <typename DerivedM>
|
||||
inline MatlabWorkspace& save(
|
||||
const Eigen::PlainObjectBase<DerivedM>& M,
|
||||
const std::string & name);
|
||||
// Template:
|
||||
// MT sparse matrix type (e.g. double)
|
||||
template <typename MT>
|
||||
inline MatlabWorkspace& save(
|
||||
const Eigen::SparseMatrix<MT>& M,
|
||||
const std::string & name);
|
||||
// Templates:
|
||||
// ScalarM scalar type, e.g. double
|
||||
template <typename ScalarM>
|
||||
inline MatlabWorkspace& save(
|
||||
const std::vector<std::vector<ScalarM> > & vM,
|
||||
const std::string & name);
|
||||
// Templates:
|
||||
// ScalarV scalar type, e.g. double
|
||||
template <typename ScalarV>
|
||||
inline MatlabWorkspace& save(
|
||||
const std::vector<ScalarV> & vV,
|
||||
const std::string & name);
|
||||
// NOTE: Eigen stores quaternions coefficients as (i,j,k,1), but most of
|
||||
// our matlab code stores them as (1,i,j,k) This takes a quaternion and
|
||||
// saves it as a (1,i,j,k) row vector
|
||||
//
|
||||
// Templates:
|
||||
// Q quaternion type
|
||||
template <typename Q>
|
||||
inline MatlabWorkspace& save(
|
||||
const Eigen::Quaternion<Q> & q,
|
||||
const std::string & name);
|
||||
inline MatlabWorkspace& save(
|
||||
const double d,
|
||||
const std::string & name);
|
||||
// Same as save() but adds 1 to each element, useful for saving "index"
|
||||
// matrices like lists of faces or elements
|
||||
template <typename DerivedM>
|
||||
inline MatlabWorkspace& save_index(
|
||||
const Eigen::DenseBase<DerivedM>& M,
|
||||
const std::string & name);
|
||||
template <typename ScalarM>
|
||||
inline MatlabWorkspace& save_index(
|
||||
const std::vector<std::vector<ScalarM> > & vM,
|
||||
const std::string & name);
|
||||
template <typename ScalarV>
|
||||
inline MatlabWorkspace& save_index(
|
||||
const std::vector<ScalarV> & vV,
|
||||
const std::string & name);
|
||||
// Find a certain matrix by name.
|
||||
//
|
||||
// KNOWN BUG: Outputs the first found (not necessarily unique lists).
|
||||
//
|
||||
// Template:
|
||||
// DerivedM eigen matrix (e.g. MatrixXd)
|
||||
// Inputs:
|
||||
// name exact name of matrix as string
|
||||
// Outputs:
|
||||
// M matrix
|
||||
// Returns true only if found.
|
||||
template <typename DerivedM>
|
||||
inline bool find(
|
||||
const std::string & name,
|
||||
Eigen::PlainObjectBase<DerivedM>& M);
|
||||
template <typename MT>
|
||||
inline bool find(
|
||||
const std::string & name,
|
||||
Eigen::SparseMatrix<MT>& M);
|
||||
inline bool find(
|
||||
const std::string & name,
|
||||
double & d);
|
||||
inline bool find(
|
||||
const std::string & name,
|
||||
int & v);
|
||||
// Subtracts 1 from all entries
|
||||
template <typename DerivedM>
|
||||
inline bool find_index(
|
||||
const std::string & name,
|
||||
Eigen::PlainObjectBase<DerivedM>& M);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Implementation
|
||||
|
||||
// Be sure that this is not compiled into libigl.a
|
||||
// http://stackoverflow.com/a/3318993/148668
|
||||
|
||||
// IGL
|
||||
#include "igl/list_to_matrix.h"
|
||||
|
||||
// MATLAB
|
||||
#include "mat.h"
|
||||
|
||||
// STL
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
inline igl::matlab::MatlabWorkspace::MatlabWorkspace():
|
||||
names(),
|
||||
data()
|
||||
{
|
||||
}
|
||||
|
||||
inline igl::matlab::MatlabWorkspace::~MatlabWorkspace()
|
||||
{
|
||||
// clean up data
|
||||
clear();
|
||||
}
|
||||
|
||||
inline void igl::matlab::MatlabWorkspace::clear()
|
||||
{
|
||||
for_each(data.begin(),data.end(),&mxDestroyArray);
|
||||
data.clear();
|
||||
names.clear();
|
||||
}
|
||||
|
||||
inline bool igl::matlab::MatlabWorkspace::write(const std::string & path) const
|
||||
{
|
||||
using namespace std;
|
||||
MATFile * mat_file = matOpen(path.c_str(), "w");
|
||||
if(mat_file == NULL)
|
||||
{
|
||||
fprintf(stderr,"Error opening file %s\n",path.c_str());
|
||||
return false;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
inline bool igl::matlab::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>
|
||||
inline igl::matlab::MatlabWorkspace& igl::matlab::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
|
||||
// Use Eigen's map and cast to copy
|
||||
Eigen::Map< Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic> >
|
||||
map(mxGetPr(mx_data),m,n);
|
||||
map = M.template cast<double>();
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Treat everything as a double
|
||||
template <typename MT>
|
||||
inline igl::matlab::MatlabWorkspace& igl::matlab::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>
|
||||
inline igl::matlab::MatlabWorkspace& igl::matlab::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>
|
||||
inline igl::matlab::MatlabWorkspace& igl::matlab::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 Q>
|
||||
inline igl::matlab::MatlabWorkspace& igl::matlab::MatlabWorkspace::save(
|
||||
const Eigen::Quaternion<Q> & q,
|
||||
const std::string & name)
|
||||
{
|
||||
Eigen::Matrix<Q,1,4> qm;
|
||||
qm(0,0) = q.w();
|
||||
qm(0,1) = q.x();
|
||||
qm(0,2) = q.y();
|
||||
qm(0,3) = q.z();
|
||||
return save(qm,name);
|
||||
}
|
||||
|
||||
inline igl::matlab::MatlabWorkspace& igl::matlab::MatlabWorkspace::save(
|
||||
const double d,
|
||||
const std::string & name)
|
||||
{
|
||||
Eigen::VectorXd v(1);
|
||||
v(0) = d;
|
||||
return save(v,name);
|
||||
}
|
||||
|
||||
template <typename DerivedM>
|
||||
inline igl::matlab::MatlabWorkspace&
|
||||
igl::matlab::MatlabWorkspace::save_index(
|
||||
const Eigen::DenseBase<DerivedM>& M,
|
||||
const std::string & name)
|
||||
{
|
||||
DerivedM Mp1 = M;
|
||||
Mp1.array() += 1;
|
||||
return this->save(Mp1,name);
|
||||
}
|
||||
|
||||
template <typename ScalarM>
|
||||
inline igl::matlab::MatlabWorkspace& igl::matlab::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>
|
||||
inline igl::matlab::MatlabWorkspace& igl::matlab::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>
|
||||
inline bool igl::matlab::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: in the sense that anything found becomes a column vector,
|
||||
// whether it was column vector, row vector or matrix
|
||||
if(DerivedM::IsVectorAtCompileTime)
|
||||
{
|
||||
assert(m==1 || n==1 || (m==0 && n==0));
|
||||
M.resize(m*n,1);
|
||||
}else
|
||||
{
|
||||
M.resize(m,n);
|
||||
}
|
||||
assert(mxGetNumberOfElements(mx_data) == M.size());
|
||||
// Use Eigen's map and cast to copy
|
||||
M = Eigen::Map< Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic> >
|
||||
(mxGetPr(mx_data),M.rows(),M.cols()).cast<typename DerivedM::Scalar>();
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename MT>
|
||||
inline bool igl::matlab::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);
|
||||
// TODO: It should be possible to directly load the data into the sparse
|
||||
// matrix without going through the triplets
|
||||
// Copy data immediately
|
||||
double * pr = mxGetPr(mx_data);
|
||||
mwIndex * ir = mxGetIr(mx_data);
|
||||
mwIndex * jc = mxGetJc(mx_data);
|
||||
vector<Triplet<MT> > MIJV;
|
||||
const int nnz = mxGetNzmax(mx_data);
|
||||
MIJV.reserve(nnz);
|
||||
// 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;
|
||||
}
|
||||
|
||||
inline bool igl::matlab::MatlabWorkspace::find(
|
||||
const std::string & name,
|
||||
int & v)
|
||||
{
|
||||
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;
|
||||
assert(mxGetNumberOfElements(mx_data) == 1);
|
||||
copy(
|
||||
mxGetPr(mx_data),
|
||||
mxGetPr(mx_data)+mxGetNumberOfElements(mx_data),
|
||||
&v);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool igl::matlab::MatlabWorkspace::find(
|
||||
const std::string & name,
|
||||
double & d)
|
||||
{
|
||||
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;
|
||||
assert(mxGetNumberOfElements(mx_data) == 1);
|
||||
copy(
|
||||
mxGetPr(mx_data),
|
||||
mxGetPr(mx_data)+mxGetNumberOfElements(mx_data),
|
||||
&d);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename DerivedM>
|
||||
inline bool igl::matlab::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::matlab::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
|
||||
|
||||
Reference in New Issue
Block a user