matlab.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495
  1. /* ----------------------------------------------------------------------------
  2. * GTSAM Copyright 2010, Georgia Tech Research Corporation,
  3. * Atlanta, Georgia 30332-0415
  4. * All Rights Reserved
  5. * Authors: Frank Dellaert, et al. (see THANKS for the full author list)
  6. * See LICENSE for the license information
  7. * -------------------------------------------------------------------------- */
  8. /**
  9. * @file matlab.h
  10. * @brief header file to be included in MATLAB wrappers
  11. * @date 2008
  12. * @author Frank Dellaert
  13. * @author Alex Cunningham
  14. * @author Andrew Melim
  15. * @author Richard Roberts
  16. *
  17. * wrapping and unwrapping is done using specialized templates, see
  18. * http://www.cplusplus.com/doc/tutorial/templates.html
  19. */
  20. #include <gtsam/base/Vector.h>
  21. #include <gtsam/base/Matrix.h>
  22. #include <gtsam/geometry/Point2.h>
  23. #include <gtsam/geometry/Point3.h>
  24. #include <gtsam/base/utilities.h>
  25. using gtsam::Vector;
  26. using gtsam::Matrix;
  27. using gtsam::Point2;
  28. using gtsam::Point3;
  29. extern "C" {
  30. #include <mex.h>
  31. }
  32. #include <boost/shared_ptr.hpp>
  33. #include <boost/make_shared.hpp>
  34. #include <list>
  35. #include <string>
  36. #include <sstream>
  37. #include <typeinfo>
  38. #include <set>
  39. #include <streambuf>
  40. using namespace std;
  41. using namespace boost; // not usual, but for conciseness of generated code
  42. // start GTSAM Specifics /////////////////////////////////////////////////
  43. // to enable Matrix and Vector constructor for SharedGaussian:
  44. #define GTSAM_MAGIC_GAUSSIAN
  45. // end GTSAM Specifics /////////////////////////////////////////////////
  46. #if defined(__LP64__) || defined(_WIN64)
  47. // 64-bit
  48. #define mxUINT32OR64_CLASS mxUINT64_CLASS
  49. #else
  50. #define mxUINT32OR64_CLASS mxUINT32_CLASS
  51. #endif
  52. // "Unique" key to signal calling the matlab object constructor with a raw pointer
  53. // to a shared pointer of the same C++ object type as the MATLAB type.
  54. // Also present in utilities.h
  55. static const boost::uint64_t ptr_constructor_key =
  56. (boost::uint64_t('G') << 56) |
  57. (boost::uint64_t('T') << 48) |
  58. (boost::uint64_t('S') << 40) |
  59. (boost::uint64_t('A') << 32) |
  60. (boost::uint64_t('M') << 24) |
  61. (boost::uint64_t('p') << 16) |
  62. (boost::uint64_t('t') << 8) |
  63. (boost::uint64_t('r'));
  64. //*****************************************************************************
  65. // Utilities
  66. //*****************************************************************************
  67. void error(const char* str) {
  68. mexErrMsgIdAndTxt("wrap:error", str);
  69. }
  70. mxArray *scalar(mxClassID classid) {
  71. mwSize dims[1]; dims[0]=1;
  72. return mxCreateNumericArray(1, dims, classid, mxREAL);
  73. }
  74. void checkScalar(const mxArray* array, const char* str) {
  75. int m = mxGetM(array), n = mxGetN(array);
  76. if (m!=1 || n!=1)
  77. mexErrMsgIdAndTxt("wrap: not a scalar in ", str);
  78. }
  79. // Replacement streambuf for cout that writes to the MATLAB console
  80. // Thanks to http://stackoverflow.com/a/249008
  81. class mstream : public std::streambuf {
  82. protected:
  83. virtual std::streamsize xsputn(const char *s, std::streamsize n) {
  84. mexPrintf("%.*s",n,s);
  85. return n;
  86. }
  87. virtual int overflow(int c = EOF) {
  88. if (c != EOF) {
  89. mexPrintf("%.1s",&c);
  90. }
  91. return 1;
  92. }
  93. };
  94. //*****************************************************************************
  95. // Check arguments
  96. //*****************************************************************************
  97. void checkArguments(const string& name, int nargout, int nargin, int expected) {
  98. stringstream err;
  99. err << name << " expects " << expected << " arguments, not " << nargin;
  100. if (nargin!=expected)
  101. error(err.str().c_str());
  102. }
  103. //*****************************************************************************
  104. // wrapping C++ basis types in MATLAB arrays
  105. //*****************************************************************************
  106. // default wrapping throws an error: only basis types are allowed in wrap
  107. template <typename Class>
  108. mxArray* wrap(const Class& value) {
  109. error("wrap internal error: attempted wrap of invalid type");
  110. return 0;
  111. }
  112. // specialization to string
  113. // wraps into a character array
  114. template<>
  115. mxArray* wrap<string>(const string& value) {
  116. return mxCreateString(value.c_str());
  117. }
  118. // specialization to char
  119. template<>
  120. mxArray* wrap<char>(const char& value) {
  121. mxArray *result = scalar(mxUINT32OR64_CLASS);
  122. *(char*)mxGetData(result) = value;
  123. return result;
  124. }
  125. // specialization to unsigned char
  126. template<>
  127. mxArray* wrap<unsigned char>(const unsigned char& value) {
  128. mxArray *result = scalar(mxUINT32OR64_CLASS);
  129. *(unsigned char*)mxGetData(result) = value;
  130. return result;
  131. }
  132. // specialization to bool
  133. template<>
  134. mxArray* wrap<bool>(const bool& value) {
  135. mxArray *result = scalar(mxUINT32OR64_CLASS);
  136. *(bool*)mxGetData(result) = value;
  137. return result;
  138. }
  139. // specialization to size_t
  140. template<>
  141. mxArray* wrap<size_t>(const size_t& value) {
  142. mxArray *result = scalar(mxUINT32OR64_CLASS);
  143. *(size_t*)mxGetData(result) = value;
  144. return result;
  145. }
  146. // specialization to int
  147. template<>
  148. mxArray* wrap<int>(const int& value) {
  149. mxArray *result = scalar(mxUINT32OR64_CLASS);
  150. *(int*)mxGetData(result) = value;
  151. return result;
  152. }
  153. // specialization to double -> just double
  154. template<>
  155. mxArray* wrap<double>(const double& value) {
  156. return mxCreateDoubleScalar(value);
  157. }
  158. // wrap a const Eigen vector into a double vector
  159. mxArray* wrap_Vector(const gtsam::Vector& v) {
  160. int m = v.size();
  161. mxArray *result = mxCreateDoubleMatrix(m, 1, mxREAL);
  162. double *data = mxGetPr(result);
  163. for (int i=0;i<m;i++) data[i]=v(i);
  164. return result;
  165. }
  166. // specialization to Eigen vector -> double vector
  167. template<>
  168. mxArray* wrap<gtsam::Vector >(const gtsam::Vector& v) {
  169. return wrap_Vector(v);
  170. }
  171. // specialization to Eigen vector -> double vector
  172. template<>
  173. mxArray* wrap<gtsam::Point2 >(const gtsam::Point2& v) {
  174. return wrap_Vector(v);
  175. }
  176. // specialization to Eigen vector -> double vector
  177. template<>
  178. mxArray* wrap<gtsam::Point3 >(const gtsam::Point3& v) {
  179. return wrap_Vector(v);
  180. }
  181. // wrap a const Eigen MATRIX into a double matrix
  182. mxArray* wrap_Matrix(const gtsam::Matrix& A) {
  183. int m = A.rows(), n = A.cols();
  184. #ifdef DEBUG_WRAP
  185. mexPrintf("wrap_Matrix called with A = \n", m,n);
  186. gtsam::print(A);
  187. #endif
  188. mxArray *result = mxCreateDoubleMatrix(m, n, mxREAL);
  189. double *data = mxGetPr(result);
  190. // converts from column-major to row-major
  191. for (int j=0;j<n;j++) for (int i=0;i<m;i++,data++) *data = A(i,j);
  192. return result;
  193. }
  194. // specialization to Eigen MATRIX -> double matrix
  195. template<>
  196. mxArray* wrap<gtsam::Matrix >(const gtsam::Matrix& A) {
  197. return wrap_Matrix(A);
  198. }
  199. //*****************************************************************************
  200. // unwrapping MATLAB arrays into C++ basis types
  201. //*****************************************************************************
  202. // default unwrapping throws an error
  203. // as wrap only supports passing a reference or one of the basic types
  204. template <typename T>
  205. T unwrap(const mxArray* array) {
  206. error("wrap internal error: attempted unwrap of invalid type");
  207. return T();
  208. }
  209. // specialization to string
  210. // expects a character array
  211. // Warning: relies on mxChar==char
  212. template<>
  213. string unwrap<string>(const mxArray* array) {
  214. char *data = mxArrayToString(array);
  215. if (data==NULL) error("unwrap<string>: not a character array");
  216. string str(data);
  217. mxFree(data);
  218. return str;
  219. }
  220. // Check for 64-bit, as Mathworks says mxGetScalar only good for 32 bit
  221. template <typename T>
  222. T myGetScalar(const mxArray* array) {
  223. switch (mxGetClassID(array)) {
  224. case mxINT64_CLASS:
  225. return (T) *(boost::int64_t*) mxGetData(array);
  226. case mxUINT64_CLASS:
  227. return (T) *(boost::uint64_t*) mxGetData(array);
  228. default:
  229. // hope for the best!
  230. return (T) mxGetScalar(array);
  231. }
  232. }
  233. // specialization to bool
  234. template<>
  235. bool unwrap<bool>(const mxArray* array) {
  236. checkScalar(array,"unwrap<bool>");
  237. return myGetScalar<bool>(array);
  238. }
  239. // specialization to char
  240. template<>
  241. char unwrap<char>(const mxArray* array) {
  242. checkScalar(array,"unwrap<char>");
  243. return myGetScalar<char>(array);
  244. }
  245. // specialization to unsigned char
  246. template<>
  247. unsigned char unwrap<unsigned char>(const mxArray* array) {
  248. checkScalar(array,"unwrap<unsigned char>");
  249. return myGetScalar<unsigned char>(array);
  250. }
  251. // specialization to int
  252. template<>
  253. int unwrap<int>(const mxArray* array) {
  254. checkScalar(array,"unwrap<int>");
  255. return myGetScalar<int>(array);
  256. }
  257. // specialization to size_t
  258. template<>
  259. size_t unwrap<size_t>(const mxArray* array) {
  260. checkScalar(array, "unwrap<size_t>");
  261. return myGetScalar<size_t>(array);
  262. }
  263. // specialization to double
  264. template<>
  265. double unwrap<double>(const mxArray* array) {
  266. checkScalar(array,"unwrap<double>");
  267. return myGetScalar<double>(array);
  268. }
  269. // specialization to Eigen vector
  270. template<>
  271. gtsam::Vector unwrap< gtsam::Vector >(const mxArray* array) {
  272. int m = mxGetM(array), n = mxGetN(array);
  273. if (mxIsDouble(array)==false || n!=1) error("unwrap<vector>: not a vector");
  274. #ifdef DEBUG_WRAP
  275. mexPrintf("unwrap< gtsam::Vector > called with %dx%d argument\n", m,n);
  276. #endif
  277. double* data = (double*)mxGetData(array);
  278. gtsam::Vector v(m);
  279. for (int i=0;i<m;i++,data++) v(i) = *data;
  280. #ifdef DEBUG_WRAP
  281. gtsam::print(v);
  282. #endif
  283. return v;
  284. }
  285. // specialization to Point2
  286. template<>
  287. gtsam::Point2 unwrap< gtsam::Point2 >(const mxArray* array) {
  288. int m = mxGetM(array), n = mxGetN(array);
  289. if (mxIsDouble(array)==false || n!=1) error("unwrap<vector>: not a vector");
  290. #ifdef DEBUG_WRAP
  291. mexPrintf("unwrap< gtsam::Vector > called with %dx%d argument\n", m,n);
  292. #endif
  293. double* data = (double*)mxGetData(array);
  294. gtsam::Vector v(m);
  295. for (int i=0;i<m;i++,data++) v(i) = *data;
  296. #ifdef DEBUG_WRAP
  297. gtsam::print(v);
  298. #endif
  299. return v;
  300. }
  301. // specialization to Point3
  302. template<>
  303. gtsam::Point3 unwrap< gtsam::Point3 >(const mxArray* array) {
  304. int m = mxGetM(array), n = mxGetN(array);
  305. if (mxIsDouble(array)==false || n!=1) error("unwrap<vector>: not a vector");
  306. #ifdef DEBUG_WRAP
  307. mexPrintf("unwrap< gtsam::Vector > called with %dx%d argument\n", m,n);
  308. #endif
  309. double* data = (double*)mxGetData(array);
  310. gtsam::Vector v(m);
  311. for (int i=0;i<m;i++,data++) v(i) = *data;
  312. #ifdef DEBUG_WRAP
  313. gtsam::print(v);
  314. #endif
  315. return v;
  316. }
  317. // specialization to Eigen matrix
  318. template<>
  319. gtsam::Matrix unwrap< gtsam::Matrix >(const mxArray* array) {
  320. if (mxIsDouble(array)==false) error("unwrap<matrix>: not a matrix");
  321. int m = mxGetM(array), n = mxGetN(array);
  322. #ifdef DEBUG_WRAP
  323. mexPrintf("unwrap< gtsam::Matrix > called with %dx%d argument\n", m,n);
  324. #endif
  325. double* data = (double*)mxGetData(array);
  326. gtsam::Matrix A(m,n);
  327. // converts from row-major to column-major
  328. for (int j=0;j<n;j++) for (int i=0;i<m;i++,data++) A(i,j) = *data;
  329. #ifdef DEBUG_WRAP
  330. gtsam::print(A);
  331. #endif
  332. return A;
  333. }
  334. /*
  335. [create_object] creates a MATLAB proxy class object with a mexhandle
  336. in the self property. Matlab does not allow the creation of matlab
  337. objects from within mex files, hence we resort to an ugly trick: we
  338. invoke the proxy class constructor by calling MATLAB with a special
  339. uint64 value ptr_constructor_key and the pointer itself. MATLAB
  340. allocates the object. Then, the special constructor in our wrap code
  341. that is activated when the ptr_constructor_key is passed in passes
  342. the pointer back into a C++ function to add the pointer to its
  343. collector. We go through this extra "C++ to MATLAB to C++ step" in
  344. order to be able to add to the collector could be in a different wrap
  345. module.
  346. */
  347. mxArray* create_object(const std::string& classname, void *pointer, bool isVirtual, const char *rttiName) {
  348. mxArray *result;
  349. mxArray *input[3];
  350. int nargin = 2;
  351. // First input argument is pointer constructor key
  352. input[0] = mxCreateNumericMatrix(1, 1, mxUINT64_CLASS, mxREAL);
  353. *reinterpret_cast<boost::uint64_t*>(mxGetData(input[0])) = ptr_constructor_key;
  354. // Second input argument is the pointer
  355. input[1] = mxCreateNumericMatrix(1, 1, mxUINT32OR64_CLASS, mxREAL);
  356. *reinterpret_cast<void**>(mxGetData(input[1])) = pointer;
  357. // If the class is virtual, use the RTTI name to look up the derived matlab type
  358. const char *derivedClassName;
  359. if(isVirtual) {
  360. const mxArray *rttiRegistry = mexGetVariablePtr("global", "gtsamwrap_rttiRegistry");
  361. if(!rttiRegistry)
  362. mexErrMsgTxt(
  363. "gtsam wrap: RTTI registry is missing - it could have been cleared from the workspace."
  364. " You can issue 'clear all' to completely clear the workspace, and next time a wrapped object is"
  365. " created the RTTI registry will be recreated.");
  366. const mxArray *derivedNameMx = mxGetField(rttiRegistry, 0, rttiName);
  367. if(!derivedNameMx)
  368. mexErrMsgTxt((
  369. "gtsam wrap: The derived class type " + string(rttiName) + " was not found in the RTTI registry. "
  370. "Try calling 'clear all' twice consecutively - we have seen things not get unloaded properly the "
  371. "first time. If this does not work, this may indicate an inconsistency in your wrap interface file. "
  372. "The most likely cause for this is that a base class was marked virtual in the wrap interface "
  373. "definition header file for gtsam or for your module, but a derived type was returned by a C++ "
  374. "function and that derived type was not marked virtual (or was not specified in the wrap interface "
  375. "definition header at all).").c_str());
  376. size_t strLen = mxGetN(derivedNameMx);
  377. char *buf = new char[strLen+1];
  378. if(mxGetString(derivedNameMx, buf, strLen+1))
  379. mexErrMsgTxt("gtsam wrap: Internal error reading RTTI table, try 'clear all' to clear your workspace and reinitialize the toolbox.");
  380. derivedClassName = buf;
  381. input[2] = mxCreateString("void");
  382. nargin = 3;
  383. } else {
  384. derivedClassName = classname.c_str();
  385. }
  386. // Call special pointer constructor, which sets 'self'
  387. mexCallMATLAB(1,&result, nargin, input, derivedClassName);
  388. // Deallocate our memory
  389. mxDestroyArray(input[0]);
  390. mxDestroyArray(input[1]);
  391. if(isVirtual) {
  392. mxDestroyArray(input[2]);
  393. delete[] derivedClassName;
  394. }
  395. return result;
  396. }
  397. /*
  398. When the user calls a method that returns a shared pointer, we create
  399. an ObjectHandle from the shared_pointer and return it as a proxy
  400. class to matlab.
  401. */
  402. template <typename Class>
  403. mxArray* wrap_shared_ptr(boost::shared_ptr< Class > shared_ptr, const std::string& matlabName, bool isVirtual) {
  404. // Create actual class object from out pointer
  405. mxArray* result;
  406. if(isVirtual) {
  407. boost::shared_ptr<void> void_ptr(shared_ptr);
  408. result = create_object(matlabName, &void_ptr, isVirtual, typeid(*shared_ptr).name());
  409. } else {
  410. boost::shared_ptr<Class> *heapPtr = new boost::shared_ptr<Class>(shared_ptr);
  411. result = create_object(matlabName, heapPtr, isVirtual, "");
  412. }
  413. return result;
  414. }
  415. template <typename Class>
  416. boost::shared_ptr<Class> unwrap_shared_ptr(const mxArray* obj, const string& propertyName) {
  417. mxArray* mxh = mxGetProperty(obj,0, propertyName.c_str());
  418. if (mxGetClassID(mxh) != mxUINT32OR64_CLASS || mxIsComplex(mxh)
  419. || mxGetM(mxh) != 1 || mxGetN(mxh) != 1) error(
  420. "Parameter is not an Shared type.");
  421. boost::shared_ptr<Class>* spp = *reinterpret_cast<boost::shared_ptr<Class>**> (mxGetData(mxh));
  422. return *spp;
  423. }
  424. //// throw an error if unwrap_shared_ptr is attempted for an Eigen Vector
  425. //template <>
  426. //Vector unwrap_shared_ptr<Vector>(const mxArray* obj, const string& propertyName) {
  427. // bool unwrap_shared_ptr_Vector_attempted = false;
  428. // BOOST_STATIC_ASSERT(unwrap_shared_ptr_Vector_attempted, "Vector cannot be unwrapped as a shared pointer");
  429. // return Vector();
  430. //}
  431. //// throw an error if unwrap_shared_ptr is attempted for an Eigen Matrix
  432. //template <>
  433. //Matrix unwrap_shared_ptr<Matrix>(const mxArray* obj, const string& propertyName) {
  434. // bool unwrap_shared_ptr_Matrix_attempted = false;
  435. // BOOST_STATIC_ASSERT(unwrap_shared_ptr_Matrix_attempted, "Matrix cannot be unwrapped as a shared pointer");
  436. // return Matrix();
  437. //}