#ifndef MXPARSE_H #define MXPARSE_H #include "base/libconfig/lib/libconfig.h++" #include #include #include using namespace itpp; using namespace std; using namespace libconfig; //! Class for writing Settings into Matlab's mxArray class UImxArray : public Config { public: //! Build an instance of Config with fields filled from the given \a mxarray UImxArray ( const mxArray *mxarray ) : Config() { Setting & setting = this->getRoot(); //setting is a group if ( !mxIsStruct ( mxarray ) ) { mexErrMsgTxt ( "Given mxArray is not a struct." ); }; //mexCallMATLAB(0, NULL, 1, (mxArray **) &mxarray, "dump"); fillGroup ( setting, mxarray ); setAutoConvert ( true ); } UImxArray() : Config() { setAutoConvert ( true ); } //! Add libconfig's \c list to the structure void addList ( const mxArray *mxarray, const char* name ) { Setting & setting = this->getRoot(); //setting is a group Setting & child = setting.add ( name, Setting::TypeList ); fillList ( child, mxarray ); } //! Add libconfig's \c group to the structure void addGroup ( const mxArray *mxarray, const char* name ) { Setting & setting = this->getRoot(); //setting is a group Setting & child = setting.add ( name, Setting::TypeGroup ); fillGroup ( child, mxarray ); } //! Operator for more convenient access to this Config operator Setting&() { return getRoot(); } private: void storeNumeric ( Setting &setting, const mxArray *value, string key = "" ) { //TODO: integer matrices if ( !mxIsNumeric ( value ) ) { mexErrMsgTxt ( "Given mxArray is not numeric." ); }; //treat empty matrices independently mat val; if ( mxGetM ( value ) > 0 && mxGetN(value)>0) { val = mxArray2mat ( value ); } if ( ( val.rows() == 1 ) && ( val.cols() == 1 ) ) { Setting &child = ( key == "" ) ? setting.add ( Setting::TypeFloat ) : setting.add ( key, Setting::TypeFloat ); child = val ( 0, 0 ); } else { Setting &child = ( key == "" ) ? setting.add ( Setting::TypeList ) : setting.add ( key, Setting::TypeList ); Setting &label = child.add ( Setting::TypeString ); label = "matrix"; Setting &rows = child.add ( Setting::TypeInt ); Setting &cols = child.add ( Setting::TypeInt ); Setting &elements = child.add ( Setting::TypeArray ); cols = val.cols(); rows = val.rows(); for ( int i = 0; i < val.rows(); i++ ) { for ( int j = 0; j < val.cols(); j++ ) { Setting &el = elements.add ( Setting::TypeFloat ); el = val ( i, j ); } } } } void fillGroup ( Setting &setting, const mxArray *mxarray ) { if ( !mxIsStruct ( mxarray ) ) { mexErrMsgTxt ( "Given mxArray is not a struct." ); }; for ( int i = 0; i < mxGetNumberOfFields ( mxarray ); i++ ) { const char *key = mxGetFieldNameByNumber ( mxarray, i ); mxArray *value = mxGetField ( mxarray, 0, key ); if ( mxIsChar ( value ) ) { Setting &child = setting.add ( key, Setting::TypeString ); child = mxArray2string ( value ); } if ( mxIsLogical ( value ) ) { Setting &child = setting.add ( key, Setting::TypeBoolean ); child = ( bool ) mxArray2bin ( value ); } if ( mxIsStruct ( value ) ) { Setting &child = setting.add ( key, Setting::TypeGroup ); fillGroup ( child, value ); } if ( mxIsCell ( value ) ) { Setting &child = setting.add ( key, Setting::TypeList ); fillList ( child, value ); } if ( mxIsNumeric ( value ) ) { storeNumeric ( setting, value, ( string ) key ); } if (mxIsObject(value)){ Setting &child = setting.add(key, Setting::TypeInt64); child = (long)value; } } } void fillList ( Setting &setting, const mxArray *mxarray ) { if ( !mxIsCell ( mxarray ) ) { mexErrMsgTxt ( "Given mxArray is not a cell." ); }; for ( unsigned int i = 0; i < ( unsigned int ) mxGetNumberOfElements ( mxarray ); i++ ) { mxArray *value = mxGetCell ( mxarray, i ); if ( mxIsChar ( value ) ) { Setting &child = setting.add ( Setting::TypeString ); child = mxArray2string ( value ); } if ( mxIsLogical ( value ) ) { Setting &child = setting.add ( Setting::TypeBoolean ); child = ( bool ) mxArray2bin ( value ); } if ( mxIsStruct ( value ) ) { Setting &child = setting.add ( Setting::TypeGroup ); fillGroup ( child, value ); } if ( mxIsCell ( value ) ) { Setting &child = setting.add ( Setting::TypeList ); fillList ( child, value ); } if ( mxIsNumeric ( value ) ) { storeNumeric ( setting, value ); } } } public: //! Convert existing Setting to Matlab arrays static mxArray * create_mxArray( const Setting &setting ) { return group2mxstruct ( setting ); } //! Convert existing Setting to Matlab arrays mxArray * create_mxArray( ) { return group2mxstruct ( *this ); } private: //! Convert libconfig's array to Matlab vector static mxArray* array2mxvector ( const Setting &setting ) { if ( !setting.isArray() ) mexErrMsgTxt ( "Given setting is not an array" ); mxArray *result = mxCreateDoubleMatrix ( 1, setting.getLength(), mxREAL ); double *elements = mxGetPr ( result ); for ( int i = 0; i < setting.getLength(); i++ ) { if ( setting.getType() == Setting::TypeInt ) { //TODO: tady je chyba -- zaporna cisla nejsou TypeInt elements[i] = ( int ) setting[i]; } else { elements[i] = setting[i]; } } return result; } //! Convert libconfig's array to Matlab matrix static mxArray* list2mxmatrix ( const Setting &setting ) { if ( !setting.isList() || ( strcmp ( "matrix", setting[0] ) != 0 ) ) mexErrMsgTxt ( "Given setting is not a matrix" ); int rows = setting[1]; int cols = setting[2]; if ( setting[3].getLength() != rows*cols ) mexErrMsgTxt ( "Matrix elements do not fit to rows*cols" ); double *elements = new double[rows*cols]; for ( int i = 0; i < rows*cols; i++ ) { elements[i] = setting[3][i]; } mat &m = * ( new mat ( elements, rows, cols ) ); mxArray *result = mxCreateDoubleMatrix ( rows, cols, mxREAL ); mat2mxArray ( m, result ); delete &m; delete [] elements; return result; } //! Convert libconfig's gourp to Matlab structure static mxArray* group2mxstruct ( const Setting &setting ) { if ( !setting.isGroup() ) mexErrMsgTxt ( "Given setting is not a group." ); const char ** keys = new const char*[setting.getLength() ]; for ( int i = 0; i < setting.getLength(); i++ ) { keys[i] = setting[i].getName(); } mxArray *result = mxCreateStructMatrix ( 1, 1, setting.getLength(), keys ); delete keys; for ( int i = 0; i < setting.getLength(); i++ ) { Setting &value = setting[i]; mxArray *old = mxGetFieldByNumber ( result, 0, i ); if ( old ) mxDestroyArray ( old ); switch ( value.getType() ) { case Setting::TypeString: mxSetFieldByNumber ( result, 0, i, mxCreateString ( value ) ); break; case Setting::TypeBoolean: mxSetFieldByNumber ( result, 0, i, mxCreateLogicalScalar ( value ) ); break; case Setting::TypeGroup: mxSetFieldByNumber ( result, 0, i, group2mxstruct ( value ) ); break; case Setting::TypeList: mxSetFieldByNumber ( result, 0, i, list2mxcell ( value ) ); break; case Setting::TypeArray: mxSetFieldByNumber ( result, 0, i, array2mxvector ( value ) ); break; case Setting::TypeInt: case Setting::TypeInt64: mxSetFieldByNumber ( result, 0, i, mxCreateDoubleScalar ( ( int ) value ) ); break; case Setting::TypeFloat: mxSetFieldByNumber ( result, 0, i, mxCreateDoubleScalar ( value ) ); break; default: //this should never happen mexErrMsgTxt ( "Unknown type of a setting." ); } } return result; } //! Convert libconfig's list to Matlab cell static mxArray* list2mxcell ( const Setting &setting ) { if ( !setting.isList() ) mexErrMsgTxt ( "Given setting is not a list." ); if ( setting.getLength() == 0 ) { mxArray *result = mxCreateCellMatrix ( 1, 0 ); return result; } if ( ( setting[0].getType() == Setting::TypeString ) ) { string s = ( setting[0] ); if ( s == "matrix" ) { return list2mxmatrix ( setting ); } } mxArray *result = mxCreateCellMatrix ( 1, setting.getLength() ); for ( int i = 0; i < setting.getLength(); i++ ) { Setting &value = setting[i]; mxArray *old = mxGetCell ( result, i ); if ( old ) mxDestroyArray ( old ); switch ( value.getType() ) { case Setting::TypeString: mxSetCell ( result, i, mxCreateString ( value ) ); break; case Setting::TypeBoolean: mxSetCell ( result, i, mxCreateLogicalScalar ( value ) ); break; case Setting::TypeGroup: mxSetCell ( result, i, group2mxstruct ( value ) ); break; case Setting::TypeList: mxSetCell ( result, i, list2mxcell ( value ) ); break; case Setting::TypeArray: mxSetCell ( result, i, array2mxvector ( value ) ); break; case Setting::TypeInt: case Setting::TypeInt64: mxSetCell ( result, i, mxCreateDoubleScalar ( ( int ) value ) ); break; case Setting::TypeFloat: mxSetCell ( result, i, mxCreateDoubleScalar ( value ) ); break; default: //this should never happen mexErrMsgTxt ( "Unknown type of a setting." ); } } return result; } }; #endif //MXPARSE_H