////////////////////////////////////////////////////////////////////
// Types.h
//
// Copyright 2007 cDc@seacave
// Distributed under the Boost Software License, Version 1.0
// (See http://www.boost.org/LICENSE_1_0.txt)

#ifndef __SEACAVE_TYPES_H__
#define __SEACAVE_TYPES_H__


// I N C L U D E S /////////////////////////////////////////////////

#ifdef _MSC_VER
#include <windows.h>
#include <tchar.h>
#else
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#endif
#ifdef _SUPPORT_CPP11
#ifdef __clang__
#include <stdint.h>
#else
#include <cstdint>
#endif
#include <cstddef>
#include <type_traits>
#include <initializer_list>
#else
#include <stdint.h>
#endif
#ifdef _SUPPORT_CPP17
#if !defined(__GNUC__) || (__GNUC__ > 7)
#include <filesystem>
#endif
#endif
#include <new>
#include <string>
#include <codecvt>
#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <functional>
#include <algorithm>
#include <numeric>
#include <limits>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <list>
#include <queue>
#include <deque>
#include <iterator>
#include <cmath>
#include <ctime>
#include <random>
#ifdef _USE_OPENMP
#include <omp.h>
#endif

// Function delegate functionality
#ifdef _SUPPORT_CPP11
#include "FastDelegateCPP11.h"
#define DELEGATE fastdelegate::delegate
#define DELEGATEBIND(DLGT, FNC) DLGT::from< FNC >()
#define DELEGATEBINDCLASS(DLGT, FNC, OBJ) DLGT::from(*OBJ, FNC)
#else
#include "FastDelegate.h"
#include "FastDelegateBind.h"
#define DELEGATE fastdelegate::FastDelegate
#define DELEGATEBIND(DLGT, FNC) fastdelegate::bind(FNC)
#define DELEGATEBINDCLASS(DLGT, FNC, OBJ) fastdelegate::bind(FNC, OBJ)
#endif

// include usual boost libraries
#ifdef _USE_BOOST
#if 1
// disable exception support
#define BOOST_NO_UNREACHABLE_RETURN_DETECTION
#define BOOST_EXCEPTION_DISABLE
#define BOOST_NO_EXCEPTIONS
#endif
#ifdef BOOST_NO_EXCEPTIONS
#include <boost/throw_exception.hpp>
#endif
#define BOOST_NO_UNREACHABLE_RETURN_DETECTION
// include headers that implement serialization support
#include <boost/serialization/split_member.hpp>
#include <boost/serialization/split_free.hpp>
#include <boost/serialization/utility.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/list.hpp>
#include <boost/serialization/map.hpp>
#include <boost/serialization/set.hpp>
#if (BOOST_VERSION / 100000) > 1 || (BOOST_VERSION / 100 % 1000) > 55
#include <boost/serialization/unordered_map.hpp>
#include <boost/serialization/unordered_set.hpp>
#endif
#include <boost/serialization/nvp.hpp>
// include headers that define an input and output archive
#include <boost/archive/detail/common_oarchive.hpp>
#include <boost/archive/detail/common_iarchive.hpp>
// include headers that define memory pools
#include <boost/pool/object_pool.hpp>
#include <boost/pool/singleton_pool.hpp>
#endif

#ifdef _USE_EIGEN
#if defined(_MSC_VER)
#pragma warning (push)
#pragma warning (disable : 4244) // 'argument': conversion from '__int64' to 'int', possible loss of data
#endif
#include <Eigen/Core>
#include <Eigen/Dense>
#include <Eigen/Sparse>
#include <Eigen/Geometry>
#include <Eigen/Eigenvalues>
#include <Eigen/SVD>
#include <Eigen/QR>
#include <Eigen/LU>
#if defined(_MSC_VER)
#pragma warning (pop)
#endif
#endif

#pragma push_macro("free")
#undef free
#pragma push_macro("DEBUG")
#undef DEBUG
#include <opencv2/core/version.hpp>
#if CV_MAJOR_VERSION > 2 || CV_MINOR_VERSION > 3
#include <opencv2/opencv_modules.hpp>
#endif
#include <opencv2/opencv.hpp>
#ifdef HAVE_OPENCV_GPU
#if CV_MAJOR_VERSION > 2
#include <opencv2/cudaarithm.hpp>
namespace cv { namespace gpu = cuda; }
#else
#include <opencv2/gpu/gpu.hpp>
#endif
#endif
#pragma pop_macro("DEBUG")
#pragma pop_macro("free")

#ifdef _USE_SSE
#include <xmmintrin.h>
#include <emmintrin.h>
#endif


// D E F I N E S ///////////////////////////////////////////////////

// In order to create a singleton class
// add this define in your class;
#define DECLARE_SINGLETON(SClass) \
	protected: SClass(); SClass(const SClass&); \
	public: static inline SClass& GetInstance() { static SClass instance; return instance; }
// or add this define and declare GetInstance() method in the .cpp
// so that the singleton is unique even across modules;
#define DEFINE_SINGLETON(SClass) \
	protected: SClass(); SClass(const SClass&); \
	public: static SClass& GetInstance();
// or add this declare ms_pInstance;
#define DECLARE_SINGLETONPTR(SClass) \
	SClass* SClass::ms_pInstance(NULL); \
	SClass*& SClass::GetInstanceRef() { return ms_pInstance; } \
	SClass* SClass::GetInstancePtr() { ASSERT(ms_pInstance); return ms_pInstance; } \
	SClass& SClass::GetInstance() { ASSERT(ms_pInstance); return *ms_pInstance; }
// and this define in the class definition.
#define DEFINE_SINGLETONPTR(SClass) \
	protected: SClass(); SClass(const SClass&); static SClass* ms_pInstance; \
	public: static SClass*& GetInstanceRef(); \
	public: static SClass* GetInstancePtr(); \
	public: static SClass& GetInstance();

#ifndef CALL_MEMBER_FN
#define CALL_MEMBER_FN(object,ptrToMember)  ((object).*(ptrToMember))
#endif

#ifndef __PROCESS__
# ifdef _MSC_VER
#  define __PROCESS__ ((unsigned)GetCurrentProcessId())
# else
#  define __PROCESS__ ((unsigned)getpid())
# endif
#endif

#ifndef __THREAD__
# ifdef _MSC_VER
#  define __THREAD__ ((unsigned)GetCurrentThreadId())
# elif defined(__APPLE__)
#  include <pthread.h>
inline pid_t GetCurrentThreadId() { uint64_t tid64; pthread_threadid_np(NULL, &tid64); return (pid_t)tid64; }
#  define __THREAD__ ((unsigned)GetCurrentThreadId())
# else
#  include <sys/syscall.h>
#  define __THREAD__ ((unsigned)((pid_t)syscall(SYS_gettid)))
# endif
#endif

#ifndef STCALL
# if defined(_MSC_VER)
#  define STCALL __cdecl
# elif defined(__OS2__)
#  if defined (__GNUC__) && __GNUC__ < 4
#   define STCALL _cdecl
#  else
#   /* On other compilers on OS/2, we use the _System calling convention */
#   /* to be compatible with every compiler */
#   define STCALL _System
#  endif
# elif defined(__GNUC__)
#   define STCALL __attribute__((__cdecl__))
# else
#  define STCALL
# endif
#endif // STCALL


// T Y P E   D E F I N E S /////////////////////////////////////////

//
// Type defines

#ifndef _MSC_VER
typedef int32_t				HRESULT;

typedef unsigned char		BYTE;
typedef unsigned short		WORD;
typedef unsigned int		DWORD;
typedef uint64_t	        QWORD;

typedef char				CHAR;
typedef CHAR*				LPSTR;
typedef const CHAR*			LPCSTR;
typedef CHAR				TCHAR;
typedef LPSTR				LPTSTR;
typedef LPCSTR				LPCTSTR;

#define _tcslen         	strlen
#define _tcscpy         	strcpy
#define _tcsncpy         	strncpy
#define _tcschr         	strchr
#define _tcsrchr         	strrchr
#define _tcscmp         	strcmp
#define _tcsncmp         	strncmp
#define _tcsicmp         	strcasecmp
#define _tcsnicmp         	strncasecmp
#define _tcsncicmp(s1,s2,s) strncasecmp(s1, s2, (s)*sizeof(TCHAR))
#define _stprintf           sprintf
#define _sntprintf          snprintf
#define _vsntprintf         vsnprintf
#define _vsctprintf         _vscprintf

int _vscprintf(LPCSTR format, va_list pargs);

#define _T(s)               s
#endif //_MSC_VER

#define DECLARE_NO_INDEX(...) std::numeric_limits<__VA_ARGS__>::max()

#ifndef MAKEWORD
#define MAKEWORD(a, b)		((WORD)(((BYTE)(((DWORD)(a)) & 0xff)) | ((WORD)((BYTE)(((DWORD)(b)) & 0xff))) << 8))
#endif
#ifndef MAKELONG
#define MAKELONG(a, b)		((DWORD)(((WORD)(((DWORD)(a)) & 0xffff)) | ((DWORD)((WORD)(((DWORD)(b)) & 0xffff))) << 16))
#endif
#ifndef LOWORD
#define LOWORD(l)			((WORD)(((DWORD)(l)) & 0xffff))
#endif
#ifndef HIWORD
#define HIWORD(l)			((WORD)((((DWORD)(l)) >> 16) & 0xffff))
#endif
#ifndef LOBYTE
#define LOBYTE(w)			((BYTE)(((WORD)(w)) & 0xff))
#endif
#ifndef HIBYTE
#define HIBYTE(w)			((BYTE)((((WORD)(w)) >> 8) & 0xff))
#endif

#ifndef MAX_PATH
#define MAX_PATH			260
#endif

#ifndef NULL
#define NULL				0
#endif

#ifdef max
#undef max
#endif
#ifdef min
#undef min
#endif

#ifndef MINF
#define MINF                std::min
#endif
#ifndef MAXF
#define MAXF                std::max
#endif

#ifndef RAND
#define RAND			    std::rand
#endif

namespace SEACAVE {

// signed and unsigned types of the size of the architecture
// (32 or 64 bit for x86 and respectively x64)
#ifdef _ENVIRONMENT64
typedef int64_t             int_t;
typedef uint64_t            uint_t;
#else
typedef int32_t             int_t;
typedef uint32_t            uint_t;
#endif

// type used for the size of the files
typedef int64_t     	    size_f_t;

// type used as the default floating number precision
typedef double              REAL;

// invalid index
constexpr uint32_t NO_ID = DECLARE_NO_INDEX(uint32_t);

template<typename TYPE, typename REALTYPE=REAL>
struct RealType { typedef typename std::conditional<std::is_floating_point<TYPE>::value, TYPE, REALTYPE>::type type; };

template<typename T>
inline T MINF3(const T& x1, const T& x2, const T& x3) {
	return MINF(MINF(x1, x2), x3);
}
template<typename T>
inline T MAXF3(const T& x1, const T& x2, const T& x3) {
	return MAXF(MAXF(x1, x2), x3);
}

template<typename T>
FORCEINLINE T RANDOM() { return T(RAND())/RAND_MAX; }

template<typename T1, typename T2>
union TAliasCast {
	T1 f;
	T2 i;
	inline TAliasCast() {}
	inline TAliasCast(T1 v) : f(v) {}
	inline TAliasCast(T2 v) : i(v) {}
	inline TAliasCast& operator = (T1 v) { f = v; return *this; }
	inline TAliasCast& operator = (T2 v) { i = v; return *this; }
	inline operator T1 () const { return f; }
};
typedef TAliasCast<float,int32_t> CastF2I;
typedef TAliasCast<double,int32_t> CastD2I;

} // namespace SEACAVE

#if defined(_MSC_VER)
# define __LITTLE_ENDIAN 0
# define __BIG_ENDIAN 1
# define __PDP_ENDIAN 2
# define __BYTE_ORDER __LITTLE_ENDIAN
#elif defined(__APPLE__)
# include <machine/endian.h>
#elif defined(__GNUC__)
# include <endian.h>
#endif


// I N C L U D E S /////////////////////////////////////////////////

#include "Strings.h"
#include "AutoPtr.h"
#include "List.h"
#include "Thread.h"
#include "SharedPtr.h"
#include "Queue.h"
#include "Hash.h"
#include "Timer.h"
#include "CriticalSection.h"
#include "Semaphore.h"
#include "Util.h"
#include "File.h"
#include "MemFile.h"
#include "LinkLib.h"

namespace SEACAVE {

typedef class GENERAL_API CSharedPtr<File>				FilePtr;

typedef class GENERAL_API CSharedPtr<ISTREAM>			ISTREAMPTR;
typedef ISTREAM*										LPISTREAM;

typedef class GENERAL_API CSharedPtr<OSTREAM>			OSTREAMPTR;
typedef OSTREAM*										LPOSTREAM;

typedef class GENERAL_API CSharedPtr<IOSTREAM>			IOSTREAMPTR;
typedef IOSTREAM*										LPIOSTREAM;

typedef class GENERAL_API cList<void*, void*, 0>        VoidArr;
typedef class GENERAL_API cList<LPCTSTR, LPCTSTR, 0>	LPCTSTRArr;
typedef class GENERAL_API cList<String>                 StringArr;
typedef class GENERAL_API cList<IDX, IDX, 0>			IDXArr;
typedef class GENERAL_API cList<uint8_t, uint8_t, 0>    Unsigned8Arr;
typedef class GENERAL_API cList<unsigned, unsigned, 0>  UnsignedArr;
typedef class GENERAL_API cList<uint32_t, uint32_t, 0>  Unsigned32Arr;
typedef class GENERAL_API cList<uint64_t, uint64_t, 0>  Unsigned64Arr;
typedef class GENERAL_API cList<size_t, size_t, 0>      SizeArr;
typedef class GENERAL_API cList<int, int, 0>            IntArr;
typedef class GENERAL_API cList<bool, bool, 0>          BoolArr;
typedef class GENERAL_API cList<float, float, 0>        FloatArr;
typedef class GENERAL_API cList<double, double, 0>      DoubleArr;

} // namespace SEACAVE

#include "Log.h"
#include "EventQueue.h"
#include "SML.h"
#include "ConfigTable.h"
#include "HTMLDoc.h"


// D E F I N E S ///////////////////////////////////////////////////

//
// Constant defines

// everything went smooth
#define _OK					((HRESULT)0L)

// just reports no errors
#define _CANCEL				0x82000000

// general error message
#define _FAIL				0x82000001

// specific error messages
#define _CREATEAPI			0x82000002
#define _CREATEDEVICE		0x82000003
#define _CREATEBUFFER		0x82000004
#define _INVALIDPARAM		0x82000005
#define _INVALIDID			0x82000006
#define _BUFFERSIZE			0x82000007
#define _BUFFERLOCK			0x82000008
#define _NOTCOMPATIBLE		0x82000009
#define _OUTOFMEMORY		0x8200000a
#define _FILENOTFOUND		0x8200000b
#define _INVALIDFILE		0x8200000c
#define _NOSHADERSUPPORT	0x8200000d
#define _NOSERVERFOUND		0x8200000e
#define _WOULDBLOCK			0x8200000f

#ifndef SUCCEEDED
#define SUCCEEDED(hr)       (((HRESULT)(hr)) >= 0)
#endif
#ifndef FAILED
#define FAILED(hr)          (((HRESULT)(hr)) < 0)
#endif


// D E F I N E S ///////////////////////////////////////////////////

#define RGBA(r, g, b, a)	((DWORD)(((a) << 24) | ((r) << 16) | ((g) << 8) | (b)))
#define RGBC(clr)			(RGBA((BYTE)((clr).fR*255), (BYTE)((clr).fG*255), (BYTE)((clr).fB*255), (BYTE)((clr).fA*255)))
#define RGB24TO8(r,g,b)		((BYTE)((((WORD)r)*30+((WORD)g)*59+((WORD)b)*11)/100))
#define RGB24TO16(r,g,b)	((((WORD)(((BYTE)(r))>>3))<<11) | (((WORD)(((BYTE)(g))>>2))<<5) | ((WORD)(((BYTE)(b))>>3)))
#define RGB16TOR(rgb)		(((BYTE)(((WORD)(rgb))>>11))<<3)
#define RGB16TOG(rgb)		(((BYTE)((((WORD)(rgb))&0x07E0)>>5))<<2)
#define RGB16TOB(rgb)		(((BYTE)(((WORD)(rgb))&0x001F))<<3)

#define TIMER_START()		SEACAVE::Timer::SysType timerStart = SEACAVE::Timer::GetSysTime()
#define TIMER_UPDATE()		timerStart = SEACAVE::Timer::GetSysTime()
#define TIMER_GET()			SEACAVE::Timer::SysTime2TimeMs(SEACAVE::Timer::GetSysTime() - timerStart)
#define TIMER_GET_INT()		((SEACAVE::Timer::SysType)TIMER_GET())
#define TIMER_GET_FORMAT()	SEACAVE::Util::formatTime(TIMER_GET_INT())


// D E F I N E S ///////////////////////////////////////////////////

#ifndef CHECK
#define CHECK(exp)			{ if (!(exp)) { VERBOSE("Check failed: " #exp); abort(); } }
#endif
#ifndef ABORT
#define ABORT(msg)			{ VERBOSE("error: " #msg); exit(-1); }
#endif

#ifndef _USE_MATH_DEFINES
/** e */
#ifndef M_E
#define M_E			2.7182818284590452353602874713527
#endif
/** ln(2) */
#ifndef M_LN2
#define M_LN2		0.69314718055994530941723212145818
#endif
/** ln(10) */
#ifndef M_LN10
#define M_LN10		2.3025850929940456840179914546844
#endif
/** pi */
#ifndef M_PI
#define M_PI		3.1415926535897932384626433832795
#endif
/** pi/2 */
#ifndef M_PI_2
#define M_PI_2		1.5707963267948966192313216916398
#endif
/** 1/pi */
#ifndef M_1_PI
#define M_1_PI		0.31830988618379067153776752674503
#endif
/** 2/pi */
#ifndef M_2_PI
#define M_2_PI		0.63661977236758134307553505349006
#endif
/** 2*sqrt(pi) */
#ifndef M_2_SQRTPI
#define M_2_SQRTPI	1.1283791670955125738961589031216
#endif
/** sqrt(2) */
#ifndef M_SQRT2
#define M_SQRT2		1.4142135623730950488016887242097
#endif
/** sqrt(1/2) */
#ifndef M_SQRT1_2
#define M_SQRT1_2	0.70710678118654752440084436210485
#endif
#endif

// constants
#define TWO_PI			6.283185307179586476925286766559
#define PI				3.1415926535897932384626433832795
#define HALF_PI			1.5707963267948966192313216916398
#define SQRT_2PI		2.506628274631000502415765284811
#define INV_TWO_PI		0.15915494309189533576888376337251
#define INV_PI			0.31830988618379067153776752674503
#define INV_HALF_PI		0.63661977236758134307553505349006
#define INV_SQRT_2PI	0.39894228040143267793994605993439
#define D2R(d)			((d)*(PI/180.0)) // degree to radian
#define R2D(r)			((r)*(180.0/PI)) // radian to degree
#define SQRT_2			1.4142135623730950488016887242097
#define SQRT_3			1.7320508075688772935274463415059
#define LOG_2			0.30102999566398119521373889472449
#define LN_2			0.69314718055994530941723212145818
#define ZERO_TOLERANCE	(1e-7)
#define INV_ZERO		(1e+14)

// float constants
#define FTWO_PI			((float)TWO_PI)
#define FPI				((float)PI)
#define FHALF_PI		((float)HALF_PI)
#define FSQRT_2PI		((float)SQRT_2PI)
#define FINV_TWO_PI		((float)INV_TWO_PI)
#define FINV_PI			((float)INV_PI)
#define FINV_HALF_PI	((float)INV_HALF_PI)
#define FINV_SQRT_2PI	((float)INV_SQRT_2PI)
#define FD2R(d)			((d)*(FPI/180.f)) // degree to radian
#define FR2D(r)			((r)*(180.f/FPI)) // radian to degree
#define FSQRT_2			((float)SQRT_2)
#define FSQRT_3			((float)SQRT_3)
#define FLOG_2			((float)LOG_2)
#define FLN_2			((float)LN_2)
#define FZERO_TOLERANCE	0.0001f
#define FINV_ZERO		1000000.f

#define GCLASS			unsigned
#define FRONT			0
#define BACK			1
#define PLANAR			2
#define CLIPPED			3
#define CULLED			4
#define VISIBLE			5


// M A C R O S /////////////////////////////////////////////////////

#define FLOOR			SEACAVE::Floor2Int
#define FLOOR2INT		SEACAVE::Floor2Int
#define CEIL			SEACAVE::Ceil2Int
#define CEIL2INT		SEACAVE::Ceil2Int
#define ROUND			SEACAVE::Round2Int
#define ROUND2INT		SEACAVE::Round2Int
#define SIN				std::sin
#define ASIN			std::asin
#define COS				std::cos
#define ACOS			std::acos
#define TAN				std::tan
#define ATAN			std::atan
#define ATAN2			std::atan2
#define POW				std::pow
#define POWI			SEACAVE::powi
#define LOG2I			SEACAVE::log2i


namespace SEACAVE {

// F U N C T I O N S ///////////////////////////////////////////////

template<typename T>
struct MakeIdentity { using type = T; };
template<typename T>
using MakeSigned = typename std::conditional<std::is_integral<T>::value,std::make_signed<T>,SEACAVE::MakeIdentity<T>>::type;

template<typename T1, typename T2>
constexpr T1 Cast(const T2& v) {
	return static_cast<T1>(v);
}

template<typename T>
constexpr T& NEGATE(T& a) {
	return (a = -a);
}
template<typename T>
constexpr T SQUARE(const T& a) {
	return a * a;
}
template<typename T>
constexpr T CUBE(const T& a) {
	return a * a * a;
}
template<typename T>
inline T SQRT(const T& a) {
	return T(sqrt(a));
}
template<typename T>
inline T EXP(const T& a) {
	return T(exp(a));
}
template<typename T>
inline T LOGN(const T& a) {
	return T(log(a));
}
template<typename T>
inline T LOG10(const T& a) {
	return T(log10(a));
}
template<typename T>
constexpr T powi(T base, unsigned exp) {
	T result(1);
	while (exp) {
		if (exp & 1)
			result *= base;
		exp >>= 1;
		base *= base;
	}
	return result;
}
constexpr int log2i(unsigned val) {
	int ret = -1;
	while (val) {
		val >>= 1;
		++ret;
	}
	return ret;
}
template <unsigned N> constexpr inline int log2i() { return 1+log2i<(N>>1)>(); }
template <>   constexpr inline int log2i<0>() { return -1; }
template <>   constexpr inline int log2i<1>() { return 0; }
template <>   constexpr inline int log2i<2>() { return 1; }

template<typename T>
inline T arithmeticSeries(T n, T a1=1, T d=1) {
	return (n*(a1*2+(n-1)*d))/2;
}
template<typename T>
constexpr T factorial(T n) {
	T ret = 1;
	while (n > 1)
		ret *= n--;
	return ret;
}
template<typename T>
constexpr T combinations(const T& n, const T& k) {
	ASSERT(n >= k);
	#if 1
	T num = n;
	const T den = factorial(k);
	for (T i=n-k+1; i<n; ++i)
		num *= i;
	ASSERT(num%den == 0);
	return num/den;
	#else
	return factorial(n) / (factorial(k)*factorial(n-k));
	#endif
}

// adapted from https://github.com/whackashoe/fastapprox.git
// (set bSafe to true if the values might be smaller than -126)
template<bool bSafe>
inline float FPOW2(float p) {
	if (bSafe && p < -126.f) {
		return 0.f;
	} else {
		ASSERT(p >= -126.f);
		CastF2I v;
		v.i = static_cast<int32_t>((1 << 23) * (p + 126.94269504f));
		return v.f;
	}
}
template<bool bSafe>
inline float FEXP(float v) {
	return FPOW2<bSafe>(1.44269504f * v);
}

// Inverse of the square root
// Compute a fast 1 / sqrtf(v) approximation
inline float RSQRT(float v) {
	#ifdef _FAST_INVSQRT
	// This code supposedly originates from Id-software
	const float halfV = v * 0.5f;
	(int32_t&)v = 0x5f3759df - (((int32_t&)v) >> 1);
	// Iterations of the Newton's method
	v = v * (1.5f - halfV * v * v);
	v = v * (1.5f - halfV * v * v);
	return v * (1.5f - halfV * v * v);
	#else
	return 1.f / SQRT(v);
	#endif
}
inline double RSQRT(const double& x) {
	#ifdef _FAST_INVSQRT
	double v = x;
	const double halfV = v * 0.5;
	(int64_t&)v = 0x5fe6ec85e7de30daLL - (((int64_t&)v) >> 1);
	// Iterations of the Newton's method
	v = v * (1.5 - halfV * v * v);
	v = v * (1.5 - halfV * v * v);
	v = v * (1.5 - halfV * v * v);
	return v * (1.5 - halfV * v * v);
	#else
	return 1.0 / SQRT(x);
	#endif
}

// approximate tanh
template <typename T>
inline T TANH(const T& x) {
	const T x2 = x*x;
	#if 0
	// Taylor series expansion (very inaccurate)
	return x*(1.0 + x2*(-T(1)/T(3) + x2*(T(2)/T(15) + x2*(-T(17)/T(315) + x2*(T(62)/T(2835) - x2*(T(1382)/T(155925)))))));
	#else
	// Lambert's continued fraction
	const T den = (((x2+T(378))*x2+T(17325))*x2+T(135135))*x;
	const T div = ((x2*T(28)+T(3150))*x2+T(62370))*x2+T(135135);
	return den/div;
	#endif
}
/*----------------------------------------------------------------*/


// Cubic root functions
// cube root approximation using bit hack for 32-bit float (5 decimals)
// (exploits the properties of IEEE 754 floating point numbers
// by leveraging the fact that their binary representation is close to a log2 representation)
inline float cbrt5(float x) {
	#if 0
	CastF2I c(x);
	c.i = ((c.i-(127<<23))/3+(127<<23));
	#else
	TAliasCast<float,uint32_t> c(x);
	c.i = c.i/3 + 709921077u;
	#endif
	return c.f;
}
// cube root approximation using bit hack for 64-bit float
// adapted from Kahan's cbrt (5 decimals)
inline double cbrt5(double x) {
	TAliasCast<double,uint32_t[2]> c(0.0), d(x);
	c.i[1] = d.i[1]/3 + 715094163u;
	return c.f;
}
// iterative cube root approximation using Halley's method
// faster convergence than Newton's method: (R/(a*a)+a*2)/3
template<typename T>
FORCEINLINE T cbrt_halley(const T& a, const T& R) {
	const T a3 = a*a*a;
	const T a3R = a3+R;
	return a * (a3R + R) / (a3 + a3R);
}
// fast cubic root (variable precision)
template<typename T, int N>
FORCEINLINE T fast_cbrt(const T& x) {
	return cbrt_halley(fast_cbrt<T,N-1>(x), x);
}
template<>
FORCEINLINE double fast_cbrt<double,1>(const double& x) {
	return cbrt_halley((double)cbrt5((float)x), x);
}
template<>
FORCEINLINE float fast_cbrt<float,1>(const float& x) {
	return cbrt_halley(cbrt5(x), x);
}
// default cubic root function
FORCEINLINE float CBRT(float x) {
	#ifdef _FAST_CBRT
	return fast_cbrt<float,1>(x);
	#else
	return POW(x, 1.0f/3.0f);
	#endif
}
FORCEINLINE double CBRT(const double& x) {
	#ifdef _FAST_CBRT
	return fast_cbrt<double,2>(x);
	#else
	return POW(x, 1.0/3.0);
	#endif
}
/*----------------------------------------------------------------*/


#if defined(__GNUC__)

FORCEINLINE int PopCnt(uint32_t bb) {
	return __builtin_popcount(bb);
}
FORCEINLINE int PopCnt(uint64_t bb) {
	return __builtin_popcountll(bb);
}
FORCEINLINE int PopCnt15(uint64_t bb) {
	return __builtin_popcountll(bb);
}
FORCEINLINE int PopCntSparse(uint64_t bb) {
	return __builtin_popcountll(bb);
}

#elif defined(_USE_SSE) && defined(_M_AMD64) // 64 bit windows

FORCEINLINE int PopCnt(uint32_t bb) {
	return (int)_mm_popcnt_u32(bb);
}
FORCEINLINE int PopCnt(uint64_t bb) {
	return (int)_mm_popcnt_u64(bb);
}
FORCEINLINE int PopCnt15(uint64_t bb) {
	return (int)_mm_popcnt_u64(bb);
}
FORCEINLINE int PopCntSparse(uint64_t bb) {
	return (int)_mm_popcnt_u64(bb);
}

#else

// general purpose population count
template<typename T>
constexpr int PopCnt(T bb)
{
	STATIC_ASSERT(std::is_integral<T>::value && std::is_unsigned<T>::value);
	return std::bitset<sizeof(T)*8>(bb).count();
}
template<>
inline int PopCnt(uint64_t bb) {
	const uint64_t k1 = (uint64_t)0x5555555555555555;
	const uint64_t k2 = (uint64_t)0x3333333333333333;
	const uint64_t k3 = (uint64_t)0x0F0F0F0F0F0F0F0F;
	const uint64_t k4 = (uint64_t)0x0101010101010101;
	bb -= (bb >> 1) & k1;
	bb = (bb & k2) + ((bb >> 2) & k2);
	bb = (bb + (bb >> 4)) & k3;
	return (bb * k4) >> 56;
}
// faster version assuming not more than 15 bits set, used in mobility
// eval, posted on CCC forum by Marco Costalba of Stockfish team
inline int PopCnt15(uint64_t bb) {
	unsigned w = unsigned(bb >> 32), v = unsigned(bb);
	v -= (v >> 1) & 0x55555555; // 0-2 in 2 bits
	w -= (w >> 1) & 0x55555555;
	v = ((v >> 2) & 0x33333333) + (v & 0x33333333); // 0-4 in 4 bits
	w = ((w >> 2) & 0x33333333) + (w & 0x33333333);
	v += w; // 0-8 in 4 bits
	v *= 0x11111111;
	return int(v >> 28);
}
// version faster on sparsely populated bitboards
inline int PopCntSparse(uint64_t bb) {
	int count = 0;
	while (bb) {
		count++;
		bb &= bb - 1;
	}
	return count;
}

#endif
/*----------------------------------------------------------------*/


#ifdef _FAST_FLOAT2INT
// fast float to int conversion
// (xs routines at stereopsis: http://www.stereopsis.com/sree/fpu2006.html by Sree Kotay)
const double _float2int_doublemagic         = 6755399441055744.0; //2^52 * 1.5, uses limited precision to floor
const double _float2int_doublemagicdelta    = (1.5e-8);
const double _float2int_doublemagicroundeps = (.5f-_float2int_doublemagicdelta); //almost .5f = .5f - 1e^(number of exp bit)
FORCEINLINE int CRound2Int(const double& x) {
	const CastD2I c(x + _float2int_doublemagic);
	ASSERT(int32_t(floor(x+.5)) == c.i);
	return c.i;
}
#endif
template <typename INTTYPE=int>
FORCEINLINE INTTYPE Floor2Int(float x) {
	#ifdef _FAST_FLOAT2INT
	return CRound2Int(double(x)-_float2int_doublemagicroundeps);
	#else
	return static_cast<INTTYPE>(floor(x));
	#endif
}
template <typename INTTYPE=int>
FORCEINLINE INTTYPE Floor2Int(double x) {
	#ifdef _FAST_FLOAT2INT
	return CRound2Int(x-_float2int_doublemagicroundeps);
	#else
	return static_cast<INTTYPE>(floor(x));
	#endif
}
template <typename INTTYPE=int>
FORCEINLINE INTTYPE Ceil2Int(float x) {
	#ifdef _FAST_FLOAT2INT
	return CRound2Int(double(x)+_float2int_doublemagicroundeps);
	#else
	return static_cast<INTTYPE>(ceil(x));
	#endif
}
template <typename INTTYPE=int>
FORCEINLINE INTTYPE Ceil2Int(double x) {
	#ifdef _FAST_FLOAT2INT
	return CRound2Int(x+_float2int_doublemagicroundeps);
	#else
	return static_cast<INTTYPE>(ceil(x));
	#endif
}
template <typename INTTYPE=int>
FORCEINLINE INTTYPE Round2Int(float x) {
	#ifdef _FAST_FLOAT2INT
	return CRound2Int(double(x)+_float2int_doublemagicdelta);
	#else
	return static_cast<INTTYPE>(floor(x+.5f));
	#endif
}
template <typename INTTYPE=int>
FORCEINLINE INTTYPE Round2Int(double x) {
	#ifdef _FAST_FLOAT2INT
	return CRound2Int(x+_float2int_doublemagicdelta);
	#else
	return static_cast<INTTYPE>(floor(x+.5));
	#endif
}
/*----------------------------------------------------------------*/


// INTERPOLATION

// Linear interpolation
inline float lerp(float u, float v, float x)
{
	return u + (v - u) * x;
}
template<typename Type>
inline Type lerp(const Type& u, const Type& v, float x)
{
	return u + (v - u) * x;
}

// Cubic interpolation
inline float cerp(float u0, float u1, float u2, float u3, float x)
{
	const float p((u3 - u2) - (u0 - u1));
	const float q((u0 - u1) - p);
	const float r(u2 - u0);
	return x * (x * (x * p + q) + r) + u1;
}
template<typename Type>
inline Type cerp(const Type& u0, const Type& u1, const Type& u2, const Type& u3, float x)
{
	const Type p((u3 - u2) - (u0 - u1));
	const Type q((u0 - u1) - p);
	const Type r(u2 - u0);
	return x * (x * (x * p + q) + r) + u1;
}
/*----------------------------------------------------------------*/


// S T R U C T S ///////////////////////////////////////////////////

#ifdef _USE_SSE

// define utile functions to deal with SSE operations

struct ALIGN(16) sse_vec4f {
	union {
		float v[4];
		struct {
			float x;
			float y;
			float z;
			float w;
		};
	};
	inline sse_vec4f() {}
	inline sse_vec4f(const float* p) : x(p[0]), y(p[1]), z(p[2]), w(p[3]) {}
	inline sse_vec4f(float f0, float f1, float f2, float f3) : x(f0), y(f1), z(f2), w(f3) {}
	inline operator const float*() const {return v;}
	inline operator float*() {return v;}
};

struct ALIGN(16) sse_vec2d {
	union {
		double v[2];
		struct {
			double x;
			double y;
		};
	};
	inline sse_vec2d() {}
	inline sse_vec2d(const double* p) : x(p[0]), y(p[1]) {}
	inline sse_vec2d(const double& f0, const double& f1) : x(f0), y(f1) {}
	inline operator const double*() const {return v;}
	inline operator double*() {return v;}
};

struct sse_f_t {
	typedef __m128 sse_t;
	typedef const sse_t& arg_sse_t;
	typedef float real_t;
	inline sse_f_t() {}
	inline sse_f_t(const sse_t& p) : v(p)        {}
	inline sse_f_t(real_t p) : v(load1(p))       {}
	inline sse_f_t(const real_t* p) : v(load(p)) {}
	inline sse_f_t(real_t f0, real_t f1, real_t f2, real_t f3) : v(set(f0,f1,f2,f3)) {}
	inline operator sse_t() const                {return v;}
	inline operator sse_t&()                     {return v;}
	inline sse_t operator ==(sse_t s) const      {return cmpeq(v,s);}
	inline sse_t operator =(sse_t s)             {return v=s;}
	inline sse_t operator +(sse_t s) const       {return add(v,s);}
	inline sse_t operator +=(sse_t s)            {return v=add(v,s);}
	inline sse_t operator -(sse_t s) const       {return sub(v,s);}
	inline sse_t operator -=(sse_t s)            {return v=sub(v,s);}
	inline sse_t operator *(sse_t s) const       {return mul(v,s);}
	inline sse_t operator *=(sse_t s)            {return v=mul(v,s);}
	inline sse_t operator /(sse_t s) const       {return div(v,s);}
	inline sse_t operator /=(sse_t s)            {return v=div(v,s);}
	inline void get(real_t* p) const             {store(p,v);}
	static inline sse_t zero()                   {return _mm_setzero_ps();}
	static inline sse_t load1(real_t p)          {return _mm_load1_ps(&p);}
	static inline sse_t load(const real_t* p)    {return _mm_load_ps(p);}
	static inline sse_t loadu(const real_t* p)   {return _mm_loadu_ps(p);}
	static inline sse_t set(real_t f0, real_t f1, real_t f2, real_t f3) {return _mm_set_ps(f0,f1,f2,f3);}
	static inline void  store(real_t *p, sse_t s){_mm_store_ps(p,s);}
	static inline void  storeu(real_t *p, sse_t s){_mm_storeu_ps(p,s);}
	static inline sse_t add(sse_t s1, sse_t s2)  {return _mm_add_ps(s1,s2);}
	static inline sse_t sub(sse_t s1, sse_t s2)  {return _mm_sub_ps(s1,s2);}
	static inline sse_t mul(sse_t s1, sse_t s2)  {return _mm_mul_ps(s1,s2);}
	static inline sse_t div(sse_t s1, sse_t s2)  {return _mm_div_ps(s1,s2);}
	static inline sse_t min(sse_t s1, sse_t s2)  {return _mm_min_ps(s1,s2);}
	static inline sse_t max(sse_t s1, sse_t s2)  {return _mm_max_ps(s1,s2);}
	static inline sse_t cmpeq(sse_t s1, sse_t s2){return _mm_cmpeq_ps(s1,s2);}
	static inline sse_t sqrt(sse_t s)            {return _mm_sqrt_ps(s);}
	static inline sse_t rsqrt(sse_t s)           {return _mm_rsqrt_ps(s);}
	static inline int floor2int(real_t f)        {return _mm_cvtt_ss2si(_mm_load_ss(&f));}
	#ifdef _WIN32
	static inline real_t sum(sse_t s)            {return (s.m128_f32[0]+s.m128_f32[2])+(s.m128_f32[1]+s.m128_f32[3]);}
	static inline real_t sum3(sse_t s)           {return (s.m128_f32[0]+s.m128_f32[2])+s.m128_f32[1];}
	#else
	static inline real_t sum(sse_t s)            {real_t *f = (real_t*)(&s); return (f[0]+f[2])+(f[1]+f[3]);}
	static inline real_t sum3(sse_t s)           {real_t *f = (real_t*)(&s); return (f[0]+f[2])+f[1];}
	#endif
	/*
	static inline real_t dot(sse_t s1, sse_t s2) {
		sse_t temp = _mm_dp_ps(s1, s2, 0xF1);
		real_t* f = (real_t*)(&temp); return f[0];
	}
	*/
	static real_t dot(const real_t* a, const real_t* b, size_t size) {
		const real_t* const end = a+size;
		const size_t iters = (size>>2);
		real_t fres = 0.f;
		if (iters) {
			const real_t* const e = a+(iters<<2);
			sse_t mres = zero();
			do {
				mres = _mm_add_ps(mres, _mm_mul_ps(_mm_loadu_ps(a), _mm_loadu_ps(b)));
				a += 4; b += 4;
			} while (a < e);
			fres = sum(mres);
		}
		while (a<end)
			fres += (*a++) * (*b++);
		return fres;
	}
	sse_t v;
};

class sse_d_t {
public:
	typedef __m128d sse_t;
	typedef double real_t;
	inline sse_d_t() {}
	inline sse_d_t(const sse_t& p) : v(p)        {}
	inline sse_d_t(const real_t& p) : v(load1(p)){}
	inline sse_d_t(const real_t* p) : v(load(p)) {}
	inline sse_d_t(const real_t& f0, const real_t& f1) : v(set(f0,f1)) {}
	inline operator sse_t() const                {return v;}
	inline operator sse_t&()                     {return v;}
	inline sse_t operator ==(sse_t s) const      {return cmpeq(v,s);}
	inline sse_t operator =(sse_t s)             {return v=s;}
	inline sse_t operator +(sse_t s) const       {return add(v,s);}
	inline sse_t operator +=(sse_t s)            {return v=add(v,s);}
	inline sse_t operator -(sse_t s) const       {return sub(v,s);}
	inline sse_t operator -=(sse_t s)            {return v=sub(v,s);}
	inline sse_t operator *(sse_t s) const       {return mul(v,s);}
	inline sse_t operator *=(sse_t s)            {return v=mul(v,s);}
	inline sse_t operator /(sse_t s) const       {return div(v,s);}
	inline sse_t operator /=(sse_t s)            {return v=div(v,s);}
	inline void get(real_t* p) const             {store(p,v);}
	static inline sse_t zero()                   {return _mm_setzero_pd();}
	static inline sse_t load1(const real_t& p)   {return _mm_load1_pd(&p);}
	static inline sse_t load(const real_t* p)    {return _mm_load_pd(p);}
	static inline sse_t loadu(const real_t* p)   {return _mm_loadu_pd(p);}
	static inline sse_t set(const real_t& f0, const real_t& f1) {return _mm_set_pd(f0,f1);}
	static inline void  store(real_t *p, sse_t s){_mm_store_pd(p,s);}
	static inline void  storeu(real_t *p, sse_t s){_mm_storeu_pd(p,s);}
	static inline sse_t add(sse_t s1, sse_t s2)  {return _mm_add_pd(s1,s2);}
	static inline sse_t sub(sse_t s1, sse_t s2)  {return _mm_sub_pd(s1,s2);}
	static inline sse_t mul(sse_t s1, sse_t s2)  {return _mm_mul_pd(s1,s2);}
	static inline sse_t div(sse_t s1, sse_t s2)  {return _mm_div_pd(s1,s2);}
	static inline sse_t min(sse_t s1, sse_t s2)  {return _mm_min_pd(s1,s2);}
	static inline sse_t max(sse_t s1, sse_t s2)  {return _mm_max_pd(s1,s2);}
	static inline sse_t cmpeq(sse_t s1, sse_t s2){return _mm_cmpeq_pd(s1,s2);}
	static inline sse_t sqrt(sse_t s)            {return _mm_sqrt_pd(s);}
	static inline int floor2int(const real_t& f) {return _mm_cvttsd_si32(_mm_load_sd(&f));}
	#ifdef _WIN32
	static inline real_t sum(sse_t s)            {return s.m128d_f64[0]+s.m128d_f64[1];}
	#else
	static inline real_t sum(sse_t s)            {real_t *d = (real_t*)(&s); return d[0]+d[1];}
	#endif
	/*
	static inline real_t dot(sse_t s1, sse_t s2) {
		sse_t temp = _mm_dp_pd(s1, s2, 0x31);
		real_t* f = (real_t*)(&temp); return f[0] ;
	}
	*/
	static real_t dot(const real_t* a, const real_t* b, size_t size) {
		const real_t* const end = a+size;
		const size_t iters = (size>>1);
		real_t fres = 0.0;
		if (iters) {
			const real_t* const e = a+(iters<<1);
			sse_t mres = zero();
			do {
				mres = _mm_add_pd(mres, _mm_mul_pd(_mm_loadu_pd(a), _mm_loadu_pd(b)));
				a += 2; b += 2;
			} while (a < e);
			fres = sum(mres);
		}
		while (a<end)
			fres += (*a++) * (*b++);
		return fres;
	}
	sse_t v;
};

inline void sse_prefetch(const void* p) {_mm_prefetch((const char*)p, _MM_HINT_NTA);}

#endif


// C L A S S E S ///////////////////////////////////////////////////

inline bool   ISINFORNAN(float x)			{ return std::isinf(x) || std::isnan(x); }
inline bool   ISINFORNAN(double x)			{ return std::isinf(x) || std::isnan(x); }
inline bool   ISFINITE(float x)				{ return std::isfinite(x); }
inline bool   ISFINITE(double x)			{ return std::isfinite(x); }
template<typename _Tp>
inline bool   ISFINITE(const _Tp* x, size_t n)	{ for (size_t i=0; i<n; ++i) if (ISINFORNAN(x[i])) return false; return true; }

template<typename _Tp>
inline bool   ISINSIDE(_Tp v,_Tp l0,_Tp l1)	{ ASSERT(l0<l1); return l0 <= v && v < l1; }
template<typename _Tp>
inline bool   ISINSIDES(_Tp v,_Tp l0,_Tp l1)	{ return l0 < l1 ? ISINSIDE(v, l0, l1) : ISINSIDE(v, l1, l0); }

template<typename _Tp>
inline _Tp    CLAMP(_Tp v, _Tp l0, _Tp l1)	{ ASSERT(l0<=l1); return MINF(MAXF(v, l0), l1); }
template<typename _Tp>
inline _Tp    CLAMPS(_Tp v, _Tp l0, _Tp l1)	{ return l0 <= l1 ? CLAMP(v, l0, l1) : CLAMP(v, l1, l0); }

template<typename _Tp>
inline _Tp    SIGN(_Tp x)					{ if (x > _Tp(0)) return _Tp(1); if (x < _Tp(0)) return _Tp(-1); return _Tp(0); }

template<typename _Tp>
inline _Tp    ABS(_Tp    x)					{ return std::abs(x); }

template<typename _Tp>
constexpr _Tp    ZEROTOLERANCE()			{ return _Tp(0); }
template<>
constexpr float  ZEROTOLERANCE()			{ return FZERO_TOLERANCE; }
template<>
constexpr double ZEROTOLERANCE()			{ return ZERO_TOLERANCE; }

template<typename _Tp>
constexpr _Tp    EPSILONTOLERANCE()			{ return std::numeric_limits<_Tp>::epsilon(); }
template<>
constexpr float  EPSILONTOLERANCE()			{ return 0.00001f; }
template<>
constexpr double EPSILONTOLERANCE()			{ return 1e-10; }

inline bool   ISZERO(float  x)				{ return ABS(x) < FZERO_TOLERANCE; }
inline bool   ISZERO(double x)				{ return ABS(x) < ZERO_TOLERANCE; }

inline bool   ISEQUAL(float  x, float  v)	{ return ABS(x-v) < FZERO_TOLERANCE; }
inline bool   ISEQUAL(double x, double v)	{ return ABS(x-v) < ZERO_TOLERANCE; }

inline float  INVZERO(float)				{ return FINV_ZERO; }
inline double INVZERO(double)				{ return INV_ZERO; }
template<typename _Tp>
inline _Tp    INVZERO(_Tp)					{ return std::numeric_limits<_Tp>::max(); }

template<typename _Tp>
inline _Tp    INVERT(_Tp    x)				{ return (x==_Tp(0) ? INVZERO(x) : _Tp(1)/x); }

template<typename _Tp>
inline _Tp    SAFEDIVIDE(_Tp   x, _Tp   y)	{ return (y==_Tp(0) ? INVZERO(y) : x/y); }
/*----------------------------------------------------------------*/

} // namespace SEACAVE


#include "Random.h"
#include "HalfFloat.h"


namespace SEACAVE {

// P R O T O T Y P E S /////////////////////////////////////////////

template <typename TYPE, int m, int n> class TMatrix;
template <typename TYPE, int DIMS> class TAABB;
template <typename TYPE, int DIMS> class TRay;
template <typename TYPE, int DIMS> class TPlane;

// 2D point struct
template <typename TYPE>
class TPoint2 : public cv::Point_<TYPE>
{
public:
	typedef TYPE Type;
	typedef cv::Point_<TYPE> Base;
	typedef cv::Size Size;
	typedef cv::Vec<TYPE,2> cvVec;
	typedef cv::Matx<TYPE,2,1> Vec;
	typedef cv::Matx<TYPE,1,2> VecT;
	#ifdef _USE_EIGEN
	EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(TYPE,2)
	typedef Eigen::Matrix<TYPE,2,1> EVec;
	typedef Eigen::Map<const EVec> CEVecMap;
	typedef Eigen::Map<EVec> EVecMap;
	#endif

	using Base::x;
	using Base::y;

	static const TPoint2 ZERO;
	static const TPoint2 INF;

public:
	inline TPoint2() {}
	inline TPoint2(const Size& rhs) : Base(rhs) {}
	template <typename T> inline TPoint2(const cv::Point_<T>& rhs) : Base((Type)rhs.x,(Type)rhs.y) {}
	template <typename T> inline TPoint2(const cv::Matx<T,2,1>& rhs) : Base(rhs(0),rhs(1)) {}
	template <typename T> inline TPoint2(const cv::Matx<T,1,2>& rhs) : Base(rhs(0),rhs(1)) {}
	#ifdef _USE_EIGEN
	inline TPoint2(const EVec& rhs) { operator EVecMap () = rhs; }
	#endif
	explicit inline TPoint2(const TYPE& _x) : Base(_x,_x) {}
	inline TPoint2(const TYPE& _x, const TYPE& _y) : Base(_x,_y) {}
	explicit inline TPoint2(const cv::Point3_<TYPE>& pt) : Base(pt.x/pt.z,pt.y/pt.z) {}

	template <typename T> inline TPoint2& operator = (const cv::Point_<T>& rhs) { Base::operator = (rhs); return *this; }
	template <typename T> inline TPoint2& operator = (const cv::Matx<T,2,1>& rhs) { operator Vec& () = rhs; return *this; }
	template <typename T> inline TPoint2& operator = (const cv::Matx<T,1,2>& rhs) { operator VecT& () = rhs; return *this; }
	#ifdef _USE_EIGEN
	inline TPoint2& operator = (const EVec& rhs) { operator EVecMap () = rhs; return *this; }
	#endif

	// conversion to another data type
	template <typename T> inline operator TPoint2<T> () const { return TPoint2<T>((T)x,(T)y); }

	// pointer to the first element access
	inline const TYPE* ptr() const { return &x; }
	inline TYPE* ptr() { return &x; }

	// 1D element access
	inline const TYPE& operator [](size_t i) const { ASSERT(i>=0 && i<2); return ptr()[i]; }
	inline TYPE& operator [](size_t i) { ASSERT(i>=0 && i<2); return ptr()[i]; }

	// Access point as Size equivalent
	inline operator const Size& () const { return *((const Size*)this); }
	inline operator Size& () { return *((Size*)this); }

	// Access point as vector equivalent
	inline operator const Vec& () const { return *((const Vec*)this); }
	inline operator Vec& () { return *((Vec*)this); }

	// Access point as transposed vector equivalent
	inline operator const VecT& () const { return *((const VecT*)this); }
	inline operator VecT& () { return *((VecT*)this); }

	#ifdef _USE_EIGEN
	// Access point as Eigen equivalent
	inline operator EVec () const { return CEVecMap((const TYPE*)this); }
	// Access point as Eigen::Map equivalent
	inline operator const CEVecMap () const { return CEVecMap((const TYPE*)this); }
	inline operator EVecMap () { return EVecMap((TYPE*)this); }
	#endif

	#ifdef _USE_BOOST
	// serialize
	template <class Archive>
	void serialize(Archive& ar, const unsigned int /*version*/) {
		ar & boost::serialization::base_object<Base>(*this);
	}
	#endif
};
template <typename TYPE> const TPoint2<TYPE> TPoint2<TYPE>::ZERO(0,0);
template <typename TYPE> const TPoint2<TYPE> TPoint2<TYPE>::INF(std::numeric_limits<TYPE>::infinity(),std::numeric_limits<TYPE>::infinity());
/*----------------------------------------------------------------*/
typedef TPoint2<int> Point2i;
typedef TPoint2<hfloat> Point2hf;
typedef TPoint2<float> Point2f;
typedef TPoint2<double> Point2d;
/*----------------------------------------------------------------*/


// 3D point struct
template <typename TYPE>
class TPoint3 : public cv::Point3_<TYPE>
{
public:
	typedef TYPE Type;
	typedef cv::Point3_<TYPE> Base;
	typedef cv::Vec<TYPE,3> cvVec;
	typedef cv::Matx<TYPE,3,1> Vec;
	typedef cv::Matx<TYPE,1,3> VecT;
	#ifdef _USE_EIGEN
	EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(TYPE,3)
	typedef Eigen::Matrix<TYPE,3,1> EVec;
	typedef Eigen::Map<const EVec> CEVecMap;
	typedef Eigen::Map<EVec> EVecMap;
	#endif

	using Base::x;
	using Base::y;
	using Base::z;

	static const TPoint3 ZERO;
	static const TPoint3 INF;

public:
	inline TPoint3() {}
	template <typename T> inline TPoint3(const cv::Point3_<T>& rhs) : Base((Type)rhs.x,(Type)rhs.y,(Type)rhs.z) {}
	template <typename T> inline TPoint3(const cv::Matx<T,3,1>& rhs) : Base(rhs(0),rhs(1),rhs(2)) {}
	template <typename T> inline TPoint3(const cv::Matx<T,1,3>& rhs) : Base(rhs(0),rhs(1),rhs(2)) {}
	#ifdef _USE_EIGEN
	inline TPoint3(const EVec& rhs) { operator EVecMap () = rhs; }
	#endif
	explicit inline TPoint3(const TYPE& _x) : Base(_x,_x,_x) {}
	inline TPoint3(const TYPE& _x, const TYPE& _y, const TYPE& _z) : Base(_x,_y,_z) {}
	template <typename T> inline TPoint3(const cv::Point_<T>& pt, const T& _z=T(1)) : Base(pt.x,pt.y,_z) {}
	template <typename T1, typename T2> inline TPoint3(const cv::Point_<T1>& pt, const T2& _z) : Base(pt.x,pt.y,_z) {}

	template <typename T> inline TPoint3& operator = (const cv::Point3_<T>& rhs)  { Base::operator = (rhs); return *this; }
	template <typename T> inline TPoint3& operator = (const cv::Matx<T,3,1>& rhs)  { operator Vec& () = rhs; return *this; }
	template <typename T> inline TPoint3& operator = (const cv::Matx<T,1,3>& rhs)  { operator VecT& () = rhs; return *this; }
	#ifdef _USE_EIGEN
	inline TPoint3& operator = (const EVec& rhs) { operator EVecMap () = rhs; return *this; }
	#endif

	// conversion to another data type
	template <typename T> inline operator TPoint3<T> () const { return TPoint3<T>((T)x,(T)y,(T)z); }

	// pointer to the first element access
	inline const TYPE* ptr() const { return &x; }
	inline TYPE* ptr() { return &x; }

	// 1D element access
	inline const TYPE& operator [](BYTE i) const { ASSERT(i<3); return ptr()[i]; }
	inline TYPE& operator [](BYTE i) { ASSERT(i<3); return ptr()[i]; }

	// Access point as vector equivalent
	inline operator const Vec& () const { return *reinterpret_cast<const Vec*>(this); }
	inline operator Vec& () { return *reinterpret_cast<Vec*>(this); }

	// Access point as transposed vector equivalent
	inline operator const VecT& () const { return *reinterpret_cast<const VecT*>(this); }
	inline operator VecT& () { return *reinterpret_cast<VecT*>(this); }

	#ifdef _USE_EIGEN
	// Access point as Eigen equivalent
	inline operator EVec () const { return CEVecMap((const TYPE*)this); }
	// Access point as Eigen::Map equivalent
	inline operator const EVecMap () const { return CEVecMap((const TYPE*)this); }
	inline operator EVecMap () { return EVecMap((TYPE*)this); }
	#endif

	// rotate point using the given parametrized rotation (axis-angle)
	inline void RotateAngleAxis(const TPoint3& rot) { return (*this) = RotateAngleAxis((*this), rot); }
	static TPoint3 RotateAngleAxis(const TPoint3& X, const TPoint3& rot);

	#ifdef _USE_BOOST
	// serialize
	template <class Archive>
	void serialize(Archive& ar, const unsigned int /*version*/) {
		ar & boost::serialization::base_object<Base>(*this);
	}
	#endif
};
template <typename TYPE> const TPoint3<TYPE> TPoint3<TYPE>::ZERO(0,0,0);
template <typename TYPE> const TPoint3<TYPE> TPoint3<TYPE>::INF(std::numeric_limits<TYPE>::infinity(),std::numeric_limits<TYPE>::infinity(),std::numeric_limits<TYPE>::infinity());
/*----------------------------------------------------------------*/
typedef TPoint3<int> Point3i;
typedef TPoint3<hfloat> Point3hf;
typedef TPoint3<float> Point3f;
typedef TPoint3<double> Point3d;
/*----------------------------------------------------------------*/


// matrix struct
template <typename TYPE, int m, int n>
class TMatrix : public cv::Matx<TYPE,m,n>
{
public:
	typedef TYPE Type;
	typedef cv::Matx<TYPE,m,n> Base;
	typedef cv::Vec<TYPE,m> Vec;
	#ifdef _USE_EIGEN
	EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(TYPE,m*n)
	typedef Eigen::Matrix<TYPE,m,n,(n>1?Eigen::RowMajor:Eigen::Default)> EMat;
	typedef Eigen::Map<const EMat> CEMatMap;
	typedef Eigen::Map<EMat> EMatMap;
	#endif

	using Base::val;
	using Base::channels;

	enum { elems = m*n };

	static const TMatrix ZERO;
	static const TMatrix IDENTITY;
	static const TMatrix INF;

public:
	inline TMatrix() {}
	template <typename T> inline TMatrix(const cv::Matx<T,m,n>& rhs) : Base(rhs) {}
	template <typename T> inline TMatrix(const cv::Point_<T>& rhs) : Base(rhs.x, rhs.y) {}
	template <typename T> inline TMatrix(const cv::Point3_<T>& rhs) : Base(rhs.x, rhs.y, rhs.z) {}
	inline TMatrix(const cv::Mat& rhs) : Base(rhs) {}
	#ifdef _USE_EIGEN
	inline TMatrix(const EMat& rhs) { operator EMatMap () = rhs; }
	#endif

	TMatrix(TYPE v0); //!< 1x1 matrix
	TMatrix(TYPE v0, TYPE v1); //!< 1x2 or 2x1 matrix
	TMatrix(TYPE v0, TYPE v1, TYPE v2); //!< 1x3 or 3x1 matrix
	TMatrix(TYPE v0, TYPE v1, TYPE v2, TYPE v3); //!< 1x4, 2x2 or 4x1 matrix
	TMatrix(TYPE v0, TYPE v1, TYPE v2, TYPE v3, TYPE v4); //!< 1x5 or 5x1 matrix
	TMatrix(TYPE v0, TYPE v1, TYPE v2, TYPE v3, TYPE v4, TYPE v5); //!< 1x6, 2x3, 3x2 or 6x1 matrix
	TMatrix(TYPE v0, TYPE v1, TYPE v2, TYPE v3, TYPE v4, TYPE v5, TYPE v6); //!< 1x7 or 7x1 matrix
	TMatrix(TYPE v0, TYPE v1, TYPE v2, TYPE v3, TYPE v4, TYPE v5, TYPE v6, TYPE v7); //!< 1x8, 2x4, 4x2 or 8x1 matrix
	TMatrix(TYPE v0, TYPE v1, TYPE v2, TYPE v3, TYPE v4, TYPE v5, TYPE v6, TYPE v7, TYPE v8); //!< 1x9, 3x3 or 9x1 matrix
	TMatrix(TYPE v0, TYPE v1, TYPE v2, TYPE v3, TYPE v4, TYPE v5, TYPE v6, TYPE v7, TYPE v8, TYPE v9); //!< 1x10, 2x5 or 5x2 or 10x1 matrix
	TMatrix(TYPE v0, TYPE v1, TYPE v2, TYPE v3,
		TYPE v4, TYPE v5, TYPE v6, TYPE v7,
		TYPE v8, TYPE v9, TYPE v10, TYPE v11); //!< 1x12, 2x6, 3x4, 4x3, 6x2 or 12x1 matrix
	TMatrix(TYPE v0, TYPE v1, TYPE v2, TYPE v3,
		TYPE v4, TYPE v5, TYPE v6, TYPE v7,
		TYPE v8, TYPE v9, TYPE v10, TYPE v11,
		TYPE v12, TYPE v13); //!< 1x14, 2x7, 7x2 or 14x1 matrix
	TMatrix(TYPE v0, TYPE v1, TYPE v2, TYPE v3,
		TYPE v4, TYPE v5, TYPE v6, TYPE v7,
		TYPE v8, TYPE v9, TYPE v10, TYPE v11,
		TYPE v12, TYPE v13, TYPE v14, TYPE v15); //!< 1x16, 4x4 or 16x1 matrix
	explicit TMatrix(const TYPE* vals); //!< initialize from a plain array

	TMatrix(const TMatrix<TYPE,m,n>& a, const TMatrix<TYPE,m,n>& b, cv::Matx_AddOp) : Base(a, b, cv::Matx_AddOp()) {}
	TMatrix(const TMatrix<TYPE,m,n>& a, const TMatrix<TYPE,m,n>& b, cv::Matx_SubOp) : Base(a, b, cv::Matx_SubOp()) {}
	template<typename TYPE2> TMatrix(const TMatrix<TYPE,m,n>& a, TYPE2 alpha, cv::Matx_ScaleOp) : Base(a, alpha, cv::Matx_ScaleOp()) {}
	TMatrix(const TMatrix<TYPE,m,n>& a, const TMatrix<TYPE,m,n>& b, cv::Matx_MulOp) : Base(a, b, cv::Matx_MulOp()) {}
	TMatrix(const TMatrix<TYPE,m,n>& a, const TMatrix<TYPE,m,n>& b, cv::Matx_DivOp) : Base(a, b, cv::Matx_DivOp()) {}
	template<int l> TMatrix(const TMatrix<TYPE,m,l>& a, const TMatrix<TYPE,l,n>& b, cv::Matx_MatMulOp) : Base(a, b, cv::Matx_MatMulOp()) {}
	TMatrix(const TMatrix<TYPE,n,m>& a, cv::Matx_TOp) : Base(a, cv::Matx_TOp()) {}

	template <typename T> inline TMatrix& operator = (const cv::Matx<T,m,n>& rhs) { Base::operator = (rhs); return *this; }
	inline TMatrix& operator = (const cv::Mat& rhs) { Base::operator = (rhs); return *this; }
	#ifdef _USE_EIGEN
	inline TMatrix& operator = (const EMat& rhs) { operator EMatMap () = rhs; return *this; }
	#endif

	inline bool IsEqual(const Base&) const;
	inline bool IsEqual(const Base&, TYPE eps) const;

	// 1D element access
	inline const TYPE& operator [](size_t i) const { ASSERT(i<elems); return val[i]; }
	inline TYPE& operator [](size_t i) { ASSERT(i<elems); return val[i]; }

	// Access point as vector equivalent
	inline operator const Vec& () const { return *reinterpret_cast<const Vec*>(this); }
	inline operator Vec& () { return *reinterpret_cast<Vec*>(this); }

	#ifdef _USE_EIGEN
	// Access point as Eigen equivalent
	inline operator EMat () const { return CEMatMap((const TYPE*)val); }
	// Access point as Eigen::Map equivalent
	inline operator CEMatMap() const { return CEMatMap((const TYPE*)val); }
	inline operator EMatMap () { return EMatMap((TYPE*)val); }
	#endif

	// calculate right null-space of this matrix ([n,n-m])
	inline TMatrix<TYPE,n,n-m> RightNullSpace(int flags = 0) const;
	// calculate right/left null-vector of this matrix ([n/m,1])
	inline TMatrix<TYPE,n,1> RightNullVector(int flags = 0) const;
	inline TMatrix<TYPE,m,1> LeftNullVector(int flags = 0) const;

	#ifdef _USE_BOOST
	// serialize
	template <class Archive>
	void serialize(Archive& ar, const unsigned int /*version*/) {
		ar & boost::serialization::base_object<Base>(*this);
	}
	#endif
};
template <typename TYPE, int m, int n> const TMatrix<TYPE,m,n> TMatrix<TYPE,m,n>::ZERO(TMatrix::zeros());
template <typename TYPE, int m, int n> const TMatrix<TYPE,m,n> TMatrix<TYPE,m,n>::IDENTITY(TMatrix::eye());
template <typename TYPE, int m, int n> const TMatrix<TYPE,m,n> TMatrix<TYPE,m,n>::INF(TMatrix::all(std::numeric_limits<TYPE>::infinity()));
/*----------------------------------------------------------------*/


// generic matrix struct
template <typename TYPE>
class TDMatrix : public cv::Mat_<TYPE>
{
public:
	typedef TYPE Type;
	typedef cv::Mat_<TYPE> Base;
	typedef cv::Size Size;
	#ifdef _USE_EIGEN
	typedef Eigen::Matrix<TYPE,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor> EMat;
	typedef Eigen::Map<const EMat> CEMatMap;
	typedef Eigen::Map<EMat> EMatMap;
	#endif

	using Base::rows;
	using Base::cols;
	using Base::data;
	using Base::step;
	using Base::dims;

public:
	inline TDMatrix() {}
	inline TDMatrix(const Base& rhs) : Base(rhs) {}
	inline TDMatrix(const cv::Mat& rhs) : Base(rhs) {}
	inline TDMatrix(const cv::MatExpr& rhs) : Base(rhs) {}
	inline TDMatrix(int _rows, int _cols) : Base(_rows, _cols) {}
	inline TDMatrix(int _rows, int _cols, TYPE* _data, size_t _step=Base::AUTO_STEP) : Base(_rows, _cols, _data, _step) {}
	inline TDMatrix(const Size& sz) : Base(sz) {}
	inline TDMatrix(const Size& sz, const TYPE& v) : Base(sz, v) {}
	inline TDMatrix(const Size& sz, TYPE* _data, size_t _step=Base::AUTO_STEP) : Base(sz.height, sz.width, _data, _step) {}
	#ifdef _USE_EIGEN
	inline TDMatrix(const EMat& rhs) { operator EMatMap () = rhs; }
	#endif

	inline TDMatrix& operator = (const Base& rhs) { Base::operator=(rhs); return *this; }
	inline TDMatrix& operator = (const cv::MatExpr& rhs) { Base::operator=(rhs); return *this; }
	#ifdef _USE_EIGEN
	inline TDMatrix& operator = (const EMat& rhs) { operator EMatMap () = rhs; return *this; }
	#endif

	/// Construct the 2D matrix with the desired size and init its elements
	inline void construct(int _rows, int _cols) {
		Base::create(_rows, _cols);
		for (int i=0; i<rows; ++i)
			for (int j=0; j<cols; ++j)
				new(cv::Mat::ptr<TYPE>(i,j)) TYPE;
	}
	inline void construct(const Size& sz) { construct(sz.height, sz.width); }
	inline void destroy() {
		for (int i=0; i<rows; ++i)
			for (int j=0; j<cols; ++j)
				cv::Mat::ptr<TYPE>(i,j)->~TYPE();
	}

	/// Set all elements to the given value
	inline void memset(uint8_t v) { ASSERT(dims == 2 && cv::Mat::isContinuous()); ::memset(data, v, row_stride()*rows); }
	inline void fill(const TYPE& v) { ASSERT(dims == 2); for (int i=0; i<rows; ++i) for (int j=0; j<cols; ++j) cv::Mat::at<TYPE>(i,j) = v; }

	/// What is the row stride of the matrix?
	inline size_t row_stride() const { ASSERT(dims == 2); return step[0]; }
	/// What is the elem stride of the matrix?
	inline size_t elem_stride() const { ASSERT(dims == 2 && step[1] == sizeof(TYPE)); return step[1]; }
	/// Compute the area of the 2D matrix
	inline int area() const { ASSERT(dims == 2); return cols*rows; }

	/// Is this coordinate inside the 2D matrix?
	template <typename T>
	static inline typename std::enable_if<std::is_integral<T>::value,bool>::type isInside(const cv::Point_<T>& pt, const cv::Size& size) {
		return pt.x>=T(0) && pt.y>=T(0) && pt.x<T(size.width) && pt.y<T(size.height);
	}
	template <typename T>
	static inline typename std::enable_if<std::is_floating_point<T>::value,bool>::type isInside(const cv::Point_<T>& pt, const cv::Size& size) {
		return pt.x>=T(0) && pt.y>=T(0) && pt.x<=T(size.width) && pt.y<=T(size.height);
	}
	template <typename T>
	inline bool isInside(const cv::Point_<T>& pt) const {
		return isInside<T>(pt, Base::size());
	}

	/// Is this coordinate inside the 2D matrix, and not too close to the edges?
	/// @param border: the size of the border
	inline bool isInsideWithBorder(const Size& pt, int border) const {
		return pt.width>=border && pt.height>=border && pt.width<Base::size().width-border && pt.height<Base::size().height-border;
	}
	template <typename T>
	inline typename std::enable_if<std::is_integral<T>::value,bool>::type isInsideWithBorder(const cv::Point_<T>& pt, int border) const {
		return pt.x>=border && pt.y>=border && pt.x<Base::size().width-border && pt.y<Base::size().height-border;
	}
	template <typename T>
	inline typename std::enable_if<std::is_floating_point<T>::value,bool>::type isInsideWithBorder(const cv::Point_<T>& pt, int border) const {
		return pt.x>=T(border) && pt.y>=T(border) && pt.x<=T(Base::size().width-(border+1)) && pt.y<=T(Base::size().height-(border+1));
	}
	template <typename T, int border>
	inline typename std::enable_if<std::is_integral<T>::value,bool>::type isInsideWithBorder(const cv::Point_<T>& pt) const {
		return pt.x>=border && pt.y>=border && pt.x<Base::size().width-border && pt.y<Base::size().height-border;
	}
	template <typename T, int border>
	inline typename std::enable_if<std::is_floating_point<T>::value,bool>::type isInsideWithBorder(const cv::Point_<T>& pt) const {
		return pt.x>=T(border) && pt.y>=T(border) && pt.x<=T(Base::size().width-(border+1)) && pt.y<=T(Base::size().height-(border+1));
	}

	template <typename T, int border=0>
	static inline void clip(TPoint2<T>& ptMin, TPoint2<T>& ptMax, const cv::Size& size) {
		if (ptMin.x < T(border))
			ptMin.x = T(border);
		if (ptMin.y < T(border))
			ptMin.y = T(border);
		if (ptMax.x >= T(size.width-border))
			ptMax.x = T(size.width-(border+1));
		if (ptMax.y >= T(size.height-border))
			ptMax.y = T(size.height-(border+1));
	}
	template <typename T, int border=0>
	inline void clip(TPoint2<T>& ptMin, TPoint2<T>& ptMax) const {
		clip<T,border>(ptMin, ptMax, Base::size());
	}

	/// Remove the given element from the vector
	inline void remove(int idx) {
		// replace the removed element by the last one and decrease the size
		ASSERT(rows == 1 || cols == 1);
		const int last = area()-1;
		Base::operator()(idx) = Base::operator()(last);
		Base::resize((size_t)last);
	}

	/** @author koeser
		@warning very slow, generic implementation (order "n!"), better to use
		matrix decomposition (see BIAS/MathAlgo/Lapack.hh) */
	inline TYPE getDetSquare() const;

	/** @brief computes the adjoint matrix
		@author Christian Beder */
	inline TDMatrix getAdjoint() const;

	/** @brief compute square system matrix dest = A^T * A
		@param dest holds result of Transpose * this

		If you want to solve A * x = b, where A has more rows than columns,
		a common technique is to solve x = (A^T * A)^-1 * A^T * b.
		This function provides a fast way to compute A^T*A from A.
		@author grest/koeser */
	inline void getSystemMatrix(TDMatrix& dest) const;

	/** @brief componentwise: this = 0.5(this + this^T) yields symmetric matrix
		only allowed for square shaped matrices
		@author koeser 01/2007 */
	inline void makeSymmetric();

	/** Return the L1 norm: |a| + |b| + |c| + ...
		@author Ingo Thomsen
		@date 04/11/2002
		@status untested    **/
	inline TYPE getNormL1() const;

	/** Return the L2 norm: a^2 + b^2 + c^2 + ...
		@author woelk 07/2004 */
	inline double getNormL2() const;

	/** Kronecker-product with matrix, result in dest */
	void Kronecker(const TDMatrix& B, TDMatrix& dest) const;

	/** @brief swaps two rows
		@author woelk 05/2008 www.vision-n.de */
	void SwapRows(int i, int r);

	/** @brief use the Gauss Jordan Algorithm to transform the matrix to
		reduced row echelon form.
		@author woelk 05/2008 www.vision-n.de */
	void GaussJordan();

	//! more convenient forms of row and element access operators
	const TYPE& operator [](size_t i) const { return cv::Mat::at<TYPE>((int)i); }
	TYPE& operator [](size_t i) { return cv::Mat::at<TYPE>((int)i); }

	/// Access an element from the matrix. Bounds checking is only performed in debug mode.
	inline const TYPE& operator [] (const Size& pos) const {
		ASSERT(isInside(pos) && elem_stride() == sizeof(TYPE));
		return ((const TYPE*)data)[pos.height*row_stride() + pos.width];
	}
	inline TYPE& operator [] (const Size& pos) {
		ASSERT(isInside(pos) && elem_stride() == sizeof(TYPE));
		return ((TYPE*)data)[pos.height*row_stride() + pos.width];
	}

	/// pointer to the beginning of the matrix data
	inline const TYPE* getData() const { ASSERT(cv::Mat::empty() || cv::Mat::isContinuous()); return (const TYPE*)data; }
	inline TYPE* getData() { ASSERT(cv::Mat::empty() || cv::Mat::isContinuous()); return (TYPE*)data; }

	#ifdef _USE_EIGEN
	// Access point as Eigen equivalent
	inline operator EMat () const { return CEMatMap(getData(), rows, cols); }
	// Access point as Eigen::Map equivalent
	inline operator const CEMatMap () const { return CEMatMap(getData(), rows, cols); }
	inline operator EMatMap () { return EMatMap(getData(), rows, cols); }
	#endif

	#ifdef _USE_BOOST
	// serialize
	template <class Archive>
	void serialize(Archive& ar, const unsigned int /*version*/) {
		ar & boost::serialization::base_object<Base>(*this);
	}
	#endif
};
/*----------------------------------------------------------------*/
typedef TDMatrix<REAL> DMatrix;
typedef TDMatrix<int8_t> DMatrix8S;
typedef TDMatrix<uint8_t> DMatrix8U;
typedef TDMatrix<int32_t> DMatrix32S;
typedef TDMatrix<uint32_t> DMatrix32U;
typedef TDMatrix<float> DMatrix32F;
typedef TDMatrix<double> DMatrix64F;
typedef CLISTDEF2(DMatrix) DMatrixArr;
typedef CLISTDEF2(cv::Mat) MatArr;
/*----------------------------------------------------------------*/


// generic vector struct
template <typename TYPE>
class TDVector : public TDMatrix<TYPE>
{
public:
	typedef TYPE Type;
	typedef TDMatrix<TYPE> Base;
	typedef typename Base::Base BaseBase;
	typedef cv::Size Size;

	using Base::rows;
	using Base::cols;
	using Base::data;

public:
	inline TDVector() {}
	inline TDVector(const Base& rhs) : Base(rhs) {}
	inline TDVector(const cv::Mat& rhs) : Base(rhs) {}
	inline TDVector(const cv::MatExpr& rhs) : Base(rhs) {}
	inline TDVector(int _rows) : Base(_rows, 1) {}
	inline TDVector(int _rows, const TYPE& v) : Base(Size(_rows,1), v) {}
	inline TDVector(int _rows, TYPE* _data, size_t _step=Base::AUTO_STEP) : Base(_rows, 1, _data, _step) {}

	inline TDVector& operator = (const Base& rhs) { BaseBase::operator=(rhs); return *this; }
	inline TDVector& operator = (const BaseBase& rhs) { BaseBase::operator=(rhs); return *this; }
	inline TDVector& operator = (const cv::MatExpr& rhs) { BaseBase::operator=(rhs); return *this; }

	//! equivalent to Mat::create(_rows, 1, DataType<_Tp>::type)
	inline void create(int _rows) { BaseBase::create(_rows, 1); }

	/** outer product, constructs a matrix.
		Often written as v * v^T for col vectors
		@author Daniel Grest, Oct 2002
		@status tested */
	TDMatrix<TYPE> getOuterProduct(const TDVector<TYPE>& v) const;

	/** kronecker product
		@author woelk 08/2004 */
	void getKroneckerProduct(const TDVector<TYPE>& arg, TDVector<TYPE>& dst) const;
};
/*----------------------------------------------------------------*/
typedef TDVector<REAL> DVector;
typedef TDVector<int8_t> DVector8S;
typedef TDVector<uint8_t> DVector8U;
typedef TDVector<int32_t> DVector32S;
typedef TDVector<uint32_t> DVector32U;
typedef TDVector<float> DVector32F;
typedef TDVector<double> DVector64F;
typedef CLISTDEF2(DVector) DVectorArr;
/*----------------------------------------------------------------*/


// generic color type
// Here the color order means the order the data is stored on this machine.
// For example BGR means that the blue byte is stored first and the red byte last,
// which correspond to the RGB format on a little-endian machine.
#define _COLORMODE_BGR 1 // little-endian
#define _COLORMODE_RGB 2 // big-endian
#ifndef _COLORMODE
#define _COLORMODE _COLORMODE_BGR
#endif

template<typename TYPE> class ColorType
{
public:
	typedef TYPE value_type;
	typedef value_type alt_type;
	static const value_type ONE;
	static const alt_type ALTONE;
};
template<> class ColorType<uint8_t>
{
public:
	typedef uint8_t value_type;
	typedef float alt_type;
	static const value_type ONE;
	static const alt_type ALTONE;
};
template<> class ColorType<uint32_t>
{
public:
	typedef uint32_t value_type;
	typedef float alt_type;
	static const value_type ONE;
	static const alt_type ALTONE;
};
template<> class ColorType<float>
{
public:
	typedef float value_type;
	typedef uint8_t alt_type;
	static const value_type ONE;
	static const alt_type ALTONE;
};
template<> class ColorType<double>
{
public:
	typedef double value_type;
	typedef uint8_t alt_type;
	static const value_type ONE;
	static const alt_type ALTONE;
};
/*----------------------------------------------------------------*/

template <typename TYPE>
struct TPixel {
	union {
		struct {
			#if _COLORMODE == _COLORMODE_BGR
			TYPE b;
			TYPE g;
			TYPE r;
			#endif
			#if _COLORMODE == _COLORMODE_RGB
			TYPE r;
			TYPE g;
			TYPE b;
			#endif
		};
		struct {
			TYPE c0;
			TYPE c1;
			TYPE c2;
		};
		TYPE c[3];
	};
	typedef typename ColorType<TYPE>::alt_type ALT;
	typedef TYPE Type;
	typedef TPoint3<TYPE> Pnt;
	static const TPixel BLACK;
	static const TPixel WHITE;
	static const TPixel GRAY;
	static const TPixel RED;
	static const TPixel GREEN;
	static const TPixel BLUE;
	static const TPixel YELLOW;
	static const TPixel MAGENTA;
	static const TPixel CYAN;
	// init
	inline TPixel() {}
	template <typename T> inline TPixel(const TPixel<T>& p)
		#if _COLORMODE == _COLORMODE_BGR
		: b(TYPE(p.b)), g(TYPE(p.g)), r(TYPE(p.r)) {}
		#endif
		#if _COLORMODE == _COLORMODE_RGB
		: r(TYPE(p.r)), g(TYPE(p.g)), b(TYPE(p.b)) {}
		#endif
	inline TPixel(TYPE _r, TYPE _g, TYPE _b)
		#if _COLORMODE == _COLORMODE_BGR
		: b(_b), g(_g), r(_r) {}
		#endif
		#if _COLORMODE == _COLORMODE_RGB
		: r(_r), g(_g), b(_b) {}
		#endif
	inline TPixel(const Pnt& col) : c0(col.x),  c1(col.y),  c2(col.z) {}
	explicit inline TPixel(uint32_t col)
		#if _COLORMODE == _COLORMODE_BGR
		: b(TYPE(col&0xFF)), g(TYPE((col>>8)&0xFF)), r(TYPE((col>>16)&0xFF)) {}
		#endif
		#if _COLORMODE == _COLORMODE_RGB
		: r(TYPE((col>>16)&0xFF)), g(TYPE((col>>8)&0xFF)), b(TYPE(col&0xFF)) {}
		#endif
	// set/get from default type
	inline TPixel& set(TYPE _r, TYPE _g, TYPE _b) { r = _r; g = _g; b = _b; return *this; }
	inline TPixel& set(const TYPE* clr) { c[0] = clr[0]; c[1] = clr[1]; c[2] = clr[2]; return *this; }
	inline void get(TYPE& _r, TYPE& _g, TYPE& _b) const { _r = r; _g = g; _b = b; }
	inline void get(TYPE* clr) const { clr[0] = c[0]; clr[1] = c[1]; clr[2] = c[2]; }
	// set/get from alternative type
	inline TPixel& set(ALT _r, ALT _g, ALT _b) { r = TYPE(_r); g = TYPE(_g); b = TYPE(_b); return *this; }
	inline TPixel& set(const ALT* clr) { c[0] = TYPE(clr[0]); c[1] = TYPE(clr[1]); c[2] = TYPE(clr[2]); return *this; }
	inline void get(ALT& _r, ALT& _g, ALT& _b) const { _r = ALT(r); _g = ALT(g); _b = ALT(b); }
	inline void get(ALT* clr) const { clr[0] = ALT(c[0]); clr[1] = ALT(c[1]); clr[2] = ALT(c[2]); }
	template<typename T> inline TPixel<typename std::enable_if<!std::is_floating_point<TYPE>::value || !std::is_same<T,uint8_t>::value,T>::type> cast() const { return TPixel<T>(T(r), T(g), T(b)); }
	template<typename T> inline TPixel<typename std::enable_if<std::is_floating_point<TYPE>::value && std::is_same<T,uint8_t>::value,T>::type> cast() const {
		return TPixel<uint8_t>(
			(uint8_t)CLAMP(ROUND2INT(r), 0, 255),
			(uint8_t)CLAMP(ROUND2INT(g), 0, 255),
			(uint8_t)CLAMP(ROUND2INT(b), 0, 255)
		);
	}
	// set/get as vector
	inline const TYPE& operator[](size_t i) const { ASSERT(i<3); return c[i]; }
	inline TYPE& operator[](size_t i) { ASSERT(i<3); return c[i]; }
	// access as point equivalent
	template<typename T> inline operator TPoint3<T>() const { return TPoint3<T>(T(c[0]), T(c[1]), T(c[2])); }
	// access as vector equivalent
	inline operator const Pnt& () const { return *((const Pnt*)this); }
	inline operator Pnt& () { return *((Pnt*)this); }
	// access as cv::Scalar equivalent
	inline operator cv::Scalar () const { return cv::Scalar(c[0], c[1], c[2], TYPE(0)); }
	// compare
	inline bool operator==(const TPixel& col) const { return (memcmp(c, col.c, sizeof(TPixel)) == 0); }
	inline bool operator!=(const TPixel& col) const { return (memcmp(c, col.c, sizeof(TPixel)) != 0); }
	// operators
	inline TPixel operator*(const TPixel& v) const { return TPixel(r*v.r, g*v.g, b*v.b); }
	template<typename T> inline TPixel operator*(T v) const { return TPixel((TYPE)(v*r), (TYPE)(v*g), (TYPE)(v*b)); }
	template<typename T> inline TPixel& operator*=(T v) { return (*this = operator*(v)); }
	inline TPixel operator/(const TPixel& v) const { return TPixel(r/v.r, g/v.g, b/v.b); }
	template<typename T> inline TPixel operator/(T v) const { return operator*(T(1)/v); }
	template<typename T> inline TPixel& operator/=(T v) { return (*this = operator/(v)); }
	inline TPixel operator+(const TPixel& v) const { return TPixel(r+v.r, g+v.g, b+v.b); }
	template<typename T> inline TPixel operator+(T v) const { return TPixel((TYPE)(r+v), (TYPE)(g+v), (TYPE)(b+v)); }
	template<typename T> inline TPixel& operator+=(T v) { return (*this = operator+(v)); }
	inline TPixel operator-(const TPixel& v) const { return TPixel(r-v.r, g-v.g, b-v.b); }
	template<typename T> inline TPixel operator-(T v) const { return TPixel((TYPE)(r-v), (TYPE)(g-v), (TYPE)(b-v)); }
	template<typename T> inline TPixel& operator-=(T v) { return (*this = operator-(v)); }
	inline uint32_t toDWORD() const { return RGBA((uint8_t)r, (uint8_t)g, (uint8_t)b, (uint8_t)0); }
	// tools
	template <typename VT>
	static TPixel colorRamp(VT v, VT vmin, VT vmax);
	static TPixel gray2color(ALT v);
	#ifdef _USE_BOOST
	// serialize
	template <class Archive>
	void serialize(Archive& ar, const unsigned int /*version*/) {
		ar & c;
	}
	#endif
};
template <> inline TPixel<float>& TPixel<float>::set(uint8_t _r, uint8_t _g, uint8_t _b) { r = float(_r)/255; g = float(_g)/255; b = float(_b)/255; return *this; }
template <> inline void TPixel<float>::get(uint8_t& _r, uint8_t& _g, uint8_t& _b) const { _r = (uint8_t)CLAMP(ROUND2INT(r*255), 0, 255); _g = (uint8_t)CLAMP(ROUND2INT(g*255), 0, 255); _b = (uint8_t)CLAMP(ROUND2INT(b*255), 0, 255); }
template <> inline TPixel<uint8_t>& TPixel<uint8_t>::set(float _r, float _g, float _b) { r = (uint8_t)CLAMP(ROUND2INT(_r*255), 0, 255); g = (uint8_t)CLAMP(ROUND2INT(_g*255), 0, 255); b = (uint8_t)CLAMP(ROUND2INT(_b*255), 0, 255); return *this; }
template <> inline void TPixel<uint8_t>::get(float& _r, float& _g, float& _b) const { _r = float(r)/255; _g = float(g)/255; _b = float(b)/255; }
/*----------------------------------------------------------------*/
typedef TPixel<uint8_t> Pixel8U;
typedef TPixel<float> Pixel32F;
typedef TPixel<double> Pixel64F;
/*----------------------------------------------------------------*/

template <typename TYPE>
struct TColor {
	union {
		struct {
			#if _COLORMODE == _COLORMODE_BGR
			TYPE b;
			TYPE g;
			TYPE r;
			TYPE a;
			#endif
			#if _COLORMODE == _COLORMODE_RGB
			TYPE a;
			TYPE r;
			TYPE g;
			TYPE b;
			#endif
		};
		struct {
			TYPE c0;
			TYPE c1;
			TYPE c2;
			TYPE c3;
		};
		TYPE c[4];
	};
	typedef typename ColorType<TYPE>::alt_type ALT;
	typedef TYPE Type;
	typedef TPixel<TYPE> Pxl;
	typedef TPoint3<TYPE> Pnt;
	static const TColor BLACK;
	static const TColor WHITE;
	static const TColor GRAY;
	static const TColor RED;
	static const TColor GREEN;
	static const TColor BLUE;
	static const TColor YELLOW;
	static const TColor MAGENTA;
	static const TColor CYAN;
	// init
	inline TColor() {}
	template <typename T> inline TColor(const TColor<T>& p)
		: r(TYPE(p.r)), g(TYPE(p.g)), b(TYPE(p.b)), a(TYPE(p.a)) {}
	inline TColor(TYPE _r, TYPE _g, TYPE _b, TYPE _a=ColorType<TYPE>::ONE)
		: r(_r), g(_g), b(_b), a(_a) {}
	inline TColor(const Pxl& col, TYPE _a=ColorType<TYPE>::ONE)
		: r(col.r),  g(col.g),  b(col.b), a(_a) {}
	#if _COLORMODE == _COLORMODE_BGR
	inline TColor(const Pnt& col, TYPE _a=ColorType<TYPE>::ONE)
		: b(col.x),  g(col.y),  r(col.z),  a(_a) {}
	#endif
	#if _COLORMODE == _COLORMODE_RGB
	inline TColor(const Pnt& col, TYPE _a=ColorType<TYPE>::ONE)
		: r(col.x),  g(col.y),  b(col.z),  a(_a) {}
	#endif
	explicit inline TColor(uint32_t col)
		: r(TYPE((col>>16)&0xFF)), g(TYPE((col>>8)&0xFF)), b(TYPE(col&0xFF)), a(TYPE((col>>24)&0xFF)) {}
	// set/get from default type
	inline TColor& set(TYPE _r, TYPE _g, TYPE _b, TYPE _a=ColorType<TYPE>::ONE) { r = _r; g = _g; b = _b; a = _a; return *this; }
	inline TColor& set(const TYPE* clr) { c[0] = clr[0]; c[1] = clr[1]; c[2] = clr[2]; c[3] = clr[3]; return *this; }
	inline void get(TYPE& _r, TYPE& _g, TYPE& _b, TYPE& _a) const { _r = r; _g = g; _b = b; _a = a; }
	inline void get(TYPE* clr) const { clr[0] = c[0]; clr[1] = c[1]; clr[2] = c[2]; clr[3] = c[3]; }
	// set/get from alternative type
	inline TColor& set(ALT _r, ALT _g, ALT _b, ALT _a=ColorType<TYPE>::ALTONE) { r = TYPE(_r); g = TYPE(_g); b = TYPE(_b); a = TYPE(_a); return *this; }
	inline TColor& set(const ALT* clr) { c[0] = TYPE(clr[0]); c[1] = TYPE(clr[1]); c[2] = TYPE(clr[2]); c[3] = TYPE(clr[3]); return *this; }
	inline void get(ALT& _r, ALT& _g, ALT& _b, ALT& _a) const { _r = ALT(r); _g = ALT(g); _b = ALT(b); _a = ALT(a); }
	inline void get(ALT* clr) const { clr[0] = ALT(c[0]); clr[1] = ALT(c[1]); clr[2] = ALT(c[2]); clr[3] = ALT(c[3]); }
	template<typename T> inline TColor<typename std::enable_if<!std::is_floating_point<TYPE>::value || !std::is_same<T,uint8_t>::value,T>::type> cast() const { return TColor<T>(T(r), T(g), T(b), T(a)); }
	template<typename T> inline TColor<typename std::enable_if<std::is_floating_point<TYPE>::value && std::is_same<T,uint8_t>::value,T>::type> cast() const {
		return TColor<uint8_t>(
			(uint8_t)CLAMP(ROUND2INT(r), 0, 255),
			(uint8_t)CLAMP(ROUND2INT(g), 0, 255),
			(uint8_t)CLAMP(ROUND2INT(b), 0, 255),
			(uint8_t)CLAMP(ROUND2INT(a), 0, 255)
		);
	}
	// set/get as vector
	inline const TYPE& operator[](size_t i) const { ASSERT(i<4); return c[i]; }
	inline TYPE& operator[](size_t i) { ASSERT(i<4); return c[i]; }
	// access as pixel equivalent
	inline operator const Pxl& () const { return *((const Pxl*)this); }
	inline operator Pxl& () { return *((Pxl*)this); }
	// access as point equivalent
	inline operator const Pnt& () const { return *((const Pnt*)this); }
	inline operator Pnt& () { return *((Pnt*)this); }
	// access as cv::Scalar equivalent
	inline operator cv::Scalar () const { return cv::Scalar(c[0], c[1], c[2], c[3]); }
	// compare
	inline bool operator==(const TColor& col) const { return (memcmp(c, col.c, sizeof(TColor)) == 0); }
	inline bool operator!=(const TColor& col) const { return (memcmp(c, col.c, sizeof(TColor)) != 0); }
	// operators
	inline TColor operator*(const TColor& v) const { return TColor(r*v.r, g*v.g, b*v.b, a*v.a); }
	template<typename T> inline TColor operator*(T v) const { return TColor((TYPE)(v*r), (TYPE)(v*g), (TYPE)(v*b), (TYPE)(v*a)); }
	template<typename T> inline TColor& operator*=(T v) { return (*this = operator*(v)); }
	inline TColor operator/(const TColor& v) const { return TColor(r/v.r, g/v.g, b/v.b, a/v.a); }
	template<typename T> inline TColor operator/(T v) const { return operator*(T(1)/v); }
	template<typename T> inline TColor& operator/=(T v) { return (*this = operator/(v)); }
	inline TColor operator+(const TColor& v) const { return TColor(r+v.r, g+v.g, b+v.b, a+v.a); }
	template<typename T> inline TColor operator+(T v) const { return TColor((TYPE)(r+v), (TYPE)(g+v), (TYPE)(b+v), (TYPE)(a+v)); }
	template<typename T> inline TColor& operator+=(T v) { return (*this = operator+(v)); }
	inline TColor operator-(const TColor& v) const { return TColor(r-v.r, g-v.g, b-v.b, a-v.a); }
	template<typename T> inline TColor operator-(T v) const { return TColor((TYPE)(r-v), (TYPE)(g-v), (TYPE)(b-v), (TYPE)(a-v)); }
	template<typename T> inline TColor& operator-=(T v) { return (*this = operator-(v)); }
	inline uint32_t toDWORD() const { return RGBA((uint8_t)r, (uint8_t)g, (uint8_t)b, (uint8_t)a); }
	#ifdef _USE_BOOST
	// serialize
	template <class Archive>
	void serialize(Archive& ar, const unsigned int /*version*/) {
		ar & c;
	}
	#endif
};
template <> inline TColor<float>& TColor<float>::set(uint8_t _r, uint8_t _g, uint8_t _b, uint8_t _a) { r = float(_r)/255; g = float(_g)/255; b = float(_b)/255; a = float(_a)/255; return *this; }
template <> inline void TColor<float>::get(uint8_t& _r, uint8_t& _g, uint8_t& _b, uint8_t& _a) const { _r = uint8_t(r*255); _g = uint8_t(g*255); _b = uint8_t(b*255); _a = uint8_t(a*255); }
template <> inline TColor<uint8_t>& TColor<uint8_t>::set(float _r, float _g, float _b, float _a) { r = uint8_t(_r*255); g = uint8_t(_g*255); b = uint8_t(_b*255); a = uint8_t(_a*255); return *this; }
template <> inline void TColor<uint8_t>::get(float& _r, float& _g, float& _b, float& _a) const { _r = float(r)/255; _g = float(g)/255; _b = float(b)/255; _a = float(a)/255; }
template <> inline bool TColor<uint8_t>::operator==(const TColor& col) const { return (*((const uint32_t*)c) == *((const uint32_t*)col.c)); }
template <> inline bool TColor<uint8_t>::operator!=(const TColor& col) const { return (*((const uint32_t*)c) != *((const uint32_t*)col.c)); }
template <> inline uint32_t TColor<uint8_t>::toDWORD() const { return *((const uint32_t*)c); }
/*----------------------------------------------------------------*/
typedef TColor<uint8_t> Color8U;
typedef TColor<float> Color32F;
typedef TColor<double> Color64F;
/*----------------------------------------------------------------*/


// structure containing the image pixels
typedef Point2i ImageRef;
template <typename TYPE>
class TImage : public TDMatrix<TYPE>
{
public:
	typedef TYPE Type;
	typedef TDMatrix<TYPE> Base;
	typedef cv::Size Size;
	typedef typename Base::Base BaseBase;

	using Base::rows;
	using Base::cols;
	using Base::data;

public:
	inline TImage() {}
	inline TImage(const Base& rhs) : Base(rhs) {}
	inline TImage(const cv::Mat& rhs) : Base(rhs) {}
	inline TImage(const cv::MatExpr& rhs) : Base(rhs) {}
	inline TImage(int _rows, int _cols) : Base(_rows, _cols) {}
	inline TImage(const Size& sz) : Base(sz) {}
	inline TImage(const Size& sz, const TYPE& v) : Base(sz, v) {}
	inline TImage(const Size& sz, TYPE* _data, size_t _step=Base::AUTO_STEP) : Base(sz.height, sz.width, _data, _step) {}
	#ifdef _SUPPORT_CPP11
	inline TImage(cv::Mat&& rhs) : Base(std::forward<cv::Mat>(rhs)) {}

	inline TImage& operator = (cv::Mat&& rhs) { BaseBase::operator=(std::forward<cv::Mat>(rhs)); return *this; }
	#endif
	inline TImage& operator = (const Base& rhs) { BaseBase::operator=(rhs); return *this; }
	inline TImage& operator = (const BaseBase& rhs) { BaseBase::operator=(rhs); return *this; }
	inline TImage& operator = (const cv::MatExpr& rhs) { BaseBase::operator=(rhs); return *this; }

	/// What is the image size?
	inline int width() const { return cols; }
	inline int height() const { return rows; }

	/// What is the pixel stride of the image?
	inline size_t pixel_stride() const { return Base::elem_stride(); }

	inline const TYPE& getPixel(int y, int x) const;

	template <typename T>
	TYPE sample(const TPoint2<T>& pt) const;
	template <typename T>
	TYPE sampleSafe(const TPoint2<T>& pt) const;

	template <typename T, typename TV, typename Functor>
	bool sample(TV& v, const TPoint2<T>& pt, const Functor& functor) const;
	template <typename T, typename TV, typename Functor>
	bool sampleSafe(TV& v, const TPoint2<T>& pt, const Functor& functor) const;
	template <typename T, typename Functor>
	TYPE sample(const TPoint2<T>& pt, const Functor& functor, const TYPE& dv) const;
	template <typename T, typename Functor>
	TYPE sampleSafe(const TPoint2<T>& pt, const Functor& functor, const TYPE& dv) const;

	template <typename SAMPLER, typename INTERTYPE>
	INTERTYPE sample(const SAMPLER& sampler, const TPoint2<typename SAMPLER::Type>& pt) const;

	template <typename T>
	void toGray(TImage<T>& out, int code, bool bNormalize=false, bool bSRGB=false) const;

	static cv::Size computeResize(const cv::Size& size, REAL scale);
	static cv::Size computeResize(const cv::Size& size, REAL scale, unsigned resizes);
	unsigned computeMaxResolution(unsigned& level, unsigned minImageSize=320, unsigned maxImageSize=INT_MAX) const;
	static unsigned computeMaxResolution(unsigned width, unsigned height, unsigned& level, unsigned minImageSize=320, unsigned maxImageSize=INT_MAX);

	template <typename T, typename PARSER>
	static void RasterizeTriangle(const TPoint2<T>& v1, const TPoint2<T>& v2, const TPoint2<T>& v3, PARSER& parser);
	template <typename T, typename PARSER, bool CULL=true>
	static void RasterizeTriangleBary(const TPoint2<T>& v1, const TPoint2<T>& v2, const TPoint2<T>& v3, PARSER& parser);
	template <typename T, typename PARSER>
	static void RasterizeTriangleDepth(TPoint3<T> p1, TPoint3<T> p2, TPoint3<T> p3, PARSER& parser);

	template <typename T, typename PARSER>
	static void DrawLine(const TPoint2<T>& p1, const TPoint2<T>& p2, PARSER& parser);

	typedef void (STCALL *FncDrawPointAntialias) (const ImageRef&, const ImageRef&, float, float, void*);
	static bool DrawLineAntialias(Point2f x1, Point2f x2, FncDrawPointAntialias fncDrawPoint, void* pData=NULL);
	static bool DrawLineAntialias(const ImageRef& x1, const ImageRef& x2, FncDrawPointAntialias fncDrawPoint, void* pData=NULL);

	template <int HalfSize>
	void DilateMean(TImage<TYPE>& out, const TYPE& invalid) const;

	bool Load(const String&);
	bool Save(const String&) const;

	#ifndef _RELEASE
	void Show(const String& winname, int delay=0, bool bDestroy=true) const;
	#endif

	#ifdef _USE_BOOST
	// serialize
	template <class Archive>
	void serialize(Archive& ar, const unsigned int /*version*/) {
		ar & boost::serialization::base_object<Base>(*this);
	}
	#endif
};
/*----------------------------------------------------------------*/
typedef TImage<uint8_t> Image8U;
typedef TImage<uint16_t> Image16U;
typedef TImage<hfloat> Image16F;
typedef TImage<float> Image32F;
typedef TImage<double> Image64F;
typedef TImage<Pixel8U> Image8U3;
typedef TImage<Color8U> Image8U4;
typedef TImage<Pixel32F> Image32F3;
typedef TImage<Color32F> Image32F4;
/*----------------------------------------------------------------*/


template <typename TYPE>
class TBitMatrix
{
public:
	typedef TYPE Type;
	typedef cv::Size Size;
	struct Index {
		size_t idx;
		Type flag;
		inline Index() {}
		inline Index(size_t _idx, Type _flag) : idx(_idx), flag(_flag) {}
	};

	enum { numBitsPerCell = sizeof(Type)*8 };
	enum { numBitsShift = LOG2I<TBitMatrix::numBitsPerCell>() };

public:
	inline TBitMatrix() : data(NULL) {}
	inline TBitMatrix(int _rows, int _cols=1) : rows(_rows), cols(_cols), data(rows && cols ? new Type[computeLength(rows, cols)] : NULL) {}
	inline TBitMatrix(int _rows, int _cols, uint8_t v) : rows(_rows), cols(_cols), data(rows && cols ? new Type[computeLength(rows, cols)] : NULL) { if (!empty()) memset(v); }
	inline TBitMatrix(const Size& sz) : rows(sz.height), cols(sz.width), data(rows && cols ? new Type[computeLength(sz)] : NULL) {}
	inline TBitMatrix(const Size& sz, uint8_t v) : rows(sz.height), cols(sz.width), data(rows && cols ? new Type[computeLength(sz)] : NULL) { if (!empty()) memset(v); }
	inline ~TBitMatrix() { delete[] data; }

	inline void create(int _rows, int _cols=1) {
		if (!empty() && rows == _rows && cols == _cols)
			return;
		rows = _rows; cols = _cols;
		if (rows <=0 || cols <= 0) {
			release();
			return;
		}
		delete[] data;
		data = new Type[length()];
	}
	inline void create(const Size& sz) { create(sz.height, sz.width); }
	inline void release() { delete[] data; data = NULL; }
	inline void memset(uint8_t v) { ASSERT(!empty()); ::memset(data, v, sizeof(Type)*length()); }
	inline void swap(TBitMatrix& m) {
		union {int i; Type* d;} tmp;
		tmp.i = rows; rows = m.rows; m.rows = tmp.i;
		tmp.i = cols; cols = m.cols; m.cols = tmp.i;
		tmp.d = data; data = m.data; m.data = tmp.d;
	}

	inline void And(const TBitMatrix& m) {
		ASSERT(rows == m.rows && cols == m.cols);
		int i = length();
		while (i-- > 0)
			data[i] &= m.data[i];
	}
	inline void Or(const TBitMatrix& m) {
		ASSERT(rows == m.rows && cols == m.cols);
		int i = length();
		while (i-- > 0)
			data[i] |= m.data[i];
	}
	inline void XOr(const TBitMatrix& m) {
		ASSERT(rows == m.rows && cols == m.cols);
		int i = length();
		while (i-- > 0)
			data[i] ^= m.data[i];
	}

	inline bool empty() const { return data == NULL; }
	inline Size size() const { return Size(cols, rows); }
	inline int area() const { return cols*rows; }
	inline int length() const { return computeLength(rows, cols); }

	inline bool operator() (int i) const { return isSet(i); }
	inline bool operator() (int i, int j) const { return isSet(i,j); }
	inline bool operator() (const ImageRef& ir) const { return isSet(ir); }

	inline bool isSet(int i) const { ASSERT(!empty() && i<area()); const Index idx(computeIndex(i)); return (data[idx.idx] & idx.flag) != 0; }
	inline bool isSet(int i, int j) const { ASSERT(!empty() && i<rows && j<cols); const Index idx(computeIndex(i, j, cols)); return (data[idx.idx] & idx.flag) != 0; }
	inline bool isSet(const ImageRef& ir) const { ASSERT(!empty() && ir.y<rows && ir.x<cols); const Index idx(computeIndex(ir, cols)); return (data[idx.idx] & idx.flag) != 0; }

	inline void set(int i, bool v) { if (v) set(i); else unset(i); }
	inline void set(int i, int j, bool v) { if (v) set(i, j); else unset(i, j); }
	inline void set(const ImageRef& ir, bool v) { if (v) set(ir); else unset(ir); }

	inline void set(int i) { ASSERT(!empty() && i<area()); const Index idx(computeIndex(i)); data[idx.idx] |= idx.flag; }
	inline void set(int i, int j) { ASSERT(!empty() && i<rows && j<cols); const Index idx(computeIndex(i, j, cols)); data[idx.idx] |= idx.flag; }
	inline void set(const ImageRef& ir) { ASSERT(!empty() && ir.y<rows && ir.x<cols); const Index idx(computeIndex(ir, cols)); data[idx.idx] |= idx.flag; }

	inline void unset(int i) { ASSERT(!empty() && i<area()); const Index idx(computeIndex(i)); data[idx.idx] &= ~idx.flag; }
	inline void unset(int i, int j) { ASSERT(!empty() && i<rows && j<cols); const Index idx(computeIndex(i, j, cols)); data[idx.idx] &= ~idx.flag; }
	inline void unset(const ImageRef& ir) { ASSERT(!empty() && ir.y<rows && ir.x<cols); const Index idx(computeIndex(ir, cols)); data[idx.idx] &= ~idx.flag; }

	inline void flip(int i) { ASSERT(!empty() && i<area()); const Index idx(computeIndex(i)); data[idx.idx] ^= idx.flag; }
	inline void flip(int i, int j) { ASSERT(!empty() && i<rows && j<cols); const Index idx(computeIndex(i, j, cols)); data[idx.idx] ^= idx.flag; }
	inline void flip(const ImageRef& ir) { ASSERT(!empty() && ir.y<rows && ir.x<cols); const Index idx(computeIndex(ir, cols)); data[idx.idx] ^= idx.flag; }

	/// Is this coordinate inside the 2D matrix?
	inline bool isInside(const Size& pt) const {
		return pt.width>=0 && pt.height>=0 && pt.width<size().width && pt.height<size().height;
	}
	template <typename T>
	inline bool isInside(const cv::Point_<T>& pt) const {
		return int(pt.x)>=0 && int(pt.y)>=0 && int(pt.x)<size().width && int(pt.y)<size().height;
	}

	/// Is this coordinate inside the 2D matrix, and not too close to the edges?
	/// @param border: the size of the border
	inline bool isInsideWithBorder(const Size& pt, int border) const {
		return pt.width>=border && pt.height>=border && pt.width<size().width-border && pt.height<size().height-border;
	}
	template <typename T>
	inline bool isInsideWithBorder(const cv::Point_<T>& pt, int border) const {
		return int(pt.x)>=border && int(pt.y)>=border && int(pt.x)<size().width-border && int(pt.y)<size().height-border;
	}
	template <typename T, int border>
	inline bool isInsideWithBorder(const cv::Point_<T>& pt) const {
		return int(pt.x)>=border && int(pt.y)>=border && int(pt.x)<size().width-border && int(pt.y)<size().height-border;
	}

	static inline int computeLength(int size) { return (size+numBitsPerCell-1)>>numBitsShift; }
	static inline int computeLength(int _rows, int _cols) { return computeLength(_rows*_cols); }
	static inline int computeLength(const Size& sz) { return computeLength(sz.area()); }

	static inline Index computeIndex(int i) { return Index(i>>numBitsShift, Type(1)<<(i&(numBitsPerCell-1))); }
	static inline Index computeIndex(int i, int j, int stride) { return computeIndex(i*stride+j); }
	static inline Index computeIndex(const ImageRef& ir, int stride) { return computeIndex(ir.y*stride+ir.x); }

	//! the number of rows and columns
	int rows, cols;
	//! pointer to the data
	Type* data;

#ifdef _USE_BOOST
protected:
	// implement BOOST serialization
	friend class boost::serialization::access;
	template<class Archive>
	void save(Archive& ar, const unsigned int /*version*/) const {
		if (empty()) {
			const int sz(0);
			ar & sz;
			return;
		}
		ar & cols;
		ar & rows;
		ar & boost::serialization::make_array(data, length());
	}
	template<class Archive>
	void load(Archive& ar, const unsigned int /*version*/) {
		release();
		ar & cols;
		if (cols == 0)
			return;
		ar & rows;
		create(rows, cols);
		ar & boost::serialization::make_array(data, length());
	}
	BOOST_SERIALIZATION_SPLIT_MEMBER()
#endif
};
/*----------------------------------------------------------------*/
typedef TBitMatrix<size_t> BitMatrix;
/*----------------------------------------------------------------*/


// weighted accumulator class that operates on arbitrary types
template <typename TYPE, typename ACCUMTYPE=TYPE, typename WEIGHTTYPE=float>
struct TAccumulator {
	typedef TYPE Type;
	typedef ACCUMTYPE AccumType;
	typedef WEIGHTTYPE WeightType;

	AccumType value;
	WeightType weight;

	inline TAccumulator() : value(INITTO(static_cast<Type*>(NULL), 0)), weight(0) {}
	inline TAccumulator(const Type& v, const WeightType& w) : value(v), weight(w) {}
	inline bool IsEmpty() const { return weight <= 0; }
	// adds the given weighted value to the internal value
	inline void Add(const Type& v, const WeightType& w) {
		value += v*w;
		weight += w;
	}
	inline TAccumulator& operator +=(const TAccumulator& accum) {
		value += accum.value;
		weight += accum.weight;
		return *this;
	}
	inline TAccumulator operator +(const TAccumulator& accum) const {
		return TAccumulator(
			value + accum.value,
			weight + accum.weight
		);
	}
	// subtracts the given weighted value to the internal value
	inline void Sub(const Type& v, const WeightType& w) {
		value -= v*w;
		weight -= w;
	}
	inline TAccumulator& operator -=(const TAccumulator& accum) {
		value -= accum.value;
		weight -= accum.weight;
		return *this;
	}
	inline TAccumulator operator -(const TAccumulator& accum) const {
		return TAccumulator(
			value - accum.value,
			weight - accum.weight
		);
	}
	// returns the normalized version of the internal value
	inline AccumType NormalizedFull() const {
		return value / weight;
	}
	inline Type Normalized() const {
		return Type(NormalizedFull());
	}
	#ifdef _USE_BOOST
	// implement BOOST serialization
	template<class Archive>
	void serialize(Archive& ar, const unsigned int /*version*/) {
		ar & value;
		ar & weight;
	}
	#endif
};
/*----------------------------------------------------------------*/


// structure used for sorting some indices by their score (decreasing by default)
template <typename IndexType, typename ScoreType>
struct TIndexScore {
	IndexType idx;
	ScoreType score;
	inline TIndexScore() {}
	inline TIndexScore(IndexType _idx, ScoreType _score) : idx(_idx), score(_score) {}
	// compare by index (increasing)
	inline bool operator<(IndexType i) const { return (idx < i); }
	inline bool operator==(IndexType i) const { return (idx == i); }
	// compare by score (decreasing)
	inline bool operator<(const TIndexScore& r) const { return (score > r.score); }
	inline bool operator==(const TIndexScore& r) const { return (score == r.score); }
	static bool STCALL CompareByIndex(const TIndexScore& l, const TIndexScore& r) { return (l.idx < r.idx); }
	static bool STCALL CompareByScore(const TIndexScore& l, const TIndexScore& r) { return (r.score < l.score); }
	#ifdef _USE_BOOST
	// implement BOOST serialization
	template<class Archive>
	void serialize(Archive& ar, const unsigned int /*version*/) {
		ar & idx;
		ar & score;
	}
	#endif
};
/*----------------------------------------------------------------*/
typedef TIndexScore<uint32_t, float> IndexScore;
typedef CLISTDEF0(IndexScore) IndexScoreArr;
/*----------------------------------------------------------------*/


// structure describing a pair of indices as one long index
struct PairIdx {
	typedef uint64_t PairIndex;
	typedef uint32_t Index;
	union {
		PairIndex idx;
		Index indices[2];
		struct {
			#if __BYTE_ORDER == __LITTLE_ENDIAN
			Index j;
			Index i;
			#else
			Index i;
			Index j;
			#endif
		};
	};
	inline PairIdx() {}
	inline PairIdx(PairIndex _idx) : idx(_idx) {}
	inline PairIdx(Index _i, Index _j)
		#if __BYTE_ORDER == __LITTLE_ENDIAN
		: j(_j), i(_i) {}
		#else
		: i(_i), j(_j) {}
		#endif
	// get index
	inline operator PairIndex () const { return idx; }
	inline Index operator[](unsigned n) const {
		ASSERT(n < 2);
		#if __BYTE_ORDER == __LITTLE_ENDIAN
		return indices[(n+1)%2];
		#else
		return indices[n];
		#endif
	}
	inline Index& operator[](unsigned n) {
		ASSERT(n < 2);
		#if __BYTE_ORDER == __LITTLE_ENDIAN
		return indices[(n+1)%2];
		#else
		return indices[n];
		#endif
	}
	// compare by index (increasing)
	inline bool operator<(const PairIdx& r) const { return (idx < r.idx); }
	inline bool operator==(const PairIdx& r) const { return (idx == r.idx); }
};
/*----------------------------------------------------------------*/
typedef CLISTDEF0(PairIdx) PairIdxArr;
inline PairIdx MakePairIdx(uint32_t idxImageA, uint32_t idxImageB) {
	return (idxImageA<idxImageB ? PairIdx(idxImageA, idxImageB) : PairIdx(idxImageB, idxImageA));
}
/*----------------------------------------------------------------*/


struct cuint32_t {
	typedef uint32_t Type;
	union {
		uint32_t idx;
		uint8_t i;
	};
	inline cuint32_t() {}
	inline cuint32_t(uint32_t _idx) : idx(_idx) {}
	inline operator uint32_t () const { return idx; }
	inline operator uint32_t& () { return idx; }
};
/*----------------------------------------------------------------*/


// tools
String cvMat2String(const cv::Mat&, LPCSTR format="% 10.4f ");
template<typename TYPE, int m, int n> inline String cvMat2String(const TMatrix<TYPE,m,n>& mat, LPCSTR format="% 10.4f ") { return cvMat2String(cv::Mat(mat), format); }
template<typename TYPE> inline String cvMat2String(const TPoint3<TYPE>& pt, LPCSTR format="% 10.4f ") { return cvMat2String(cv::Mat(pt), format); }
/*----------------------------------------------------------------*/

} // namespace SEACAVE


#ifdef _USE_EIGEN

// Implement SO3 and SO2 lie groups
// as in TooN library: https://github.com/edrosten/TooN
// Copyright (C) 2005,2009 Tom Drummond (twd20@cam.ac.uk)

namespace Eigen {

/// Class to represent a three-dimensional rotation matrix. Three-dimensional rotation
/// matrices are members of the Special Orthogonal Lie group SO3. This group can be parameterized
/// three numbers (a vector in the space of the Lie Algebra). In this class, the three parameters are the
/// finite rotation vector, i.e. a three-dimensional vector whose direction is the axis of rotation
/// and whose length is the angle of rotation in radians. Exponentiating this vector gives the matrix,
/// and the logarithm of the matrix gives this vector.
template <typename Precision>
class SO3
{
public:
	template <typename P>
	friend std::istream& operator>>(std::istream& is, SO3<P>& rhs);

	typedef Matrix<Precision,3,3,Eigen::RowMajor> Mat3;
	typedef Matrix<Precision,3,1> Vec3;

	/// Default constructor. Initializes the matrix to the identity (no rotation)
	inline SO3() : mat(Mat3::Identity()) {}

	/// Construct from a rotation matrix.
	inline SO3(const Mat3& rhs) : mat(rhs) {}

	/// Construct from the axis of rotation (and angle given by the magnitude).
	inline SO3(const Vec3& v) : mat(exp(v)) {}

	/// creates an SO3 as a rotation that takes Vector a into the direction of Vector b
	/// with the rotation axis along a ^ b. If |a ^ b| == 0, it creates the identity rotation.
	/// An assertion will fail if Vector a and Vector b are in exactly opposite directions. 
	/// @param a source Vector
	/// @param b target Vector
	SO3(const Vec3& a, const Vec3& b) {
		ASSERT(a.size() == 3);
		ASSERT(b.size() == 3);
		Vec3 n(a.cross(b));
		const Precision nrmSq(n.squaredNorm());
		if (nrmSq == Precision(0)) {
			// check that the vectors are in the same direction if cross product is 0; if not,
			// this means that the rotation is 180 degrees, which leads to an ambiguity in the rotation axis
			ASSERT(a.dot(b) >= Precision(0));
			mat = Mat3::Identity();
			return;
		}
		n *= Precision(1)/sqrt(nrmSq);
		Mat3 R1;
		R1.col(0) = a.normalized();
		R1.col(1) = n;
		R1.col(2) = R1.col(0).cross(n);
		mat.col(0) = b.normalized();
		mat.col(1) = n;
		mat.col(2) = mat.col(0).cross(n);
		mat = mat * R1.transpose();
	}

	/// Assignment operator from a general matrix. This also calls coerce()
	/// to make sure that the matrix is a valid rotation matrix.
	inline SO3& operator=(const Mat3& rhs) {
		mat = rhs;
		coerce();
		return *this;
	}

	/// Modifies the matrix to make sure it is a valid rotation matrix.
	void coerce() {
		mat.row(0).normalize();
		const Precision d01(mat.row(0).dot(mat.row(1)));
		mat.row(1) -= mat.row(0) * d01;
		mat.row(1).normalize();
		const Precision d02(mat.row(0).dot(mat.row(2)));
		mat.row(2) -= mat.row(0) * d02;
		const Precision d12(mat.row(1).dot(mat.row(2)));
		mat.row(2) -= mat.row(1) * d12;
		mat.row(2).normalize();
		// check for positive determinant <=> right handed coordinate system of row vectors
		ASSERT(mat.row(0).cross(mat.row(1)).dot(mat.row(2)) > 0); 
	}

	/// Exponentiate a vector in the Lie algebra to generate a new SO3.
	/// See the Detailed Description for details of this vector.
	inline Mat3 exp(const Vec3& vect) const;

	/// Take the logarithm of the matrix, generating the corresponding vector in the Lie Algebra.
	/// See the Detailed Description for details of this vector.
	inline Vec3 ln() const;

	/// Right-multiply by another rotation matrix
	template <typename P>
	inline SO3& operator *=(const SO3<P>& rhs) {
		*this = *this * rhs;
		return *this;
	}

	/// Right-multiply by another rotation matrix
	inline SO3 operator *(const SO3& rhs) const { return SO3(*this, rhs); }

	/// Returns the SO3 as a Matrix<3>
	inline const Mat3& get_matrix() const { return mat; }

	/// Returns the i-th generator.  The generators of a Lie group are the basis
	/// for the space of the Lie algebra.  For %SO3, the generators are three
	/// \f$3\times3\f$ matrices representing the three possible (linearized)
	/// rotations.
	inline static Mat3 generator(int i) {
		Mat3 result(Mat3::Zero());
		result((i+1)%3,(i+2)%3) = Precision(-1);
		result((i+2)%3,(i+1)%3) = Precision( 1);
		return result;
	}

	/// Returns the i-th generator times pos
	inline static Vec3 generator_field(int i, const Vec3& pos) {
		Vec3 result;
		result(i) = Precision(0);
		result((i+1)%3) = -pos((i+2)%3);
		result((i+2)%3) =  pos((i+1)%3);
		return result;
	}

	template <typename PA, typename PB>
	inline SO3(const SO3<PA>& a, const SO3<PB>& b) : mat(a.get_matrix()*b.get_matrix()) {}

protected:
	Mat3 mat;

	#ifdef _USE_BOOST
	// implement BOOST serialization
	friend class boost::serialization::access;
	template<class Archive>
	void save(Archive& ar, const unsigned int /*version*/) const
	{
		Vec3 comp(ln());
		ar & comp;
	}
	template<class Archive>
	void load(Archive& ar, const unsigned int /*version*/)
	{
		Vec3 comp;
		ar & comp;
		mat = exp(comp);
	}
	BOOST_SERIALIZATION_SPLIT_MEMBER()
	#endif
};
/*----------------------------------------------------------------*/


/// Class to represent a two-dimensional rotation matrix. Two-dimensional rotation
/// matrices are members of the Special Orthogonal Lie group SO2. This group can be parameterized
/// with one number (the rotation angle).
template<typename Precision>
class SO2
{
public:
	template <typename P>
	friend std::istream& operator>>(std::istream&, SO2<P>&);

	typedef Matrix<Precision,2,2,Eigen::RowMajor> Mat2;

	/// Default constructor. Initializes the matrix to the identity (no rotation)
	inline SO2() : mat(Mat2::Identity()) {}

	/// Construct from a rotation matrix.
	inline SO2(const Mat2& rhs) : mat(rhs) {}

	/// Construct from an angle.
	inline SO2(const Precision l) : mat(exp(l)) {}

	/// Assignment operator from a general matrix. This also calls coerce()
	/// to make sure that the matrix is a valid rotation matrix.
	inline SO2& operator=(const Mat2& rhs) {
		mat = rhs;
		coerce();
		return *this;
	}

	/// Modifies the matrix to make sure it is a valid rotation matrix.
	inline void coerce() {
		mat.row(0).normalize();
		mat.row(1) = (mat.row(1) - mat.row(0) * (mat.row(0).dot(mat.row(1)))).normalized();
	}

	/// Exponentiate an angle in the Lie algebra to generate a new SO2.
	inline Mat2 exp(const Precision& d) const;

	/// extracts the rotation angle from the SO2
	inline Precision ln() const;

	/// Self right-multiply by another rotation matrix
	inline SO2& operator *=(const SO2& rhs) {
		mat = mat*rhs.get_matrix();
		return *this;
	}

	/// Right-multiply by another rotation matrix
	inline SO2 operator *(const SO2& rhs) const { return SO2(*this, rhs); }

	/// Returns the SO2 as a Matrix<2>
	inline const Mat2& get_matrix() const { return mat; }

	/// returns generator matrix
	inline static Mat2 generator() {
		Mat2 result;
		result(0,0) = Precision(0); result(0,1) = Precision(-1);
		result(1,0) = Precision(1); result(1,1) = Precision(0);
		return result;
	}

protected:
	Mat2 mat;

	#ifdef _USE_BOOST
	// implement BOOST serialization
	friend class boost::serialization::access;
	template<class Archive>
	void save(Archive& ar, const unsigned int /*version*/) const
	{
		Precision comp(ln());
		ar & comp;
	}
	template<class Archive>
	void load(Archive& ar, const unsigned int /*version*/)
	{
		Precision comp;
		ar & comp;
		mat = exp(comp);
	}
	BOOST_SERIALIZATION_SPLIT_MEMBER()
	#endif
};
/*----------------------------------------------------------------*/

} // namespace Eigen

#endif // _USE_EIGEN

#include "../Math/LMFit/lmmin.h"
#include "Types.inl"
#include "Util.inl"
#include "Rotation.h"
#include "Sphere.h"
#include "AABB.h"
#include "OBB.h"
#include "Plane.h"
#include "Ray.h"
#include "Line.h"
#include "Octree.h"
#include "UtilCUDA.h"

#endif // __SEACAVE_TYPES_H__
