/* ----------------------------------------------------------------------- Copyright: 2010-2021, imec Vision Lab, University of Antwerp 2014-2021, CWI, Amsterdam Contact: astra@astra-toolbox.com Website: http://www.astra-toolbox.com/ This file is part of the ASTRA Toolbox. The ASTRA Toolbox is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. The ASTRA Toolbox is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the ASTRA Toolbox. If not, see . ----------------------------------------------------------------------- */ /** \file mexHelpFunctions.cpp * * \brief Contains some functions for interfacing matlab with c data structures */ #include "mexHelpFunctions.h" #include "astra/Utilities.h" using namespace std; using namespace astra; //----------------------------------------------------------------------------------------- // get string from matlab string mexToString(const mxArray* pInput) { // is string? if (mxIsChar(pInput)) { mwSize iLength = mxGetNumberOfElements(pInput) + 1; char* buf = new char[iLength]; mxGetString(pInput, buf, iLength); std::string res = std::string(buf); delete[] buf; return res; } // is scalar? if (mxIsNumeric(pInput) && mxGetM(pInput)*mxGetN(pInput) == 1) { return StringUtil::doubleToString(mxGetScalar(pInput)); } return ""; } //----------------------------------------------------------------------------------------- // return true if the argument is a scalar bool mexIsScalar(const mxArray* pInput) { return (mxIsNumeric(pInput) && mxGetM(pInput)*mxGetN(pInput) == 1); } //----------------------------------------------------------------------------------------- void get3DMatrixDims(const mxArray* x, mwSize *dims) { const mwSize* mdims = mxGetDimensions(x); mwSize dimCount = mxGetNumberOfDimensions(x); if (dimCount == 1) { dims[0] = mdims[0]; dims[1] = 1; dims[2] = 1; } else if (dimCount == 2) { dims[0] = mdims[0]; dims[1] = mdims[1]; dims[2] = 1; } else if (dimCount == 3) { dims[0] = mdims[0]; dims[1] = mdims[1]; dims[2] = mdims[2]; } else { dims[0] = 0; dims[1] = 0; dims[2] = 0; } } //----------------------------------------------------------------------------------------- // turn an std vector object to an mxArray mxArray* vectorToMxArray(std::vector mInput) { mxArray* res = mxCreateDoubleMatrix(1, mInput.size(), mxREAL); double* pdData = mxGetPr(res); for (unsigned int i = 0; i < mInput.size(); i++) { pdData[i] = mInput[i]; } return res; } //----------------------------------------------------------------------------------------- // turn a vector> object to an mxArray mxArray* vector2DToMxArray(std::vector > mInput) { unsigned int sizex = mInput.size(); if (sizex == 0) return mxCreateString("empty"); unsigned int sizey = mInput[0].size(); mxArray* res = mxCreateDoubleMatrix(sizex, sizey, mxREAL); double* pdData = mxGetPr(res); for (unsigned int i = 0; i < sizex; i++) { for (unsigned int j = 0; j < sizey && j < mInput[i].size(); j++) { pdData[j*sizex+i] = mInput[i][j]; } } return res; } //----------------------------------------------------------------------------------------- // turn a boost::any object to an mxArray mxArray* anyToMxArray(boost::any _any) { if (_any.type() == typeid(std::string)) { std::string str = boost::any_cast(_any); return mxCreateString(str.c_str()); } if (_any.type() == typeid(int)) { return mxCreateDoubleScalar(boost::any_cast(_any)); } if (_any.type() == typeid(float32)) { return mxCreateDoubleScalar(boost::any_cast(_any)); } if (_any.type() == typeid(std::vector)) { return vectorToMxArray(boost::any_cast >(_any)); } if (_any.type() == typeid(std::vector >)) { return vector2DToMxArray(boost::any_cast > >(_any)); } return NULL; } //----------------------------------------------------------------------------------------- // turn a MATLAB struct into a Config object Config* structToConfig(string rootname, const mxArray* pStruct) { if (!mxIsStruct(pStruct)) { mexErrMsgTxt("Input must be a struct."); return NULL; } // create the document Config* cfg = new Config(); cfg->initialize(rootname); // read the struct bool ret = structToXMLNode(cfg->self, pStruct); if (!ret) { delete cfg; mexErrMsgTxt("Error parsing struct."); return NULL; } return cfg; } //----------------------------------------------------------------------------------------- bool structToXMLNode(XMLNode node, const mxArray* pStruct) { // loop all fields int nfields = mxGetNumberOfFields(pStruct); for (int i = 0; i < nfields; i++) { // field and fieldname std::string sFieldName = std::string(mxGetFieldNameByNumber(pStruct, i)); const mxArray* pField = mxGetFieldByNumber(pStruct, 0, i); // string if (mxIsChar(pField)) { string sValue = mexToString(pField); if (sFieldName == "type") { node.addAttribute("type", sValue); } else { node.addChildNode(sFieldName, sValue); } } // scalar else if (mxIsNumeric(pField) && mxGetM(pField)*mxGetN(pField) == 1) { string sValue = mexToString(pField); node.addChildNode(sFieldName, sValue); } // numerical array else if (mxIsNumeric(pField) && mxGetM(pField)*mxGetN(pField) > 1) { if (!mxIsDouble(pField)) { mexErrMsgTxt("Numeric input must be double."); return false; } XMLNode listbase = node.addChildNode(sFieldName); double* pdValues = mxGetPr(pField); listbase.setContent(pdValues, mxGetN(pField), mxGetM(pField), true); } // not castable to a single string else if (mxIsStruct(pField)) { if (sFieldName == "options" || sFieldName == "option" || sFieldName == "Options" || sFieldName == "Option") { bool ret = optionsToXMLNode(node, pField); if (!ret) return false; } else { XMLNode newNode = node.addChildNode(sFieldName); bool ret = structToXMLNode(newNode, pField); if (!ret) return false; } } } return true; } //----------------------------------------------------------------------------------------- // Options struct to xml node bool optionsToXMLNode(XMLNode node, const mxArray* pOptionStruct) { // loop all fields int nfields = mxGetNumberOfFields(pOptionStruct); for (int i = 0; i < nfields; i++) { std::string sFieldName = std::string(mxGetFieldNameByNumber(pOptionStruct, i)); const mxArray* pField = mxGetFieldByNumber(pOptionStruct, 0, i); if (node.hasOption(sFieldName)) { mexErrMsgTxt("Duplicate option"); return false; } // string or scalar if (mxIsChar(pField) || mexIsScalar(pField)) { string sValue = mexToString(pField); node.addOption(sFieldName, sValue); } // numerical array else if (mxIsNumeric(pField) && mxGetM(pField)*mxGetN(pField) > 1) { if (!mxIsDouble(pField)) { mexErrMsgTxt("Numeric input must be double."); return false; } XMLNode listbase = node.addChildNode("Option"); listbase.addAttribute("key", sFieldName); double* pdValues = mxGetPr(pField); listbase.setContent(pdValues, mxGetN(pField), mxGetM(pField), true); } else { mexErrMsgTxt("Unsupported option type"); return false; } } return true; } //----------------------------------------------------------------------------------------- // turn a matlab struct into a c++ map std::map parseStruct(const mxArray* pInput) { std::map res; // check type if (!mxIsStruct(pInput)) { mexErrMsgTxt("Input must be a struct."); return res; } // get field names int nfields = mxGetNumberOfFields(pInput); for (int i = 0; i < nfields; i++) { std::string sFieldName = std::string(mxGetFieldNameByNumber(pInput, i)); res[sFieldName] = mxGetFieldByNumber(pInput,0,i); } return res; } //----------------------------------------------------------------------------------------- // turn a Config object into a MATLAB struct mxArray* configToStruct(astra::Config* cfg) { return XMLNodeToStruct(cfg->self); } //----------------------------------------------------------------------------------------- mxArray* XMLNodeToStruct(astra::XMLNode node) { std::map mList; std::map mOptions; // type_attribute if (node.hasAttribute("type")) { mList["type"] = mxCreateString(node.getAttribute("type").c_str()); } list nodes = node.getNodes(); for (list::iterator it = nodes.begin(); it != nodes.end(); it++) { XMLNode subnode = (*it); // option if (subnode.getName() == "Option") { if(subnode.hasAttribute("value")){ mOptions[subnode.getAttribute("key")] = stringToMxArray(subnode.getAttribute("value")); }else{ mOptions[subnode.getAttribute("key")] = stringToMxArray(subnode.getContent()); } } // regular content else { mList[subnode.getName()] = stringToMxArray(subnode.getContent()); } } if (mOptions.size() > 0) mList["options"] = buildStruct(mOptions); return buildStruct(mList); } //----------------------------------------------------------------------------------------- mxArray* stringToMxArray(std::string input) { // matrix if (input.find(';') != std::string::npos) { // split rows std::vector row_strings; std::vector col_strings; StringUtil::splitString(row_strings, input, ";"); StringUtil::splitString(col_strings, row_strings[0], ","); // get dimensions size_t rows = row_strings.size(); size_t cols = col_strings.size(); // init matrix mxArray* pMatrix = mxCreateDoubleMatrix(rows, cols, mxREAL); double* out = mxGetPr(pMatrix); // loop elements for (size_t row = 0; row < rows; row++) { StringUtil::splitString(col_strings, row_strings[row], ","); // check size for (size_t col = 0; col < col_strings.size(); col++) { out[col*rows + row] = StringUtil::stringToFloat(col_strings[col]); } } return pMatrix; } // vector if (input.find(',') != std::string::npos) { // split std::vector items; StringUtil::splitString(items, input, ","); // init matrix mxArray* pVector = mxCreateDoubleMatrix(1, items.size(), mxREAL); double* out = mxGetPr(pVector); // loop elements for (size_t i = 0; i < items.size(); i++) { out[i] = StringUtil::stringToFloat(items[i]); } return pVector; } try { // number return mxCreateDoubleScalar(StringUtil::stringToDouble(input)); } catch (const StringUtil::bad_cast &) { // string return mxCreateString(input.c_str()); } } //----------------------------------------------------------------------------------------- // turn a c++ map into a matlab struct mxArray* buildStruct(std::map mInput) { mwSize dims[2] = {1, 1}; mxArray* res = mxCreateStructArray(2,dims,0,0); for (std::map::iterator it = mInput.begin(); it != mInput.end(); it++) { mxAddField(res, (*it).first.c_str()); mxSetField(res, 0, (*it).first.c_str(), (*it).second); } return res; }