// Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2013-2016. // Modifications copyright (c) 2013-2016 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_RESULT_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_RESULT_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace relate { enum field { interior = 0, boundary = 1, exterior = 2 }; // TODO: IF THE RESULT IS UPDATED WITH THE MAX POSSIBLE VALUE FOR SOME PAIR OF GEOEMTRIES // THE VALUE ALREADY STORED MUSN'T BE CHECKED // update() calls chould be replaced with set() in those cases // but for safety reasons (STATIC_ASSERT) we should check if parameter D is valid and set() doesn't do that // so some additional function could be added, e.g. set_dim() // --------------- MATRIX ---------------- // matrix template class matrix { public: typedef char value_type; typedef std::size_t size_type; typedef const char * const_iterator; typedef const_iterator iterator; static const std::size_t static_width = Width; static const std::size_t static_height = Height; static const std::size_t static_size = Width * Height; inline matrix() { ::memset(m_array, 'F', static_size); } template inline char get() const { BOOST_STATIC_ASSERT(F1 < Height && F2 < Width); static const std::size_t index = F1 * Width + F2; BOOST_STATIC_ASSERT(index < static_size); return m_array[index]; } template inline void set() { BOOST_STATIC_ASSERT(F1 < Height && F2 < Width); static const std::size_t index = F1 * Width + F2; BOOST_STATIC_ASSERT(index < static_size); m_array[index] = V; } inline char operator[](std::size_t index) const { BOOST_GEOMETRY_ASSERT(index < static_size); return m_array[index]; } inline const_iterator begin() const { return m_array; } inline const_iterator end() const { return m_array + static_size; } inline static std::size_t size() { return static_size; } inline const char * data() const { return m_array; } inline std::string str() const { return std::string(m_array, static_size); } private: char m_array[static_size]; }; // matrix_handler template class matrix_handler { public: typedef Matrix result_type; static const bool interrupt = false; matrix_handler() {} result_type const& result() const { return m_matrix; } result_type const& matrix() const { return m_matrix; } result_type & matrix() { return m_matrix; } template inline bool may_update() const { BOOST_STATIC_ASSERT('0' <= D && D <= '9'); char const c = m_matrix.template get(); return D > c || c > '9'; } template inline void set() { static const bool in_bounds = F1 < Matrix::static_height && F2 < Matrix::static_width; typedef boost::integral_constant in_bounds_t; set_dispatch(in_bounds_t()); } template inline void update() { static const bool in_bounds = F1 < Matrix::static_height && F2 < Matrix::static_width; typedef boost::integral_constant in_bounds_t; update_dispatch(in_bounds_t()); } private: template inline void set_dispatch(integral_constant) { static const std::size_t index = F1 * Matrix::static_width + F2; BOOST_STATIC_ASSERT(index < Matrix::static_size); BOOST_STATIC_ASSERT(('0' <= V && V <= '9') || V == 'T' || V == 'F'); m_matrix.template set(); } template inline void set_dispatch(integral_constant) {} template inline void update_dispatch(integral_constant) { static const std::size_t index = F1 * Matrix::static_width + F2; BOOST_STATIC_ASSERT(index < Matrix::static_size); BOOST_STATIC_ASSERT('0' <= D && D <= '9'); char const c = m_matrix.template get(); if ( D > c || c > '9') m_matrix.template set(); } template inline void update_dispatch(integral_constant) {} Matrix m_matrix; }; // --------------- RUN-TIME MASK ---------------- // run-time mask template class mask { public: static const std::size_t static_width = Width; static const std::size_t static_height = Height; static const std::size_t static_size = Width * Height; inline mask(const char * s) { char * it = m_array; char * const last = m_array + static_size; for ( ; it != last && *s != '\0' ; ++it, ++s ) { char c = *s; check_char(c); *it = c; } if ( it != last ) { ::memset(it, '*', last - it); } } inline mask(const char * s, std::size_t count) { if ( count > static_size ) { count = static_size; } if ( count > 0 ) { std::for_each(s, s + count, check_char); ::memcpy(m_array, s, count); } if ( count < static_size ) { ::memset(m_array + count, '*', static_size - count); } } template inline char get() const { BOOST_STATIC_ASSERT(F1 < Height && F2 < Width); static const std::size_t index = F1 * Width + F2; BOOST_STATIC_ASSERT(index < static_size); return m_array[index]; } private: static inline void check_char(char c) { bool const is_valid = c == '*' || c == 'T' || c == 'F' || ( c >= '0' && c <= '9' ); if ( !is_valid ) { BOOST_THROW_EXCEPTION(geometry::invalid_input_exception()); } } char m_array[static_size]; }; // interrupt() template struct interrupt_dispatch { template static inline bool apply(Mask const&) { return false; } }; template struct interrupt_dispatch { template static inline bool apply(Mask const& mask) { char m = mask.template get(); return check_element(m); } template static inline bool check_element(char m) { if ( BOOST_GEOMETRY_CONDITION(V >= '0' && V <= '9') ) { return m == 'F' || ( m < V && m >= '0' && m <= '9' ); } else if ( BOOST_GEOMETRY_CONDITION(V == 'T') ) { return m == 'F'; } return false; } }; template ::value> struct interrupt_dispatch_tuple { template static inline bool apply(Masks const& masks) { typedef typename boost::tuples::element::type mask_type; mask_type const& mask = boost::get(masks); return interrupt_dispatch::template apply(mask) && interrupt_dispatch_tuple::template apply(masks); } }; template struct interrupt_dispatch_tuple { template static inline bool apply(Masks const& ) { return true; } }; //template //struct interrupt_dispatch, true> //{ // typedef boost::tuple mask_type; // template // static inline bool apply(mask_type const& mask) // { // return interrupt_dispatch_tuple::template apply(mask); // } //}; template struct interrupt_dispatch, true> { typedef boost::tuples::cons mask_type; template static inline bool apply(mask_type const& mask) { return interrupt_dispatch_tuple::template apply(mask); } }; template inline bool interrupt(Mask const& mask) { return interrupt_dispatch ::template apply(mask); } // may_update() template struct may_update_dispatch { template static inline bool apply(Mask const& mask, Matrix const& matrix) { BOOST_STATIC_ASSERT('0' <= D && D <= '9'); char const m = mask.template get(); if ( m == 'F' ) { return true; } else if ( m == 'T' ) { char const c = matrix.template get(); return c == 'F'; // if it's T or between 0 and 9, the result will be the same } else if ( m >= '0' && m <= '9' ) { char const c = matrix.template get(); return D > c || c > '9'; } return false; } }; template ::value> struct may_update_dispatch_tuple { template static inline bool apply(Masks const& masks, Matrix const& matrix) { typedef typename boost::tuples::element::type mask_type; mask_type const& mask = boost::get(masks); return may_update_dispatch::template apply(mask, matrix) || may_update_dispatch_tuple::template apply(masks, matrix); } }; template struct may_update_dispatch_tuple { template static inline bool apply(Masks const& , Matrix const& ) { return false; } }; //template //struct may_update_dispatch< boost::tuple > //{ // typedef boost::tuple mask_type; // template // static inline bool apply(mask_type const& mask, Matrix const& matrix) // { // return may_update_dispatch_tuple::template apply(mask, matrix); // } //}; template struct may_update_dispatch< boost::tuples::cons > { typedef boost::tuples::cons mask_type; template static inline bool apply(mask_type const& mask, Matrix const& matrix) { return may_update_dispatch_tuple::template apply(mask, matrix); } }; template inline bool may_update(Mask const& mask, Matrix const& matrix) { return may_update_dispatch ::template apply(mask, matrix); } // check_matrix() template struct check_dispatch { template static inline bool apply(Mask const& mask, Matrix const& matrix) { return per_one(mask, matrix) && per_one(mask, matrix) && per_one(mask, matrix) && per_one(mask, matrix) && per_one(mask, matrix) && per_one(mask, matrix) && per_one(mask, matrix) && per_one(mask, matrix) && per_one(mask, matrix); } template static inline bool per_one(Mask const& mask, Matrix const& matrix) { const char mask_el = mask.template get(); const char el = matrix.template get(); if ( mask_el == 'F' ) { return el == 'F'; } else if ( mask_el == 'T' ) { return el == 'T' || ( el >= '0' && el <= '9' ); } else if ( mask_el >= '0' && mask_el <= '9' ) { return el == mask_el; } return true; } }; template ::value> struct check_dispatch_tuple { template static inline bool apply(Masks const& masks, Matrix const& matrix) { typedef typename boost::tuples::element::type mask_type; mask_type const& mask = boost::get(masks); return check_dispatch::apply(mask, matrix) || check_dispatch_tuple::apply(masks, matrix); } }; template struct check_dispatch_tuple { template static inline bool apply(Masks const&, Matrix const&) { return false; } }; //template //struct check_dispatch< boost::tuple > //{ // typedef boost::tuple mask_type; // template // static inline bool apply(mask_type const& mask, Matrix const& matrix) // { // return check_dispatch_tuple::apply(mask, matrix); // } //}; template struct check_dispatch< boost::tuples::cons > { typedef boost::tuples::cons mask_type; template static inline bool apply(mask_type const& mask, Matrix const& matrix) { return check_dispatch_tuple::apply(mask, matrix); } }; template inline bool check_matrix(Mask const& mask, Matrix const& matrix) { return check_dispatch::apply(mask, matrix); } // matrix_width template struct matrix_width { static const std::size_t value = MatrixOrMask::static_width; }; template ::value> struct matrix_width_tuple { static const std::size_t current = matrix_width::type>::value; static const std::size_t next = matrix_width_tuple::value; static const std::size_t value = current > next ? current : next; }; template struct matrix_width_tuple { static const std::size_t value = 0; }; template struct matrix_width< boost::tuples::cons > { static const std::size_t value = matrix_width_tuple< boost::tuples::cons >::value; }; // mask_handler template class mask_handler : private matrix_handler < relate::matrix::value> > { typedef matrix_handler < relate::matrix::value> > base_t; public: typedef bool result_type; bool interrupt; inline explicit mask_handler(Mask const& m) : interrupt(false) , m_mask(m) {} result_type result() const { return !interrupt && check_matrix(m_mask, base_t::matrix()); } template inline bool may_update() const { return detail::relate::may_update( m_mask, base_t::matrix() ); } template inline void set() { if ( relate::interrupt(m_mask) ) { interrupt = true; } else { base_t::template set(); } } template inline void update() { if ( relate::interrupt(m_mask) ) { interrupt = true; } else { base_t::template update(); } } private: Mask const& m_mask; }; // --------------- COMPILE-TIME MASK ---------------- // static_check_characters template < typename Seq, typename First = typename boost::mpl::begin::type, typename Last = typename boost::mpl::end::type > struct static_check_characters : static_check_characters < Seq, typename boost::mpl::next::type > { typedef typename boost::mpl::deref::type type; static const char value = type::value; static const bool is_valid = (value >= '0' && value <= '9') || value == 'T' || value == 'F' || value == '*'; BOOST_MPL_ASSERT_MSG((is_valid), INVALID_STATIC_MASK_CHARACTER, (type)); }; template struct static_check_characters {}; // static_mask template < typename Seq, std::size_t Height, std::size_t Width = Height > struct static_mask { static const std::size_t static_width = Width; static const std::size_t static_height = Height; static const std::size_t static_size = Width * Height; BOOST_STATIC_ASSERT( std::size_t(boost::mpl::size::type::value) == static_size); template struct static_get { BOOST_STATIC_ASSERT(std::size_t(F1) < static_height); BOOST_STATIC_ASSERT(std::size_t(F2) < static_width); static const char value = boost::mpl::at_c::type::value; }; private: // check static_mask characters enum { mask_check = sizeof(static_check_characters) }; }; // static_should_handle_element template struct static_should_handle_element_dispatch { static const char mask_el = StaticMask::template static_get::value; static const bool value = mask_el == 'F' || mask_el == 'T' || ( mask_el >= '0' && mask_el <= '9' ); }; template struct static_should_handle_element_sequence { typedef typename boost::mpl::deref::type StaticMask; static const bool value = static_should_handle_element_dispatch < StaticMask, F1, F2, boost::mpl::is_sequence::value >::value || static_should_handle_element_sequence < typename boost::mpl::next::type, Last, F1, F2 >::value; }; template struct static_should_handle_element_sequence { static const bool value = false; }; template struct static_should_handle_element_dispatch { static const bool value = static_should_handle_element_sequence < typename boost::mpl::begin::type, typename boost::mpl::end::type, F1, F2 >::value; }; template struct static_should_handle_element { static const bool value = static_should_handle_element_dispatch < StaticMask, F1, F2, boost::mpl::is_sequence::value >::value; }; // static_interrupt template struct static_interrupt_dispatch { static const bool value = false; }; template struct static_interrupt_dispatch { static const char mask_el = StaticMask::template static_get::value; static const bool value = ( V >= '0' && V <= '9' ) ? ( mask_el == 'F' || ( mask_el < V && mask_el >= '0' && mask_el <= '9' ) ) : ( ( V == 'T' ) ? mask_el == 'F' : false ); }; template struct static_interrupt_sequence { typedef typename boost::mpl::deref::type StaticMask; static const bool value = static_interrupt_dispatch < StaticMask, V, F1, F2, true, boost::mpl::is_sequence::value >::value && static_interrupt_sequence < typename boost::mpl::next::type, Last, V, F1, F2 >::value; }; template struct static_interrupt_sequence { static const bool value = true; }; template struct static_interrupt_dispatch { static const bool value = static_interrupt_sequence < typename boost::mpl::begin::type, typename boost::mpl::end::type, V, F1, F2 >::value; }; template struct static_interrupt { static const bool value = static_interrupt_dispatch < StaticMask, V, F1, F2, EnableInterrupt, boost::mpl::is_sequence::value >::value; }; // static_may_update template struct static_may_update_dispatch { static const char mask_el = StaticMask::template static_get::value; static const int version = mask_el == 'F' ? 0 : mask_el == 'T' ? 1 : mask_el >= '0' && mask_el <= '9' ? 2 : 3; template static inline bool apply(Matrix const& matrix) { return apply_dispatch(matrix, integral_constant()); } // mask_el == 'F' template static inline bool apply_dispatch(Matrix const& , integral_constant) { return true; } // mask_el == 'T' template static inline bool apply_dispatch(Matrix const& matrix, integral_constant) { char const c = matrix.template get(); return c == 'F'; // if it's T or between 0 and 9, the result will be the same } // mask_el >= '0' && mask_el <= '9' template static inline bool apply_dispatch(Matrix const& matrix, integral_constant) { char const c = matrix.template get(); return D > c || c > '9'; } // else template static inline bool apply_dispatch(Matrix const&, integral_constant) { return false; } }; template struct static_may_update_sequence { typedef typename boost::mpl::deref::type StaticMask; template static inline bool apply(Matrix const& matrix) { return static_may_update_dispatch < StaticMask, D, F1, F2, boost::mpl::is_sequence::value >::apply(matrix) || static_may_update_sequence < typename boost::mpl::next::type, Last, D, F1, F2 >::apply(matrix); } }; template struct static_may_update_sequence { template static inline bool apply(Matrix const& /*matrix*/) { return false; } }; template struct static_may_update_dispatch { template static inline bool apply(Matrix const& matrix) { return static_may_update_sequence < typename boost::mpl::begin::type, typename boost::mpl::end::type, D, F1, F2 >::apply(matrix); } }; template struct static_may_update { template static inline bool apply(Matrix const& matrix) { return static_may_update_dispatch < StaticMask, D, F1, F2, boost::mpl::is_sequence::value >::apply(matrix); } }; // static_check_matrix template struct static_check_dispatch { template static inline bool apply(Matrix const& matrix) { return per_one::apply(matrix) && per_one::apply(matrix) && per_one::apply(matrix) && per_one::apply(matrix) && per_one::apply(matrix) && per_one::apply(matrix) && per_one::apply(matrix) && per_one::apply(matrix) && per_one::apply(matrix); } template struct per_one { static const char mask_el = StaticMask::template static_get::value; static const int version = mask_el == 'F' ? 0 : mask_el == 'T' ? 1 : mask_el >= '0' && mask_el <= '9' ? 2 : 3; template static inline bool apply(Matrix const& matrix) { const char el = matrix.template get(); return apply_dispatch(el, integral_constant()); } // mask_el == 'F' static inline bool apply_dispatch(char el, integral_constant) { return el == 'F'; } // mask_el == 'T' static inline bool apply_dispatch(char el, integral_constant) { return el == 'T' || ( el >= '0' && el <= '9' ); } // mask_el >= '0' && mask_el <= '9' static inline bool apply_dispatch(char el, integral_constant) { return el == mask_el; } // else static inline bool apply_dispatch(char /*el*/, integral_constant) { return true; } }; }; template struct static_check_sequence { typedef typename boost::mpl::deref::type StaticMask; template static inline bool apply(Matrix const& matrix) { return static_check_dispatch < StaticMask, boost::mpl::is_sequence::value >::apply(matrix) || static_check_sequence < typename boost::mpl::next::type, Last >::apply(matrix); } }; template struct static_check_sequence { template static inline bool apply(Matrix const& /*matrix*/) { return false; } }; template struct static_check_dispatch { template static inline bool apply(Matrix const& matrix) { return static_check_sequence < typename boost::mpl::begin::type, typename boost::mpl::end::type >::apply(matrix); } }; template struct static_check_matrix { template static inline bool apply(Matrix const& matrix) { return static_check_dispatch < StaticMask, boost::mpl::is_sequence::value >::apply(matrix); } }; // static_mask_handler template class static_mask_handler : private matrix_handler< matrix<3> > { typedef matrix_handler< relate::matrix<3> > base_type; public: typedef bool result_type; bool interrupt; inline static_mask_handler() : interrupt(false) {} inline explicit static_mask_handler(StaticMask const& /*dummy*/) : interrupt(false) {} result_type result() const { return (!Interrupt || !interrupt) && static_check_matrix::apply(base_type::matrix()); } template inline bool may_update() const { return static_may_update:: apply(base_type::matrix()); } template static inline bool expects() { return static_should_handle_element::value; } template inline void set() { static const bool interrupt_c = static_interrupt::value; static const bool should_handle = static_should_handle_element::value; static const int version = interrupt_c ? 0 : should_handle ? 1 : 2; set_dispatch(integral_constant()); } template inline void update() { static const bool interrupt_c = static_interrupt::value; static const bool should_handle = static_should_handle_element::value; static const int version = interrupt_c ? 0 : should_handle ? 1 : 2; update_dispatch(integral_constant()); } private: // Interrupt && interrupt template inline void set_dispatch(integral_constant) { interrupt = true; } // else should_handle template inline void set_dispatch(integral_constant) { base_type::template set(); } // else template inline void set_dispatch(integral_constant) {} // Interrupt && interrupt template inline void update_dispatch(integral_constant) { interrupt = true; } // else should_handle template inline void update_dispatch(integral_constant) { base_type::template update(); } // else template inline void update_dispatch(integral_constant) {} }; // --------------- UTIL FUNCTIONS ---------------- // set template inline void set(Result & res) { res.template set(); } template struct set_dispatch { template static inline void apply(Result & res) { res.template set(); } }; template struct set_dispatch { template static inline void apply(Result & res) { res.template set(); } }; template inline void set(Result & res) { set_dispatch::apply(res); } // update template inline void update(Result & res) { res.template update(); } template struct update_result_dispatch { template static inline void apply(Result & res) { update(res); } }; template struct update_result_dispatch { template static inline void apply(Result & res) { update(res); } }; template inline void update(Result & res) { update_result_dispatch::apply(res); } // may_update template inline bool may_update(Result const& res) { return res.template may_update(); } template struct may_update_result_dispatch { template static inline bool apply(Result const& res) { return may_update(res); } }; template struct may_update_result_dispatch { template static inline bool apply(Result const& res) { return may_update(res); } }; template inline bool may_update(Result const& res) { return may_update_result_dispatch::apply(res); } // result_dimension template struct result_dimension { BOOST_STATIC_ASSERT(geometry::dimension::value >= 0); static const char value = ( geometry::dimension::value <= 9 ) ? ( '0' + geometry::dimension::value ) : 'T'; }; }} // namespace detail::relate #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_RESULT_HPP