1 /************************************************************************/
2 /*                                                                      */
3 /*                  Copyright 2008 by Ullrich Koethe                    */
4 /*                                                                      */
5 /*    This file is part of the VIGRA computer vision library.           */
6 /*    The VIGRA Website is                                              */
7 /*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
8 /*    Please direct questions, bug reports, and contributions to        */
9 /*        ullrich.koethe@iwr.uni-heidelberg.de    or                    */
10 /*        vigra@informatik.uni-hamburg.de                               */
11 /*                                                                      */
12 /*    Permission is hereby granted, free of charge, to any person       */
13 /*    obtaining a copy of this software and associated documentation    */
14 /*    files (the "Software"), to deal in the Software without           */
15 /*    Software is furnished to do so, subject to the following          */
16 /*    conditions:                                                       */
17 /*    restriction, including without limitation the rights to use,      */
18 /*    copy, modify, merge, publish, distribute, sublicense, and/or      */
19 /*    sell copies of the Software, and to permit persons to whom the    */
20 /*                                                                      */
21 /*    The above copyright notice and this permission notice shall be    */
22 /*    included in all copies or substantial portions of the             */
23 /*    Software.                                                         */
24 /*                                                                      */
25 /*    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND    */
26 /*    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES   */
27 /*    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND          */
28 /*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
29 /*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
30 /*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
31 /*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
32 /*    OTHER DEALINGS IN THE SOFTWARE.                                   */
33 /*                                                                      */
34 /************************************************************************/
35 
36 
37 #ifndef VIGRA_MATLAB_HXX
38 #define VIGRA_MATLAB_HXX
39 
40 #include <string>
41 
42 #include "array_vector.hxx"
43 #include "sized_int.hxx"
44 #include "matrix.hxx"
45 #include <map>
46 #include <time.h>
47 // This is needed with visual studio 10
48 #ifdef _CHAR16T
49 #define CHAR16_T
50 #endif
51 #include <mex.h>
52 #include "matlab_FLEXTYPE.hxx"
53 
54 namespace vigra {
55 
56 namespace matlab {
57 
58 /*++++++++++++++++++++++++++HELPERFUNC+++++++++++++++++++++++++++++++*
59  * This is used for better readability of the test cases            .
60  * Nothing to be done here.
61  *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
cantorPair(int x,int y)62 int cantorPair(int x, int y){
63         return (int)(((x+y)*(x+y+1))/2+y);
64 }
65 
cantorPair(int x,int y,int z)66 int cantorPair(int x, int y, int z){
67         return cantorPair(cantorPair(x,y),z);
68 }
69 
70 template <int x, int y>
71 struct cP{
72     enum { value = (int)(((x+y)*(x+y+1))/2+y)};
73 };
74 
75 template <int x, int y, int z>
76 struct cP3{
77     enum { value = cP<cP<x, y>::value, z>::value};
78 };
79 
80 template <class T>
is_in_range(T in,T min,T max)81 inline bool is_in_range(T in, T min, T max)
82 {
83     return (in >= min && in <= max);
84 }
85 template<class T>
is_in_range(T in,std::string min,T max)86 inline bool is_in_range(T in, std::string min, T max)
87 {
88     return(in <= max);
89 }
90 
91 template<class T>
is_in_range(T in,T min,std::string max)92 inline bool is_in_range(T in, T min, std::string max)
93 {
94     return (in >= min);
95 }
96 
97 template <class T>
98 struct ValueType;
99 
100 #define VIGRA_MATLAB_VALUETYPE_UTIL(type, functionName, typeID, matTypeName) \
101 template <> \
102 struct ValueType<type> \
103 { \
104     static bool check(mxArray const * t) \
105     { \
106         return mxIs##functionName(t); \
107     } \
108     \
109     static mxClassID const classID = typeID; \
110     \
111     static std::string typeName() \
112     { \
113         return #matTypeName; \
114     } \
115 };
116 
117 VIGRA_MATLAB_VALUETYPE_UTIL(double, Double, mxDOUBLE_CLASS, double)
118 VIGRA_MATLAB_VALUETYPE_UTIL(float, Single, mxSINGLE_CLASS, single)
119 VIGRA_MATLAB_VALUETYPE_UTIL(Int8,  Int8, mxINT8_CLASS, int8)
120 VIGRA_MATLAB_VALUETYPE_UTIL(UInt8,  Uint8, mxUINT8_CLASS, uint8)
121 VIGRA_MATLAB_VALUETYPE_UTIL(Int16, Int16, mxINT16_CLASS, int16)
122 VIGRA_MATLAB_VALUETYPE_UTIL(UInt16, Uint16, mxUINT16_CLASS, uint16)
123 
124 #if VIGRA_BITSOF_INT == 32
125 VIGRA_MATLAB_VALUETYPE_UTIL(int, Int32, mxINT32_CLASS, int32)
126 VIGRA_MATLAB_VALUETYPE_UTIL(unsigned int, Uint32, mxUINT32_CLASS, uint32)
127 #elif VIGRA_BITSOF_INT == 64
128 VIGRA_MATLAB_VALUETYPE_UTIL(int, Int64, mxINT64_CLASS, int64)
129 VIGRA_MATLAB_VALUETYPE_UTIL(unsigned int, Uint64, mxUINT64_CLASS, uint64)
130 #endif
131 
132 #if VIGRA_BITSOF_LONG == 32
133 VIGRA_MATLAB_VALUETYPE_UTIL(long, Int32, mxINT32_CLASS, int32)
134 VIGRA_MATLAB_VALUETYPE_UTIL(unsigned long, Uint32, mxUINT32_CLASS, uint32)
135 #elif VIGRA_BITSOF_LONG == 64
136 VIGRA_MATLAB_VALUETYPE_UTIL(long, Int64, mxINT64_CLASS, int64)
137 VIGRA_MATLAB_VALUETYPE_UTIL(unsigned long, Uint64, mxUINT64_CLASS, uint64)
138 #endif
139 
140 #if VIGRA_BITSOF_LONG_LONG == 32
141 VIGRA_MATLAB_VALUETYPE_UTIL(long long, Int32, mxINT32_CLASS, int32)
142 VIGRA_MATLAB_VALUETYPE_UTIL(unsigned long long, Uint32, mxUINT32_CLASS, uint32)
143 #elif VIGRA_BITSOF_LONG_LONG == 64
144 VIGRA_MATLAB_VALUETYPE_UTIL(long long, Int64, mxINT64_CLASS, int64)
145 VIGRA_MATLAB_VALUETYPE_UTIL(unsigned long long, Uint64, mxUINT64_CLASS, uint64)
146 #endif
147 
148 #undef VIGRA_MATLAB_VALUETYPE_UTIL
149 
150 class ConstStructArray
151 {
152   protected:
153     mxArray * matPointer_;
154 
155   public:
156 
157     struct Proxy
158     {
159         mxArray * matPointer_;
160         int index_;
161 
Proxyvigra::matlab::ConstStructArray::Proxy162         Proxy(mxArray * matPointer, int index)
163         : matPointer_(matPointer),
164           index_(index)
165         {}
166 
operator const mxArray*vigra::matlab::ConstStructArray::Proxy167         operator const mxArray *() const
168         {
169             return mxGetFieldByNumber(matPointer_, 0, index_);
170         }
171     };
172 
ConstStructArray(const mxArray * matPointer=0)173     ConstStructArray(const mxArray * matPointer = 0)
174     : matPointer_(const_cast<mxArray *>(matPointer))
175     {
176         if(matPointer != 0 && !mxIsStruct(matPointer))
177             mexErrMsgTxt("StructArray(mxArray *): Argument must be a Matlab struct array.");
178     }
179 
operator [](const char * field_name) const180     Proxy operator[](const char * field_name) const
181     {
182         if(matPointer_ == 0)
183             mexErrMsgTxt("StructArray::operator[]: Cannot access uninitialized struct array.");
184 
185         int i = mxGetFieldNumber(matPointer_, field_name);
186         if(i == -1)
187             mexErrMsgTxt("StructArray::operator[]: Unknown field name.");
188 
189         return Proxy(matPointer_, i);
190     }
191 
operator [](std::string field_name) const192     Proxy operator[](std::string field_name) const
193     {
194         return operator[](field_name.c_str());
195     }
196 
isValid() const197     bool isValid() const
198     {
199         return matPointer_ != 0;
200     }
201 
isValid(const char * field_name) const202     bool isValid(const char * field_name) const
203     {
204         return isValid() && mxGetFieldNumber(matPointer_, field_name) != -1;
205     }
206 
isValid(std::string field_name) const207     bool isValid(std::string field_name) const
208     {
209         return isValid(field_name.c_str());
210     }
211 };
212 
213 class ConstCellArray
214 {
215   protected:
216     mxArray * matPointer_;
217     int size_;
218 
219   public:
220 
221     struct Proxy
222     {
223         mxArray * matPointer_;
224         int index_;
225 
Proxyvigra::matlab::ConstCellArray::Proxy226         Proxy(mxArray * matPointer, int index)
227         : matPointer_(matPointer),
228           index_(index)
229         {}
230 
operator const mxArray*vigra::matlab::ConstCellArray::Proxy231         operator const mxArray *() const
232         {
233             return mxGetCell(matPointer_, index_);
234         }
235     };
236 
ConstCellArray(const mxArray * matPointer=0)237     ConstCellArray(const mxArray * matPointer = 0)
238     : matPointer_(const_cast<mxArray *>(matPointer)),
239       size_(0)
240     {
241         if(matPointer != 0 && !mxIsCell(matPointer))
242             mexErrMsgTxt("CellArray(mxArray *): Argument must be a Matlab cell array.");
243         if(matPointer != 0)
244             size_ = static_cast<int>(mxGetNumberOfElements(matPointer));
245         else
246             size_ = -1;
247     }
248 
operator [](int i) const249     Proxy operator[](int i) const
250     {
251         if(!isValid(i))
252             mexErrMsgTxt("CellArray::operator[]: Index out of range.");
253         return Proxy(matPointer_, i);
254     }
255 
size() const256     int size() const
257     {
258         return size_;
259     }
260 
isValid(int i) const261     bool isValid( int i ) const
262     {
263         return i >= 0 && i < size_;
264     }
265 
266 };
267 
268 class CellArray
269 : public ConstCellArray
270 {
271   public:
272 
273     struct Proxy
274     : public ConstCellArray::Proxy
275     {
Proxyvigra::matlab::CellArray::Proxy276         Proxy(mxArray * matPointer, int index)
277         : ConstCellArray::Proxy(matPointer, index)
278         {}
279 
operator =vigra::matlab::CellArray::Proxy280         void operator=(mxArray * v)
281         {
282             mxDestroyArray(mxGetCell(matPointer_, index_));
283             mxSetCell(matPointer_, index_, v);
284         }
285     };
286 
CellArray(const mxArray * matPointer)287     CellArray(const mxArray * matPointer)
288     : ConstCellArray(matPointer)
289     {}
290 
operator [](int i)291     Proxy operator[](int i)
292     {
293         if(!isValid(i))
294             mexErrMsgTxt("CellArray::operator[]: Index out of range.");
295         return Proxy(matPointer_, i);
296     }
297 
operator [](int i) const298     ConstCellArray::Proxy operator[](int i) const
299     {
300         if(!isValid(i))
301             mexErrMsgTxt("CellArray::operator[]: Index out of range.");
302         return ConstCellArray::Proxy(matPointer_, i);
303     }
304 };
305 
306 
307 
308 
309 
310 template <class T, unsigned int SIZE>
311 TinyVectorView<T, SIZE>
getTinyVector(mxArray const * t)312 getTinyVector(mxArray const * t)
313 {
314     if(!ValueType<T>::check(t))
315     {
316         std::string msg = std::string("Input array must have type ") +
317                           ValueType<T>::typeName() + ".";
318         mexErrMsgTxt(msg.c_str());
319     }
320     if(SIZE != mxGetNumberOfElements(t))
321     {
322         mexErrMsgTxt("getTinyVector(): Input array has wrong number of elements.");
323     }
324 
325     return TinyVectorView<T, SIZE>((T *)mxGetData(t));
326 }
327 
328 template <unsigned int SIZE>
329 typename MultiArrayShape<SIZE>::type
getShape(mxArray const * t)330 getShape(mxArray const * t)
331 {
332     if(!ValueType<Int32>::check(t))
333     {
334         std::string msg = std::string("Input array must have type 'int32'.");
335         mexErrMsgTxt(msg.c_str());
336     }
337     if(SIZE != mxGetNumberOfElements(t))
338     {
339         mexErrMsgTxt("getShape(): Input array has wrong number of elements.");
340     }
341     TinyVectorView<Int32, SIZE> res((MultiArrayIndex *)mxGetData(t));
342     return typename MultiArrayShape<SIZE>::type(res);
343 }
344 
345 template <int DIM, class T>
346 MultiArrayView<DIM, T>
getMultiArray(mxArray const * t)347 getMultiArray(mxArray const * t)
348 {
349     typedef typename MultiArrayView<DIM, T>::difference_type Shape;
350 
351     if(!ValueType<T>::check(t))
352     {
353         std::string msg = std::string("getMultiArray(): Input array must have type ") +
354                           ValueType<T>::typeName() + ".";
355         mexErrMsgTxt(msg.c_str());
356     }
357 
358     Shape shape;
359     if(DIM > 1)
360     {
361         int mdim = mxGetNumberOfDimensions(t);
362         if(DIM < mdim)
363         {
364             mexErrMsgTxt("getMultiArray(): Input array has too many dimensions.");
365         }
366         const mwSize * matlabShape = mxGetDimensions(t);
367         for(int k=0; k<mdim; ++k)
368         {
369             shape[k] = static_cast<typename Shape::value_type>(matlabShape[k]);
370         }
371         for(int k=mdim; k<DIM; ++k)
372         {
373             shape[k] = 1;
374         }
375     }
376     else
377     {
378         shape[0] = static_cast<typename Shape::value_type>(mxGetNumberOfElements(t));
379     }
380     return MultiArrayView<DIM, T>(shape, (T *)mxGetData(t));
381 }
382 
383 template <int DIM, class T>
384 MultiArrayView<DIM, T>
createMultiArray(typename MultiArrayShape<DIM>::type const & shape,mxArray * & t)385 createMultiArray(typename MultiArrayShape<DIM>::type const & shape, mxArray * & t)
386 {
387     mwSize matlabShape[DIM];
388     for(int k=0; k<DIM; ++k)
389         matlabShape[k] = static_cast<mwSize>(shape[k]);
390     t = mxCreateNumericArray(DIM, matlabShape, ValueType<T>::classID, mxREAL);
391 
392     return MultiArrayView<DIM, T>(shape, (T *)mxGetData(t));
393 }
394 
395 template <int DIM, class T>
396 MultiArrayView<DIM, T>
createMultiArray(typename MultiArrayShape<DIM>::type const & shape,CellArray::Proxy t)397 createMultiArray(typename MultiArrayShape<DIM>::type const & shape, CellArray::Proxy t)
398 {
399     mwSize matlabShape[DIM];
400     for(int k=0; k<DIM; ++k)
401         matlabShape[k] = static_cast<mwSize>(shape[k]);
402     t = mxCreateNumericArray(DIM, matlabShape, ValueType<T>::classID, mxREAL);
403 
404     return MultiArrayView<DIM, T>(shape, (T *)mxGetData(t));
405 }
406 
407 template <class T>
408 inline MultiArrayView<1, T>
getArray(mxArray const * t)409 getArray(mxArray const * t)
410 {
411     return getMultiArray<1, T>(t);
412 }
413 
414 template <class T>
415 inline MultiArrayView<1, T>
createArray(MultiArrayIndex size,mxArray * & t)416 createArray(MultiArrayIndex size, mxArray * & t)
417 {
418     return createMultiArray<1, T>(MultiArrayShape<1>::type(size), t);
419 }
420 
421 template <class T>
422 inline MultiArrayView<1, T>
createArray(MultiArrayIndex size,CellArray::Proxy t)423 createArray(MultiArrayIndex size, CellArray::Proxy t)
424 {
425     return createMultiArray<1, T>(MultiArrayShape<1>::type(size), t);
426 }
427 
428 template <class T>
429 MultiArrayView<2, T>
getMatrix(mxArray const * t)430 getMatrix(mxArray const * t)
431 {
432     typedef typename MultiArrayView<2, T>::difference_type Shape;
433 
434     if(!ValueType<T>::check(t))
435     {
436         std::string msg = std::string("getMatrix(): Input matrix must have type ") +
437                           ValueType<T>::typeName() + ".";
438         mexErrMsgTxt(msg.c_str());
439     }
440 
441     if(2 != mxGetNumberOfDimensions(t))
442         mexErrMsgTxt("getMatrix(): Input matrix must have 2 dimensions.");
443 
444     const mwSize * matlabShape = mxGetDimensions(t);
445     Shape shape(static_cast<MultiArrayIndex>(matlabShape[0]),
446                 static_cast<MultiArrayIndex>(matlabShape[1]));
447 
448     return MultiArrayView<2, T>(shape, (T *)mxGetData(t));
449 }
450 
451 template <class T>
452 MultiArrayView<2, T>
createMatrix(mwSize rowCount,mwSize columnCount,mxArray * & t)453 createMatrix(mwSize rowCount, mwSize columnCount, mxArray * & t)
454 {
455     typedef typename MultiArrayView<2, T>::difference_type Shape;
456 
457     Shape shape(rowCount, columnCount);
458     t = mxCreateNumericMatrix(rowCount, columnCount, ValueType<T>::classID, mxREAL);
459 
460     return MultiArrayView<2, T>(shape, (T *)mxGetData(t));
461 }
462 
463 template <class T>
464 MultiArrayView<2, T>
createMatrix(mwSize rowCount,mwSize columnCount,CellArray::Proxy t)465 createMatrix(mwSize rowCount, mwSize columnCount, CellArray::Proxy t)
466 {
467     typedef typename MultiArrayView<2, T>::difference_type Shape;
468 
469     Shape shape(rowCount, columnCount);
470     t = mxCreateNumericMatrix(rowCount, columnCount, ValueType<T>::classID, mxREAL);
471 
472     return MultiArrayView<2, T>(shape, (T *)mxGetData(t));
473 }
474 
475 template <class T>
476 BasicImageView<T>
getImage(mxArray const * t)477 getImage(mxArray const * t)
478 {
479     if(!ValueType<T>::check(t))
480     {
481         std::string msg = std::string("getImage(): Input matrix must have type ") +
482                           ValueType<T>::typeName() + ".";
483         mexErrMsgTxt(msg.c_str());
484     }
485 
486     if(2 != mxGetNumberOfDimensions(t))
487         mexErrMsgTxt("getImage(): Input matrix must have 2 dimensions.");
488 
489     const mwSize * matlabShape = mxGetDimensions(t);
490     return BasicImageView<T>((T *)mxGetData(t), static_cast<int>(matlabShape[0]),
491                                                 static_cast<int>(matlabShape[1]));
492 }
493 
494 template <class T>
495 BasicImageView<T>
createImage(mwSize width,mwSize height,mxArray * & t)496 createImage(mwSize width, mwSize height, mxArray * & t)
497 {
498     t = mxCreateNumericMatrix(width, height, ValueType<T>::classID, mxREAL);
499 
500     return BasicImageView<T>((T *)mxGetData(t), width, height);
501 }
502 
503 template <class T>
504 BasicImageView<T>
createImage(mwSize width,mwSize height,CellArray::Proxy t)505 createImage(mwSize width, mwSize height, CellArray::Proxy t)
506 {
507     t = mxCreateNumericMatrix(width, height, ValueType<T>::classID, mxREAL);
508 
509     return BasicImageView<T>((T *)mxGetData(t), width, height);
510 }
511 
512 inline ConstCellArray
getCellArray(mxArray const * t)513 getCellArray(mxArray const * t)
514 {
515     return ConstCellArray(t);
516 }
517 
518 inline CellArray
createCellArray(mwSize size,mxArray * & t)519 createCellArray(mwSize size, mxArray * & t)
520 {
521     mwSize matSize[] = { size };
522     t = mxCreateCellArray(1, matSize);
523 
524     return CellArray(t);
525 }
526 
527 inline CellArray
createCellArray(mwSize size,CellArray::Proxy t)528 createCellArray(mwSize size, CellArray::Proxy t)
529 {
530     mwSize matSize[] = { size };
531     t = mxCreateCellArray(1, matSize);
532 
533     return CellArray(t);
534 }
535 
536 inline ConstStructArray
getStructArray(mxArray const * t)537 getStructArray(mxArray const * t)
538 {
539     return ConstStructArray(t);
540 }
541 
542 template<class T>
543 T
getScalar(mxArray const * t)544 getScalar(mxArray const * t)
545 {
546     if(mxIsEmpty(t))
547         mexErrMsgTxt("getScalar() on empty input.");
548     if(!mxIsNumeric(t) && !mxIsLogical(t))
549         mexErrMsgTxt("getScalar(): argument is not numeric.");
550     return static_cast<T>(mxGetScalar(t));
551 }
552 
553 template<class T>
554 mxArray *
createScalar(T v)555 createScalar(T v)
556 {
557     mxArray * m;
558     createMatrix<double>(1, 1, m)(0,0) = static_cast<double>(v);
559     return m;
560 }
561 
562 inline std::string
getString(mxArray const * t)563 getString(mxArray const * t)
564 {
565     if(mxIsEmpty(t))
566         mexErrMsgTxt("getString() on empty input.");
567     if(!mxIsChar(t))
568         mexErrMsgTxt("getString(): argument is not a string.");
569     int size = static_cast<int>(mxGetNumberOfElements(t) + 1);
570     ArrayVector<char> buf(size);
571     mxGetString(t, buf.begin(), size);
572     return std::string(buf.begin());
573 }
574 
575 
576 
577 class CompileTimeError;
578 
579 namespace detail {
580 
581 class Required
582 {
583   public:
argumentWasProvided() const584     void argumentWasProvided() const { /* empty because required arguments are always provided */ }
585 };
586 
587 
588 template<class T>
589 class DefaultImpl
590 {
591   public:
592 
593     T defaultValue_;
594     mutable bool * argumentWasProvided_;
595 
DefaultImpl(T v,bool * argFlag=0)596     DefaultImpl(T v, bool * argFlag = 0)
597     : defaultValue_(v),
598       argumentWasProvided_(argFlag)
599     {
600         if(argumentWasProvided_ != 0)
601             *argumentWasProvided_ = false;
602     }
603 
argumentWasProvided() const604     void argumentWasProvided() const
605     {
606         if(argumentWasProvided_ != 0)
607             *argumentWasProvided_ = true;
608     }
609 };
610 
611 class OptionalImpl
612 {
613   public:
614     mutable bool * argumentWasProvided_;
615 
OptionalImpl(bool * argFlag=0)616     OptionalImpl(bool * argFlag = 0)
617     : argumentWasProvided_(argFlag)
618     {
619         if(argumentWasProvided_ != 0)
620             *argumentWasProvided_ = false;
621     }
622 
argumentWasProvided() const623     void argumentWasProvided() const
624     {
625         if(argumentWasProvided_ != 0)
626             *argumentWasProvided_ = true;
627     }
628 };
629 
630 } // namespace detail
631 
v_required()632 inline detail::Required v_required()
633 {
634     return detail::Required();
635 }
636 
637 template<class T>
v_default(T in)638 inline detail::DefaultImpl<T> v_default(T in)
639 {
640     return detail::DefaultImpl<T>(in);
641 }
642 
643 template<class T>
v_default(T in,bool & argFlag)644 inline detail::DefaultImpl<T> v_default(T in, bool & argFlag)
645 {
646     return detail::DefaultImpl<T>(in, &argFlag);
647 }
648 
v_optional()649 inline detail::OptionalImpl v_optional()
650 {
651     return detail::OptionalImpl();
652 }
653 
v_optional(bool & argFlag)654 inline detail::OptionalImpl v_optional(bool& argFlag)
655 {
656     return detail::OptionalImpl(&argFlag);
657 }
658 
659 // TODO:
660 //    * handle rgb images
661 //    * handle complex matrices
662 //    * handle sparse matrices
663 
664 class InputArray
665 {
666     int size_;
667     const mxArray ** data_;
668 
createErrMsg(std::string name)669     std::string createErrMsg(std::string name)
670     {
671         std::string s1;
672         s1 =  "Required input '" + name + "' not found in option struct!";
673         return s1;
674     }
createErrMsg(int pos)675     std::string createErrMsg(int pos)
676     {
677         char tmp[10] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
678         std::string oi(1, tmp[pos%10]);
679         std::string s1  = "Required input in signature of function at position: '"+ oi+"' has not been supplied";
680         return s1;
681     }
682 
683 
684   public:
685     ConstStructArray options_;
686 
687     /* Local Typedefs */
688     typedef const mxArray * value_type;
689     typedef value_type & reference;
690     typedef value_type const & const_reference;
691     typedef value_type * pointer;
692     typedef value_type const * const_pointer;
693     typedef int size_type;
694     typedef int difference_type;
695 
696     /*Constructor*/
InputArray(size_type size,pointer data)697     InputArray(size_type size, pointer data)
698     : size_(size),
699       data_(data),
700       options_(isValid(size-1) && mxIsStruct(data_[size-1])
701                  ? data_[size-1]
702                  : 0)
703     {}
704 
705     /*Operators*/
operator [](difference_type i) const706     const_reference operator[]( difference_type i ) const
707     {
708         if(!isValid(i))
709             mexErrMsgTxt("Too few input arguments.");
710         return data_[i];
711     }
712 
operator [](std::string name) const713     value_type operator[]( std::string name) const
714     {
715         std::string errMsg = "Not Found " + name +" in OptionStruct or OptionStruct not set";
716         if(!isValid(name))
717             mexErrMsgTxt(errMsg.c_str());
718         return options_[name];
719     }
720 
721 
722     /*Some More Helper Func*/
size() const723     size_type size() const
724     {
725         return size_;
726     }
727 
isValid(difference_type i) const728     bool isValid( difference_type i ) const
729     {
730         return i >= 0 && i < size_;
731     }
732 
isValid(std::string name) const733     bool isValid(std::string name) const
734     {
735         return options_.isValid(name);
736     }
737 
isEmpty(difference_type i) const738     bool isEmpty(difference_type i) const
739     {
740         return mxIsEmpty(data_[i]);
741     }
742 
isEmpty(std::string name) const743     bool isEmpty(std::string name) const
744     {
745         return mxIsEmpty(options_[name]);
746     }
747 
hasData(difference_type i) const748     bool hasData(difference_type i) const
749     {
750         return isValid(i) && !isEmpty(i);
751     }
752 
hasData(std::string name) const753     bool hasData(std::string name) const
754     {
755         return isValid(name) && !isEmpty(name);
756     }
757 
758     template<class Place>
typeOf(Place posOrName)759     mxClassID typeOf(Place posOrName)
760     {
761         return mxGetClassID((*this)[posOrName]);
762     }
763 
764     /*Action to take if value not set*/
765     template <class T, class U, class Place>
766     T errorOrDefault(detail::DefaultImpl<U> const & o, Place posOrName)
767     {
768         return o.defaultValue_;
769     }
770 
771     template <class T, class Place>
772     T errorOrDefault(detail::OptionalImpl, Place posOrName)
773     {
774         return T();
775     }
776 
777     template <class T, class Place>
778     T errorOrDefault(detail::Required r, Place posOrName)
779     {
780         std::string a = createErrMsg(posOrName);
781         mexErrMsgTxt( a.c_str());
782         return T();
783     }
784 
785     /*getter Func*/
786     template <class Place, class ReqType>
getEnum(Place posOrName,ReqType req,std::map<std::string,int> const & converter)787     int getEnum(Place posOrName, ReqType req, std::map<std::string, int> const & converter)
788     {
789         if(!hasData(posOrName))
790         {
791             return errorOrDefault<int>(req, posOrName);
792         }
793         std::string enumAsString = matlab::getString((*this)[posOrName]);
794         typename std::map<std::string, int>::const_iterator m = converter.find(enumAsString);
795         if(m == converter.end())
796         {
797             std::string msg = std::string("Unknown option: ") + enumAsString + ".";
798             mexErrMsgTxt(msg.c_str());
799         }
800 
801         req.argumentWasProvided();
802         return (*m).second;
803     }
804 
805 
806     /*String Type*/
807     template <class Place, class ReqType>
getString(Place posOrName,ReqType req)808     std::string getString(Place posOrName, ReqType req)
809     {
810         if(!hasData(posOrName))
811         {
812             return errorOrDefault<std::string>(req, posOrName);
813         }
814         else
815         {
816             req.argumentWasProvided();
817             return matlab::getString((*this)[posOrName]);
818         }
819     }
820 
821     /*Scalar Type*/
822     template <class T,class Place, class ReqType>
823     T getScalar(Place posOrName, ReqType req)
824     {
825         if(!hasData(posOrName))
826         {
827             return errorOrDefault<T>(req, posOrName);
828         }
829         else
830         {
831             req.argumentWasProvided();
832             return matlab::getScalar<T>((*this)[posOrName]);
833         }
834     }
835 
836 
837     template <class T, class Place, class ReqType, class minClass, class maxClass>
838     T getScalarMinMax(Place posOrName, ReqType req, minClass min_, maxClass max_)
839     {
840         T temp = this->getScalar<T>(posOrName, req);
841         if (!is_in_range(temp, min_, max_))
842             mexErrMsgTxt("Value out of bounds.");
843         return temp;
844     }
845 
846     template <class T, class Place, class ReqType, class iteratorType>
847     T getScalarVals(Place posOrName, ReqType req, iteratorType begin_, iteratorType end_)
848     {
849         T temp = this->getScalar<T>(posOrName, req);
850         for(iteratorType iter = begin_; iter != end_; ++iter)
851         {
852             if((*iter) == temp) return temp;
853         }
854         mexErrMsgTxt("Value not allowed");
855     }
856 
857 
858 
859     template <class T, class Place, class ReqType, class iteratorType>
860     T getScalarVals2D3D(Place posOrName, ReqType req, iteratorType begin2D_, iteratorType end2D_,
861                                                      iteratorType begin3D_, iteratorType end3D_,
862                                                      int dimVar)
863     {
864         T temp = this->getScalar<T>(posOrName, req);
865         switch(dimVar)
866         {
867             case 2:
868                 for(iteratorType iter = begin2D_; iter != end2D_; ++iter)
869                 {
870                     if((*iter) == temp) return temp;
871                 }
872                 break;
873             case 3:
874                 for(iteratorType iter = begin3D_; iter != end3D_; ++iter)
875                 {
876                     if((*iter) == temp) return temp;
877                 }
878                 break;
879             default:
880                 mexErrMsgTxt("dimVar specified must be 2 or 3");
881         }
882         mexErrMsgTxt("Value not allowed");
883     }
884 
885     template <class Place, class ReqType>
getBool(Place posOrName,ReqType req)886     bool getBool(Place posOrName, ReqType req)
887     {
888         return this->getScalarMinMax<int>(posOrName, req, 0, 1) != 0;
889     }
890 
891     /*Array Type*/
892     template <unsigned int N, class T, class Place, class ReqType>
getMultiArray(Place posOrName,ReqType req)893     MultiArrayView<N,T> getMultiArray(Place posOrName, ReqType req)
894     {
895         if(!hasData(posOrName))
896         {
897             return errorOrDefault< MultiArrayView<N,T> >(req, posOrName);
898         }
899         else
900         {
901             req.argumentWasProvided();
902             value_type temp = (*this)[posOrName];
903             return matlab::getMultiArray<N,T>(temp);
904         }
905     }
906 
907     template < class T, class Place, class ReqType>
getImage(Place posOrName,ReqType req)908     BasicImageView<T> getImage(Place posOrName, ReqType req)
909     {
910         if(!hasData(posOrName))
911         {
912             return errorOrDefault<BasicImageView<T> >(req, posOrName);
913         }
914         else
915         {
916             req.argumentWasProvided();
917             value_type temp = (*this)[posOrName];
918             return matlab::getImage<T>(temp);
919         }
920     }
921 
922     template<class T,unsigned int sze, class Place, class ReqType>
getTinyVector(Place posOrName,ReqType req)923     TinyVectorView< T, sze> getTinyVector(Place posOrName, ReqType req)
924     {
925         if(!hasData(posOrName))
926         {
927             return errorOrDefault<TinyVectorView< T, sze> >(req, posOrName);
928         }
929         else
930         {
931             req.argumentWasProvided();
932             value_type temp = (*this)[posOrName];
933             return matlab::getTinyVector< T, sze>(temp);
934         }
935     }
936 
937     template< unsigned int sze, class Place, class ReqType>
getShape(Place posOrName,ReqType req)938     TinyVectorView<MultiArrayIndex, sze> getShape(Place posOrName, ReqType req)
939     {
940         if(!hasData(posOrName))
941         {
942             return errorOrDefault<TinyVectorView<MultiArrayIndex, sze> >(req, posOrName);
943         }
944         else
945         {
946             req.argumentWasProvided();
947             value_type temp = (*this)[posOrName];
948             return matlab::getShape<sze>(temp);
949         }
950     }
951 
952 
953     template< class Place, class ReqType>
getDimOfInput(Place posOrName,ReqType req)954     int getDimOfInput(Place posOrName, ReqType req)
955     {
956         if(!hasData(posOrName))
957         {
958             return errorOrDefault<int>(req, posOrName);
959         }
960         else
961         {
962             req.argumentWasProvided();
963             return mxGetNumberOfDimensions((*this)[posOrName]);
964         }
965     }
966 
967     template<class ReqType>
getCellArray(int posOrName,ReqType req)968     ConstCellArray getCellArray(int posOrName, ReqType req)
969     {
970         if(!hasData(posOrName))
971         {
972             return errorOrDefault<ConstCellArray>(req, posOrName);
973         }
974         else
975         {
976             req.argumentWasProvided();
977             value_type temp = (*this)[posOrName];
978             return matlab::getCellArray(temp);
979         }
980     }
981 
982     template<class ReqType>
getCellArray(std::string posOrName,ReqType req)983     ConstCellArray getCellArray(std::string posOrName, ReqType req)
984     {
985         CompileTimeError ERROR__Const_Cell_Array_May_Not_Be_In_Option_Struct;
986         return ConstCellArray(); //avoid compiler warning
987     }
988 
989 };
990 
991 class OutputArray
992 {
993     int size_;
994     mxArray ** data_;
createErrMsgOut(int pos)995     std::string createErrMsgOut(int pos)
996     {
997         char tmp[10] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
998         std::string oi(1, tmp[pos%10]);
999         std::string s1 =  "Required Output at position: '" + oi + "' has not been supplied";
1000         return s1;
1001     }
1002   public:
1003 
1004     typedef mxArray * value_type;
1005     typedef value_type & reference;
1006     typedef value_type const & const_reference;
1007     typedef value_type * pointer;
1008     typedef value_type const * const_pointer;
1009     typedef int size_type;
1010     typedef int difference_type;
1011 
OutputArray(size_type size,pointer data)1012     OutputArray(size_type size, pointer data)
1013     : size_(size),
1014       data_(data)
1015     {}
1016 
operator [](difference_type i)1017     reference operator[]( difference_type i )
1018     {
1019         if(!isValid(i))
1020             mexErrMsgTxt("Too few output arguments.");
1021         return data_[i];
1022     }
1023 
operator [](difference_type i) const1024     const_reference operator[]( difference_type i ) const
1025     {
1026         if(!isValid(i))
1027             mexErrMsgTxt("Too few output arguments.");
1028         return data_[i];
1029     }
1030 
size() const1031     size_type size() const
1032     {
1033         return size_;
1034     }
1035 
isValid(difference_type i) const1036     bool isValid( difference_type i ) const
1037     {
1038         return i >= 0 && i < size_;
1039     }
1040 
isEmpty(difference_type i)1041     bool isEmpty(difference_type i){
1042         return mxIsEmpty(data_[i]);
1043     }
1044 
1045     template <class T>
errorOrDefault(detail::OptionalImpl const & o,int Pos)1046     T errorOrDefault(detail::OptionalImpl const & o, int Pos)
1047     {
1048         return T();
1049     }
1050 
1051     template <class T>
errorOrDefault(detail::Required r,int Pos)1052     T errorOrDefault(detail::Required r, int Pos)
1053     {
1054         mexErrMsgTxt(createErrMsgOut(Pos).c_str());
1055         return T();
1056     }
1057 
1058     /* creating func */
1059     template <unsigned int DIM, class T, class ReqType>
createMultiArray(int pos,ReqType req,const TinyVector<int,DIM> & shape)1060     MultiArrayView<DIM, T> createMultiArray(int pos,ReqType req,
1061                                             const TinyVector<int, DIM>  & shape)
1062     {
1063         if(!isValid(pos))
1064             return errorOrDefault<MultiArrayView<DIM, T> >(req, pos);
1065         req.argumentWasProvided();
1066         return matlab::createMultiArray<DIM, T>(shape, (*this)[pos]);
1067     }
1068 
1069     template <class T, class ReqType>
createImage(int pos,ReqType req,mwSize width,mwSize height)1070     BasicImageView<T> createImage(int pos, ReqType req,
1071                                     mwSize width, mwSize height)
1072     {
1073         if(!isValid(pos))
1074             return errorOrDefault<BasicImageView<T> >(req, pos);
1075         req.argumentWasProvided();
1076         return matlab::createImage<T>(width, height, (*this)[pos]);
1077     }
1078 
1079     template <class T, class ReqType>
createImage(int pos,ReqType req,typename MultiArrayShape<2>::type const & shape)1080     BasicImageView<T> createImage(  int pos, ReqType req,
1081                                     typename MultiArrayShape<2>::type const & shape)
1082     {
1083         return createImage<T>(pos, req, shape[1], shape[0]);
1084     }
1085 
1086     template <class T, class ReqType>
1087     T* createScalar(int pos, ReqType req)
1088     {
1089         if(!isValid(pos))
1090             return errorOrDefault<T*>(req, pos);
1091         req.argumentWasProvided();
1092         BasicImageView<T> temp = matlab::createImage<T>(1, 1, (*this)[pos]);
1093         return &temp(0,0);
1094     }
1095 
1096     template <class T, class ReqType>
createScalar(int pos,ReqType req,T val)1097     void createScalar(int pos, ReqType req, T val)
1098     {
1099         if(!isValid(pos))
1100         {
1101             errorOrDefault<T>(req, pos);
1102             return;
1103         }
1104         req.argumentWasProvided();
1105         BasicImageView<T> temp = matlab::createImage<T>(1, 1, (*this)[pos]);
1106         temp(0,0) = val;
1107     }
1108 
1109     template <class ReqType>
createCellArray(int pos,ReqType req,mwSize sze)1110     ConstCellArray createCellArray(int pos, ReqType req, mwSize sze)
1111     {
1112         if(!isValid(pos))
1113             return errorOrDefault<ConstCellArray>(req, pos);
1114         return matlab::createCellArray(sze, (*this)[pos]);
1115     }
1116 };
1117 
1118 
1119 
1120 /***********************************
1121 Rahuls code starts here
1122 ************************************/
1123 using namespace vigra;
1124 
1125 
1126 //Wrapper classes to STL-Map for use as a sparse array.
1127 
1128 //This is used for the ordering of the map. Lexicographical ordering of the index pairs.
1129 struct ShapeCmp {
operator ()vigra::matlab::ShapeCmp1130   bool operator()( TinyVector<int,2> s1, TinyVector<int,2>  s2 ) const {
1131     if(s1[0] != s2[0]){
1132         return (s1[0] < s2[0]);
1133     } else {
1134         return s1[1] < s2[1];
1135     }
1136   }
1137 };
1138 
1139 template<class T>
1140 class SparseArray
1141 {
1142 
1143     std::map<TinyVector<int,2>, T,ShapeCmp> data;
1144     int width, length;
1145 
1146     public:
assign(int i=1,int j=1)1147     void assign(int i = 1, int j = 1){
1148         width = j;
1149         length = i;
1150     }
SparseArray(int i=1,int j=1)1151     SparseArray(int i = 1 , int j = 1){
1152         width = j;
1153         length = i;
1154     }
1155 
1156     //Any better idea? i would like to unify the get and operator() functions.
1157     // Problem is that  operator() always passes a reference or creates one.
1158     template<class indexType>
operator ()(indexType i_,indexType j_)1159     T& operator()(indexType i_, indexType j_){
1160         Int32 i = static_cast<Int32>(i_);
1161         Int32 j = static_cast<Int32>(j_);
1162         TinyVector<int,2> newShapew(i, j);
1163         typename std::map<TinyVector<int,2>, T, ShapeCmp>::iterator iter;
1164         TinyVector<int,2> newShape;
1165         return data[newShapew];
1166     }
1167 
1168     template<class indexType>
get(indexType i_,indexType j_)1169     const T get(indexType i_, indexType j_){
1170         Int32 i = static_cast<Int32>(i_);
1171         Int32 j = static_cast<Int32>(j_);
1172         TinyVector<int,2> newShape(i, j);
1173         if(data.find(newShape) == data.end()) return 0;
1174         else return data.find(newShape)->second;
1175     }
1176 
1177     //see documentation of mxCreateSparse and the mxGet functions to understand this.
mapToMxArray(mxArray * & in)1178     void mapToMxArray(mxArray * & in){
1179 
1180         int len = data.size();
1181         in = mxCreateSparse(width, length, len, mxREAL);
1182         int* jc = mxGetJc(in);
1183         int* ir = mxGetIr(in);
1184         double* pr = mxGetPr(in);
1185         if(len == 0){
1186             jc[0] = 1;
1187             return;
1188         }
1189         typename std::map<TinyVector<int,2>, T, ShapeCmp>::iterator iter;
1190         TinyVector<int,2> newShape;
1191         int ii = 0;
1192         int jj = 0;
1193         int curjc = -1;
1194         for( iter = data.begin(); iter != data.end(); ++iter ) {
1195             newShape = iter->first;
1196             ir[ii] = newShape[1];
1197             pr[ii] = iter->second;
1198             if(newShape[0]  != curjc){
1199                 curjc = newShape[0] ;
1200                 jc[jj] = ii;
1201                 jj++;
1202             }
1203 
1204             ii++;
1205         }
1206         jc[jj] = len;
1207     }
1208 
1209 };
1210 
1211 enum DataDimension {IMAGE = 2, VOLUME = 3};
1212 
1213 } // namespace matlab
1214 
1215 } // namespace vigra
1216 
1217 void vigraMexFunction(vigra::matlab::OutputArray, vigra::matlab::InputArray);
1218 
1219 #ifndef VIGRA_CUSTOM_MEXFUNCTION
1220 
1221 /*
1222     DO NOT Comment out this function. If you are using a
1223     custom mexfunction just #define VIGRA_CUSTOM_MEXFUNCTION
1224     before #including matlab.hxx.
1225 */
mexFunction(int nlhs,mxArray * plhs[],int nrhs,const mxArray * prhs[])1226 void mexFunction(int nlhs, mxArray *plhs[],
1227                  int nrhs, const mxArray *prhs[])
1228 {
1229   try
1230   {
1231     vigra::matlab::InputArray inputs(nrhs, prhs);
1232     vigra::matlab::OutputArray outputs(nlhs, plhs);
1233 
1234     vigraMexFunction(outputs, inputs);
1235   }
1236   catch(std::exception & e)
1237   {
1238     mexErrMsgTxt(e.what());
1239   }
1240 }
1241 
1242 #endif /*CUSTOM_MEXFUNCTION*/
1243 
1244 
1245 #define VIGRA_CREATE_ENUM_AND_STD_MAP2(mapName, item1, item2) \
1246     const int item1 = 1;\
1247     const int item2 = 2;\
1248     std::map<std::string,int>  mapName;\
1249     mapName[#item1] = (int)item1;\
1250     mapName[#item2] = (int)item2;\
1251 
1252 
1253 #define VIGRA_CREATE_ENUM_AND_STD_MAP3(mapName, item1, item2, item3) \
1254     const int item1 = 1;\
1255     const int item2 = 2;\
1256     const int item3 = 3;\
1257     std::map<std::string,int>  mapName;\
1258     mapName[#item1] = (int)item1;\
1259     mapName[#item2] = (int)item2;\
1260     mapName[#item3] = (int)item3;\
1261 
1262 
1263 #define VIGRA_CREATE_ENUM_AND_STD_MAP4(mapName, item1, item2, item3, item4) \
1264     const int item1 = 1;\
1265     const int item2 = 2;\
1266     const int item3 = 3;\
1267     const int item4 = 4;\
1268     std::map<std::string,int>  mapName;\
1269     mapName[#item1] = (int)item1;\
1270     mapName[#item2] = (int)item2;\
1271     mapName[#item3] = (int)item3;\
1272     mapName[#item4] = (int)item4;\
1273 
1274 #define VIGRA_CREATE_ENUM_AND_STD_MAP5(mapName, item1, item2, item3, item4, item5) \
1275     const int item1 = 1;\
1276     const int item2 = 2;\
1277     const int item3 = 3;\
1278     const int item4 = 4;\
1279     const int item5 = 5;\
1280     std::map<std::string, int>  mapName;\
1281     mapName[#item1] = (int)item1;\
1282     mapName[#item2] = (int)item2;\
1283     mapName[#item3] = (int)item3;\
1284     mapName[#item4] = (int)item4;\
1285     mapName[#item5] = (int)item5;\
1286 
1287 #define VIGRA_CREATE_ENUM_AND_STD_MAP6(mapName, item1, item2, item3, item4, item5, item6) \
1288     const int item1 = 1;\
1289     const int item2 = 2;\
1290     const int item3 = 3;\
1291     const int item4 = 4;\
1292     const int item5 = 5;\
1293     const int item6 = 6;\
1294     std::map<std::string,int>  mapName;\
1295     mapName[#item1] = (int)item1;\
1296     mapName[#item2] = (int)item2;\
1297     mapName[#item3] = (int)item3;\
1298     mapName[#item4] = (int)item4;\
1299     mapName[#item5] = (int)item5;\
1300     mapName[#item6] = (int)item6;\
1301 
1302 #endif // VIGRA_MATLAB_HXX
1303