    // Copyright (C) 2003  Davis E. King (davis@dlib.net)
    // License: Boost Software License   See LICENSE.txt for the full license.
    #ifndef DLIB_VECTOr_H_
    #define DLIB_VECTOr_H_

    #include <cmath>
    #include "vector_abstract.h"
    #include "../algs.h"
    #include "../serialize.h"
    #include <functional>
    #include <iostream>
    #include "../matrix/matrix.h"
    #include <limits>

    #if defined(_MSC_VER) && _MSC_VER < 1400
    // Despite my efforts to disabuse visual studio of its usual nonsense I can't find a
    // way to make this warning go away without just disabling it.   This is the warning:
    //   dlib\geometry\vector.h(129) : warning C4805: '==' : unsafe mix of type 'std::numeric_limits<_Ty>::is_integer' and type 'bool' in operation
    //
    #pragma warning(disable:4805)
    #endif

    namespace dlib
    {

        template <
            typename T,
            long NR = 3
            >
        class vector;

    // ----------------------------------------------------------------------------------------

        template <typename T, typename U, typename enabled = void>
        struct vect_promote;

        template <typename T, typename U, bool res = (sizeof(T) <= sizeof(U))>
        struct largest_type
        {
            typedef T type;
        };
        template <typename T, typename U>
        struct largest_type<T,U,true>
        {
            typedef U type;
        };

        template <typename T, typename U>
        struct vect_promote<T,U, typename enable_if_c<std::numeric_limits<T>::is_integer == std::numeric_limits<U>::is_integer>::type>
        {
            // If both T and U are both either integral or non-integral then just
            // use the biggest one
            typedef typename largest_type<T,U>::type type;
        };

        template <typename T, typename U>
        struct vect_promote<T,U, typename enable_if_c<std::numeric_limits<T>::is_integer != std::numeric_limits<U>::is_integer>::type>
        {
            typedef double type;
        };

    // ----------------------------------------------------------------------------------------

        // This insanity here is to work around a bug in visual studio 8.   These two rebind
        // structures are actually declared at a few points in this file because just having the
        // one declaration here isn't enough for visual studio.  It takes the three spread around
        // to avoid all its bugs.
        template <typename T, long N>
        struct vc_rebind
        {
            typedef vector<T,N> type;
        };
        template <typename T, typename U, long N>
        struct vc_rebind_promote
        {
            typedef vector<typename vect_promote<T,U>::type,N> type;
        };

    // ----------------------------------------------------------------------------------------

        template <typename T, typename U, typename enabled = void>
        struct vector_assign_helper
        {
            template <long NR>
            static void assign (
                vector<T,2>& dest,
                const vector<U,NR>& src
            )
            {
                dest.x() = static_cast<T>(src.x());
                dest.y() = static_cast<T>(src.y());
            }

            template <long NR>
            static void assign (
                vector<T,3>& dest,
                const vector<U,NR>& src
            )
            {
                dest.x() = static_cast<T>(src.x());
                dest.y() = static_cast<T>(src.y());
                dest.z() = static_cast<T>(src.z());
            }

            template <typename EXP>
            static void assign (
                vector<T,2>& dest,
                const matrix_exp<EXP>& m
            )
            {
                T x = static_cast<T>(m(0));
                T y = static_cast<T>(m(1));
                dest.x() = x;
                dest.y() = y;
            }

            template <typename EXP>
            static void assign (
                vector<T,3>& dest,
                const matrix_exp<EXP>& m
            )
            {
                T x = static_cast<T>(m(0));
                T y = static_cast<T>(m(1));
                T z = static_cast<T>(m(2));

                dest.x() = x;
                dest.y() = y;
                dest.z() = z;
            }
        };

        // This is an overload for the case where you are converting from a floating point
        // type to an integral type.  These overloads make sure values are rounded to
        // the nearest integral value.
        template <typename T, typename U>
        struct vector_assign_helper<T,U, typename enable_if_c<std::numeric_limits<T>::is_integer == true &&
                                                              std::numeric_limits<U>::is_integer == false>::type>
        {
            template <long NR>
            static void assign (
                vector<T,2>& dest,
                const vector<U,NR>& src
            )
            {
                dest.x() = static_cast<T>(std::floor(src.x() + 0.5));
                dest.y() = static_cast<T>(std::floor(src.y() + 0.5));
            }

            template <long NR>
            static void assign (
                vector<T,3>& dest,
                const vector<U,NR>& src
            )
            {
                dest.x() = static_cast<T>(std::floor(src.x() + 0.5));
                dest.y() = static_cast<T>(std::floor(src.y() + 0.5));
                dest.z() = static_cast<T>(std::floor(src.z() + 0.5));
            }

            template <typename EXP>
            static void assign (
                vector<T,3>& dest,
                const matrix_exp<EXP>& m
            )
            {
                dest.x() = static_cast<T>(std::floor(m(0) + 0.5));
                dest.y() = static_cast<T>(std::floor(m(1) + 0.5));
                dest.z() = static_cast<T>(std::floor(m(2) + 0.5));
            }

            template <typename EXP>
            static void assign (
                vector<T,2>& dest,
                const matrix_exp<EXP>& m
            )
            {
                dest.x() = static_cast<T>(std::floor(m(0) + 0.5));
                dest.y() = static_cast<T>(std::floor(m(1) + 0.5));
            }

        };

    // ----------------------------------------------------------------------------------------

        template <typename T>
        class vector<T,3> : public matrix<T,3,1>
        {
            /*!
                INITIAL VALUE
                    - x() == 0
                    - y() == 0
                    - z() == 0

                CONVENTION
                    - (*this)(0) == x()
                    - (*this)(1) == y()
                    - (*this)(2) == z()

            !*/

            // This insanity here is to work around a bug in visual studio 8.
            template <typename V, long N>
            struct vc_rebind
            {
                typedef vector<V,N> type;
            };
                template <typename V, typename U, long N>
            struct vc_rebind_promote
            {
                typedef vector<typename vect_promote<V,U>::type,N> type;
            };

        public:

            typedef T type;

            vector (
            )
            {
                x() = 0;
                y() = 0;
                z() = 0;
            }

            // ---------------------------------------

            vector (
                const T _x,
                const T _y,
                const T _z
            )
            {
                x() = _x;
                y() = _y;
                z() = _z;
            }

            // ---------------------------------------

            vector (
                const vector& item
            ) : matrix<T,3,1>(item)
            {
            }

            // ---------------------------------------

            template <typename U>
            vector (
                const vector<U,2>& item
            )
            {
                // Do this so that we get the appropriate rounding depending on the relative
                // type of T and U.
                vector<T,2> temp(item);
                x() = temp.x();
                y() = temp.y();
                z() = 0;
            }

            // ---------------------------------------

            vector (
                const vector<T,2>& item
            )
            {
                x() = item.x();
                y() = item.y();
                z() = 0;
            }

            // ---------------------------------------

            template <typename U>
            vector (
                const vector<U,3>& item
            )
            {
                (*this) = item;
            }

            // ---------------------------------------

            template <typename EXP>
            vector ( const matrix_exp<EXP>& m)
            {
                (*this) = m;
            }

            // ---------------------------------------

            template <typename EXP>
            vector& operator = (
                const matrix_exp<EXP>& m
            )
            {
                // you can only assign vectors with 3 elements to a dlib::vector<T,3> object
                COMPILE_TIME_ASSERT(EXP::NR*EXP::NC == 3 || EXP::NR*EXP::NC == 0);

                // make sure requires clause is not broken
                DLIB_ASSERT((m.nr() == 1 || m.nc() == 1) && (m.size() == 3),
                    "\t vector(const matrix_exp& m)"
                    << "\n\t the given matrix is of the wrong size"
                    << "\n\t m.nr():   " << m.nr()
                    << "\n\t m.nc():   " << m.nc()
                    << "\n\t m.size(): " << m.size()
                    << "\n\t this: " << this
                    );

                vector_assign_helper<T, typename EXP::type>::assign(*this, m);
                return *this;
            }

            // ---------------------------------------

            template <typename U, long N>
            vector& operator = (
                const vector<U,N>& item
            )
            {
                vector_assign_helper<T,U>::assign(*this, item);
                return *this;
            }

            // ---------------------------------------

            vector& operator= (
                const vector& item
            )
            {
                x() = item.x();
                y() = item.y();
                z() = item.z();
                return *this;
            }

            // ---------------------------------------

            double length(
            ) const
            {
                return std::sqrt((double)(x()*x() + y()*y() + z()*z()));
            }

            // ---------------------------------------

            double length_squared(
            ) const
            {
                return (double)(x()*x() + y()*y() + z()*z());
            }

            // ---------------------------------------

            typename vc_rebind<double,3>::type normalize (
            ) const
            {
                const double tmp = std::sqrt((double)(x()*x() + y()*y() + z()*z()));
                return vector<double,3> ( x()/tmp,
                                          y()/tmp,
                                          z()/tmp
                );
            }

            // ---------------------------------------

            T& x (
            )
            {
                return (*this)(0);
            }

            // ---------------------------------------

            T& y (
            )
            {
                return (*this)(1);
            }

            // ---------------------------------------

            T& z (
            )
            {
                return (*this)(2);
            }

            // ---------------------------------------

            const T& x (
            ) const
            {
                return (*this)(0);
            }

            // ---------------------------------------

            const T& y (
            ) const
            {
                return (*this)(1);
            }

            // ---------------------------------------

            const T& z (
            ) const
            {
                return (*this)(2);
            }

            // ---------------------------------------

            T dot (
                const vector& rhs
            ) const
            {
                return x()*rhs.x() + y()*rhs.y() + z()*rhs.z();
            }

            // ---------------------------------------

            template <typename U, long N>
            typename vect_promote<T,U>::type dot (
                const vector<U,N>& rhs
            ) const
            {
                return x()*rhs.x() + y()*rhs.y() + z()*rhs.z();
            }

            // ---------------------------------------

            template <typename U, long N>
            typename vc_rebind_promote<T,U,3>::type cross (
                const vector<U,N>& rhs
            ) const
            {
                typedef vector<typename vect_promote<T,U>::type,3> ret_type;

                return ret_type (
                    y()*rhs.z() - z()*rhs.y(),
                    z()*rhs.x() - x()*rhs.z(),
                    x()*rhs.y() - y()*rhs.x()
                    );
            }

            // ---------------------------------------

            vector& operator += (
                const vector& rhs
            )
            {
                x() += rhs.x();
                y() += rhs.y();
                z() += rhs.z();
                return *this;
            }

            // ---------------------------------------

            vector& operator -= (
                const vector& rhs
            )
            {
                x() -= rhs.x();
                y() -= rhs.y();
                z() -= rhs.z();
                return *this;
            }

            // ---------------------------------------

            vector& operator /= (
                const T& rhs
            )
            {
                x() /= rhs;
                y() /= rhs;
                z() /= rhs;
                return *this;
            }

            // ---------------------------------------

            vector& operator *= (
                const T& rhs
            )
            {
                x() *= rhs;
                y() *= rhs;
                z() *= rhs;
                return *this;
            }

            // ---------------------------------------

            vector operator - (
            ) const
            {
                return vector(-x(), -y(), -z());
            }

            // ---------------------------------------

            template <typename U>
            typename vc_rebind_promote<T,U,3>::type operator / (
                const U& val
            ) const
            {
                typedef vector<typename vect_promote<T,U>::type,3> ret_type;
                return ret_type(x()/val, y()/val, z()/val);
            }

            // ---------------------------------------

            template <typename U, long NR2>
            bool operator== (
                const vector<U,NR2>& rhs
            ) const
            {
                return x()==rhs.x() && y()==rhs.y() && z()==rhs.z();
            }

            // ---------------------------------------

            template <typename U, long NR2>
            bool operator!= (
                const vector<U,NR2>& rhs
            ) const
            {
                return !(*this == rhs);
            }

            // ---------------------------------------

            void swap (
                vector& item
            )
            {
                dlib::exchange(x(), item.x());
                dlib::exchange(y(), item.y());
                dlib::exchange(z(), item.z());
            }

            // ---------------------------------------

        };

    // ----------------------------------------------------------------------------------------

        template <typename T>
        class vector<T,2> : public matrix<T,2,1>
        {
            /*!
                INITIAL VALUE
                    - x() == 0
                    - y() == 0

                CONVENTION
                    - (*this)(0) == x()
                    - (*this)(1) == y()
                    - z() == 0
            !*/

            // This insanity here is to work around a bug in visual studio 8.
            template <typename V, long N>
            struct vc_rebind
            {
                typedef vector<V,N> type;
            };
                template <typename V, typename U, long N>
            struct vc_rebind_promote
            {
                typedef vector<typename vect_promote<V,U>::type,N> type;
            };

        public:

            typedef T type;

            vector (
            )
            {
                x() = 0;
                y() = 0;
            }

            // ---------------------------------------

            vector (
                const T _x,
                const T _y
            )
            {
                x() = _x;
                y() = _y;
            }

            // ---------------------------------------

            template <typename U>
            vector (
                const vector<U,3>& item
            )
            {
                // Do this so that we get the appropriate rounding depending on the relative
                // type of T and U.
                vector<T,3> temp(item);
                x() = temp.x();
                y() = temp.y();
            }

            // ---------------------------------------

            vector (
                const vector& item
            ) : matrix<T,2,1>(item)
            {
            }

            // ---------------------------------------

            vector (
                const vector<T,3>& item
            )
            {
                x() = item.x();
                y() = item.y();
            }

            // ---------------------------------------

            template <typename U>
            vector (
                const vector<U,2>& item
            )
            {
                (*this) = item;
            }

            // ---------------------------------------

            template <typename EXP>
            vector ( const matrix_exp<EXP>& m)
            {
                (*this) = m;
            }

            // ---------------------------------------

            template <typename EXP>
            vector& operator = (
                const matrix_exp<EXP>& m
            )
            {
                // you can only assign vectors with 2 elements to a dlib::vector<T,2> object
                COMPILE_TIME_ASSERT(EXP::NR*EXP::NC == 2 || EXP::NR*EXP::NC == 0);

                // make sure requires clause is not broken
                DLIB_ASSERT((m.nr() == 1 || m.nc() == 1) && (m.size() == 2),
                    "\t vector(const matrix_exp& m)"
                    << "\n\t the given matrix is of the wrong size"
                    << "\n\t m.nr():   " << m.nr()
                    << "\n\t m.nc():   " << m.nc()
                    << "\n\t m.size(): " << m.size()
                    << "\n\t this: " << this
                    );

                vector_assign_helper<T, typename EXP::type>::assign(*this, m);
                return *this;
            }

            // ---------------------------------------

            template <typename U, long N>
            vector& operator = (
                const vector<U,N>& item
            )
            {
                vector_assign_helper<T,U>::assign(*this, item);
                return *this;
            }

            // ---------------------------------------

            vector& operator= (
                const vector& item
            )
            {
                x() = item.x();
                y() = item.y();
                return *this;
            }

            // ---------------------------------------

            double length(
            ) const
            {
                return std::sqrt((double)(x()*x() + y()*y()));
            }

            // ---------------------------------------

            double length_squared(
            ) const
            {
                return (double)(x()*x() + y()*y());
            }

            // ---------------------------------------

            typename vc_rebind<double,2>::type normalize (
            ) const
            {
                const double tmp = std::sqrt((double)(x()*x() + y()*y()));
                return vector<double,2> ( x()/tmp,
                             y()/tmp
                );
            }

            // ---------------------------------------

            T& x (
            )
            {
                return (*this)(0);
            }

            // ---------------------------------------

            T& y (
            )
            {
                return (*this)(1);
            }

            // ---------------------------------------

            const T& x (
            ) const
            {
                return (*this)(0);
            }

            // ---------------------------------------

            const T& y (
            ) const
            {
                return (*this)(1);
            }

            // ---------------------------------------

            const T z (
            ) const
            {
                return 0;
            }

            // ---------------------------------------

            T dot (
                const vector& rhs
            ) const
            {
                return x()*rhs.x() + y()*rhs.y();
            }

            // ---------------------------------------

            template <typename U, long N>
            typename vect_promote<T,U>::type dot (
                const vector<U,N>& rhs
            ) const
            {
                return x()*rhs.x() + y()*rhs.y() + z()*rhs.z();
            }

            // ---------------------------------------

            vector& operator += (
                const vector& rhs
            )
            {
                x() += rhs.x();
                y() += rhs.y();
                return *this;
            }

            // ---------------------------------------

            vector& operator -= (
                const vector& rhs
            )
            {
                x() -= rhs.x();
                y() -= rhs.y();
                return *this;
            }

            // ---------------------------------------

            vector& operator /= (
                const T& rhs
            )
            {
                x() /= rhs;
                y() /= rhs;
                return *this;
            }

            // ---------------------------------------

            vector& operator *= (
                const T& rhs
            )
            {
                x() *= rhs;
                y() *= rhs;
                return *this;
            }

            // ---------------------------------------

            vector operator - (
            ) const
            {
                return vector(-x(), -y());
            }

            // ---------------------------------------

            template <typename U>
            typename vc_rebind_promote<T,U,2>::type operator / (
                const U& val
            ) const
            {
                typedef vector<typename vect_promote<T,U>::type,2> ret_type;
                return ret_type(x()/val, y()/val);
            }

            // ---------------------------------------

            template <typename U, long NR2>
            bool operator== (
                const vector<U,NR2>& rhs
            ) const
            {
                return x()==rhs.x() && y()==rhs.y() && z()==rhs.z();
            }

            // ---------------------------------------

            bool operator== (
                const vector& rhs
            ) const
            {
                return x()==rhs.x() && y()==rhs.y();
            }

            // ---------------------------------------

            template <typename U, long NR2>
            bool operator!= (
                const vector<U,NR2>& rhs
            ) const
            {
                return !(*this == rhs);
            }

            // ---------------------------------------

            bool operator!= (
                const vector& rhs
            ) const
            {
                return !(*this == rhs);
            }

            // ---------------------------------------

            void swap (
                vector& item
            )
            {
                dlib::exchange(x(), item.x());
                dlib::exchange(y(), item.y());
            }

            // ---------------------------------------

            template <typename U, long N>
            typename vc_rebind_promote<T,U,3>::type cross (
                const vector<U,N>& rhs
            ) const
            {
                typedef vector<typename vect_promote<T,U>::type,3> ret_type;
                return ret_type (
                    y()*rhs.z(),
                    - x()*rhs.z(),
                    x()*rhs.y() - y()*rhs.x()
                    );
            }

            // ---------------------------------------

        };

    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------

        template <typename T, typename U>
        inline const typename vc_rebind_promote<T,U,2>::type operator+ (
            const vector<T,2>& lhs,
            const vector<U,2>& rhs
        )
        {
            typedef typename vc_rebind_promote<T,U,2>::type ret_type;
            return ret_type(lhs.x()+rhs.x(), lhs.y()+rhs.y());
        }

    // ----------------------------------------------------------------------------------------

        template <typename T, typename U>
        inline const typename vc_rebind_promote<T,U,3>::type operator+ (
            const vector<T,3>& lhs,
            const vector<U,3>& rhs
        )
        {
            typedef typename vc_rebind_promote<T,U,3>::type ret_type;
            return ret_type(lhs.x()+rhs.x(), lhs.y()+rhs.y(), lhs.z()+rhs.z());
        }

    // ----------------------------------------------------------------------------------------

        template <typename T, typename U>
        inline const typename vc_rebind_promote<T,U,3>::type operator+ (
            const vector<T,2>& lhs,
            const vector<U,3>& rhs
        )
        {
            typedef typename vc_rebind_promote<T,U,3>::type ret_type;
            return ret_type(lhs.x()+rhs.x(), lhs.y()+rhs.y(), rhs.z());
        }

    // ----------------------------------------------------------------------------------------

        template <typename T, typename U>
        inline const typename vc_rebind_promote<T,U,3>::type operator+ (
            const vector<T,3>& lhs,
            const vector<U,2>& rhs
        )
        {
            typedef typename vc_rebind_promote<T,U,3>::type ret_type;
            return ret_type(lhs.x()+rhs.x(), lhs.y()+rhs.y(), lhs.z());
        }

    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------

        template <typename T, typename U>
        inline const typename vc_rebind_promote<T,U,2>::type operator- (
            const vector<T,2>& lhs,
            const vector<U,2>& rhs
        )
        {
            typedef typename vc_rebind_promote<T,U,2>::type ret_type;
            return ret_type(lhs.x()-rhs.x(), lhs.y()-rhs.y());
        }

    // ----------------------------------------------------------------------------------------

        template <typename T, typename U>
        inline const typename vc_rebind_promote<T,U,3>::type operator- (
            const vector<T,3>& lhs,
            const vector<U,3>& rhs
        )
        {
            typedef typename vc_rebind_promote<T,U,3>::type ret_type;
            return ret_type(lhs.x()-rhs.x(), lhs.y()-rhs.y(), lhs.z()-rhs.z());
        }

    // ----------------------------------------------------------------------------------------

        template <typename T, typename U>
        inline const typename vc_rebind_promote<T,U,3>::type operator- (
            const vector<T,2>& lhs,
            const vector<U,3>& rhs
        )
        {
            typedef typename vc_rebind_promote<T,U,3>::type ret_type;
            return ret_type(lhs.x()-rhs.x(), lhs.y()-rhs.y(), -rhs.z());
        }

    // ----------------------------------------------------------------------------------------

        template <typename T, typename U>
        inline const typename vc_rebind_promote<T,U,3>::type operator- (
            const vector<T,3>& lhs,
            const vector<U,2>& rhs
        )
        {
            typedef typename vc_rebind_promote<T,U,3>::type ret_type;
            return ret_type(lhs.x()-rhs.x(), lhs.y()-rhs.y(), lhs.z());
        }

    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------

        template <typename T, typename U>
        inline typename disable_if<is_matrix<U>, const typename vc_rebind_promote<T,U,2>::type >::type operator* (
            const vector<T,2>& v,
            const U& s
        )
        {
            typedef typename vc_rebind_promote<T,U,2>::type ret_type;
            return ret_type(v.x()*s, v.y()*s);
        }

    // ----------------------------------------------------------------------------------------

        template <typename T, typename U>
        inline typename disable_if<is_matrix<U>, const typename vc_rebind_promote<T,U,2>::type >::type operator* (
            const U& s,
            const vector<T,2>& v
        )
        {
            typedef typename vc_rebind_promote<T,U,2>::type ret_type;
            return ret_type(v.x()*s, v.y()*s);
        }

    // ----------------------------------------------------------------------------------------

        template <typename T, typename U>
        inline typename disable_if<is_matrix<U>, const typename vc_rebind_promote<T,U,3>::type >::type operator* (
            const vector<T,3>& v,
            const U& s
        )
        {
            typedef typename vc_rebind_promote<T,U,3>::type ret_type;
            return ret_type(v.x()*s, v.y()*s, v.z()*s);
        }

    // ----------------------------------------------------------------------------------------

        template <typename T, typename U>
        inline typename disable_if<is_matrix<U>, const typename vc_rebind_promote<T,U,3>::type >::type operator* (
            const U& s,
            const vector<T,3>& v
        )
        {
            typedef typename vc_rebind_promote<T,U,3>::type ret_type;
            return ret_type(v.x()*s, v.y()*s, v.z()*s);
        }

    // ----------------------------------------------------------------------------------------

        template<typename T, long NR>
        inline void swap (
            vector<T,NR> & a,
            vector<T,NR> & b
        ) { a.swap(b); }

    // ----------------------------------------------------------------------------------------

        template<typename T>
        inline void serialize (
            const vector<T,3>& item,
            std::ostream& out
        )
        {
            try
            {
                serialize(item.x(),out);
                serialize(item.y(),out);
                serialize(item.z(),out);
            }
            catch (serialization_error& e)
            {
                throw serialization_error(e.info + "\n   while serializing object of type vector");
            }
        }

        template<typename T>
        inline void deserialize (
            vector<T,3>& item,
            std::istream& in
        )
        {
            try
            {
                deserialize(item.x(),in);
                deserialize(item.y(),in);
                deserialize(item.z(),in);
            }
            catch (serialization_error& e)
            {
                item.x() = 0;
                item.y() = 0;
                item.z() = 0;
                throw serialization_error(e.info + "\n   while deserializing object of type vector");
            }
        }

    // ----------------------------------------------------------------------------------------

        template<typename T>
        inline void serialize (
            const vector<T,2>& item,
            std::ostream& out
        )
        {
            try
            {
                serialize(item.x(),out);
                serialize(item.y(),out);
            }
            catch (serialization_error& e)
            {
                throw serialization_error(e.info + "\n   while serializing object of type vector");
            }
        }

        template<typename T>
        inline void deserialize (
            vector<T,2>& item,
            std::istream& in
        )
        {
            try
            {
                deserialize(item.x(),in);
                deserialize(item.y(),in);
            }
            catch (serialization_error& e)
            {
                item.x() = 0;
                item.y() = 0;
                throw serialization_error(e.info + "\n   while deserializing object of type vector");
            }
        }

    // ----------------------------------------------------------------------------------------

        template<typename T>
        std::ostream& operator<< (
            std::ostream& out,
            const vector<T,3>& item
        )
        {
            out << "(" << item.x() << ", " << item.y() << ", " << item.z() << ")";
            return out;
        }

        template<typename T>
        std::istream& operator>>(
            std::istream& in,
            vector<T,3>& item
        )
        {

            // eat all the crap up to the '('
            while (in.peek() == ' ' || in.peek() == '\t' || in.peek() == '\r' || in.peek() == '\n')
                in.get();

            // there should be a '(' if not then this is an error
            if (in.get() != '(')
            {
                in.setstate(in.rdstate() | std::ios::failbit);
                return in;
            }

            // eat all the crap up to the first number
            while (in.peek() == ' ' || in.peek() == '\t')
                in.get();
            in >> item.x();

            if (!in.good())
                return in;

            // eat all the crap up to the next number
            while (in.peek() == ' ' || in.peek() == '\t' || in.peek() == ',')
                in.get();
            in >> item.y();

            if (!in.good())
                return in;

            // eat all the crap up to the next number
            while (in.peek() == ' ' || in.peek() == '\t' || in.peek() == ',')
                in.get();
            in >> item.z();

            if (!in.good())
                return in;

            // eat all the crap up to the ')'
            while (in.peek() == ' ' || in.peek() == '\t')
                in.get();

            // there should be a ')' if not then this is an error
            if (in.get() != ')')
                in.setstate(in.rdstate() | std::ios::failbit);
            return in;
        }

    // ----------------------------------------------------------------------------------------

        template<typename T>
        std::ostream& operator<< (
            std::ostream& out,
            const vector<T,2>& item
        )
        {
            out << "(" << item.x() << ", " << item.y() << ")";
            return out;
        }

        template<typename T>
        std::istream& operator>>(
            std::istream& in,
            vector<T,2>& item
        )
        {

            // eat all the crap up to the '('
            while (in.peek() == ' ' || in.peek() == '\t' || in.peek() == '\r' || in.peek() == '\n')
                in.get();

            // there should be a '(' if not then this is an error
            if (in.get() != '(')
            {
                in.setstate(in.rdstate() | std::ios::failbit);
                return in;
            }

            // eat all the crap up to the first number
            while (in.peek() == ' ' || in.peek() == '\t')
                in.get();
            in >> item.x();

            if (!in.good())
                return in;

            // eat all the crap up to the next number
            while (in.peek() == ' ' || in.peek() == '\t' || in.peek() == ',')
                in.get();
            in >> item.y();

            if (!in.good())
                return in;

            // eat all the crap up to the ')'
            while (in.peek() == ' ' || in.peek() == '\t')
                in.get();

            // there should be a ')' if not then this is an error
            if (in.get() != ')')
                in.setstate(in.rdstate() | std::ios::failbit);
            return in;
        }

    // ----------------------------------------------------------------------------------------

        typedef vector<long,2> point;
        typedef vector<double,2> dpoint;

    // ----------------------------------------------------------------------------------------

    }

    namespace std
    {
        /*!
            Define std::less<vector<T,3> > so that you can use vectors in the associative containers.
        !*/
        template<typename T>
        struct less<dlib::vector<T,3> > : public binary_function<dlib::vector<T,3> ,dlib::vector<T,3> ,bool>
        {
            inline bool operator() (const dlib::vector<T,3> & a, const dlib::vector<T,3> & b) const
            {
                if      (a.x() < b.x()) return true;
                else if (a.x() > b.x()) return false;
                else if (a.y() < b.y()) return true;
                else if (a.y() > b.y()) return false;
                else if (a.z() < b.z()) return true;
                else if (a.z() > b.z()) return false;
                else                    return false;
            }
        };

        /*!
            Define std::less<vector<T,2> > so that you can use vector<T,2>s in the associative containers.
        !*/
        template<typename T>
        struct less<dlib::vector<T,2> > : public binary_function<dlib::vector<T,2> ,dlib::vector<T,2> ,bool>
        {
            inline bool operator() (const dlib::vector<T,2> & a, const dlib::vector<T,2> & b) const
            {
                if      (a.x() < b.x()) return true;
                else if (a.x() > b.x()) return false;
                else if (a.y() < b.y()) return true;
                else if (a.y() > b.y()) return false;
                else                    return false;
            }
        };
    }

    #if defined(_MSC_VER) && _MSC_VER < 1400
    // turn this warning back on
    #pragma warning(default:4805)
    #endif

    #endif // DLIB_VECTOr_H_