// Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2013, 2014. // Modifications copyright (c) 2013, 2014 Oracle and/or its affiliates. // 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) // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_RESULT_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_RESULT_HPP #include #include #include #include #include #include #include #include // TEMP - move this header to geometry/detail #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 // TODO add height? template class matrix { BOOST_STATIC_ASSERT(Width == 2 || Width == 3); public: static const std::size_t size = Width * Width; inline matrix() { ::memset(m_array, 'F', size); } template inline char get() const { static const bool in_bounds = F1 * Width + F2 < size; return get_dispatch(integral_constant()); } template inline void set() { static const bool in_bounds = F1 * Width + F2 < size; set_dispatch(integral_constant()); } template inline void update() { static const bool in_bounds = F1 * Width + F2 < size; update_dispatch(integral_constant()); } inline const char * data() const { return m_array; } private: template inline char get_dispatch(integral_constant) const { return m_array[F1 * Width + F2]; } template inline char get_dispatch(integral_constant) const { return 'F'; } template inline void set_dispatch(integral_constant) { BOOST_STATIC_ASSERT(('0' <= V && V <= '9') || V == 'T' || V == 'F'); m_array[F1 * Width + F2] = V; } template inline void set_dispatch(integral_constant) {} template inline void update_dispatch(integral_constant) { BOOST_STATIC_ASSERT('0' <= D && D <= '9'); char c = m_array[F1 * Width + F2]; if ( D > c || c > '9') m_array[F1 * Width + F2] = D; } template inline void update_dispatch(integral_constant) {} char m_array[size]; }; // TODO add EnableDimensions parameter? struct matrix9 {}; //struct matrix4 {}; // matrix_width template struct matrix_width : not_implemented {}; template <> struct matrix_width { static const std::size_t value = 3; }; // matrix_handler template class matrix_handler : private matrix::value> { typedef matrix::value> base_t; public: typedef std::string result_type; static const bool interrupt = false; matrix_handler(Matrix const&) {} result_type result() const { return std::string(this->data(), this->data() + base_t::size); } template inline bool may_update() const { BOOST_STATIC_ASSERT('0' <= D && D <= '9'); char const c = static_cast(*this).template get(); return D > c || c > '9'; } //template //inline char get() const //{ // return static_cast(*this).template get(); //} template inline void set() { static_cast(*this).template set(); } template inline void update() { static_cast(*this).template update(); } }; // RUN-TIME MASKS // mask9 class mask9 { public: static const std::size_t width = 3; // TEMP inline mask9(std::string const& de9im_mask) { // TODO: throw an exception here? BOOST_ASSERT(de9im_mask.size() == 9); ::memcpy(m_mask, de9im_mask.c_str(), 9); } template inline char get() const { return m_mask[F1 * 3 + F2]; } private: char m_mask[9]; }; // 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(m); } template static inline bool check(char m) { if ( V >= '0' && V <= '9' ) { return m == 'F' || ( m < V && m >= '0' && m <= '9' ); } else if ( 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() 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(Mask const& mask, Matrix const& matrix) { return check_dispatch::apply(mask, matrix); } // matrix_width template <> struct matrix_width { static const std::size_t value = 3; }; 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; }; // matrix_handler template class mask_handler : private matrix::value> { typedef matrix::value> base_t; public: typedef bool result_type; bool interrupt; inline mask_handler(Mask const& m) : interrupt(false) , m_mask(m) {} result_type result() const { return !interrupt && check(m_mask, static_cast(*this)); } template inline bool may_update() const { return detail::relate::may_update( m_mask, static_cast(*this) ); } //template //inline char get() const //{ // return static_cast(*this).template get(); //} 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; }; // STATIC MASKS // static_mask template class static_mask { typedef boost::mpl::vector_c < char, II, IB, IE, BI, BB, BE, EI, EB, EE > vector_type; public: template struct get { BOOST_STATIC_ASSERT(F1 * 3 + F2 < boost::mpl::size::value); static const char value = boost::mpl::at_c::type::value; }; }; // static_should_handle_element template struct static_should_handle_element_dispatch { static const char mask_el = StaticMask::template 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 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 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 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 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 { 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<3> { typedef matrix<3> base_t; public: typedef bool result_type; bool interrupt; inline static_mask_handler(StaticMask const& /*dummy*/) : interrupt(false) {} result_type result() const { return (!Interrupt || !interrupt) && static_check:: apply(static_cast(*this)); } template inline bool may_update() const { return static_may_update:: apply(static_cast(*this)); } template static inline bool expects() { return static_should_handle_element::value; } //template //inline char get() const //{ // return base_t::template get(); //} 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_t::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_t::template update(); } // else template inline void update_dispatch(integral_constant) {} }; // OPERATORS template inline boost::tuples::cons< Mask1, boost::tuples::cons > operator||(Mask1 const& m1, Mask2 const& m2) { namespace bt = boost::tuples; return bt::cons< Mask1, bt::cons > ( m1, bt::cons(m2, bt::null_type()) ); } template inline typename index::detail::tuples::push_back< boost::tuples::cons, Mask >::type operator||(boost::tuples::cons const& t, Mask const& m) { namespace bt = boost::tuples; return index::detail::tuples::push_back< bt::cons, Mask >::apply(t, m); } // PREDEFINED MASKS // TODO: // 1. specialize for simplified masks if available // e.g. for TOUCHES use 1 mask for A/A // 2. Think about dimensions > 2 e.g. should TOUCHES be true // if the interior of the Areal overlaps the boundary of the Volumetric // like it's true for Linear/Areal // EQUALS template struct static_mask_equals_type { typedef static_mask<'T', '*', 'F', '*', '*', 'F', 'F', 'F', '*'> type; // wikipedia //typedef static_mask<'T', 'F', 'F', 'F', 'T', 'F', 'F', 'F', 'T'> type; // OGC }; // DISJOINT typedef static_mask<'F', 'F', '*', 'F', 'F', '*', '*', '*', '*'> static_mask_disjoint; // TOUCHES - NOT P/P template ::value, std::size_t Dim2 = topological_dimension::value> struct static_mask_touches_impl { typedef boost::mpl::vector< static_mask<'F', 'T', '*', '*', '*', '*', '*', '*', '*'>, static_mask<'F', '*', '*', 'T', '*', '*', '*', '*', '*'>, static_mask<'F', '*', '*', '*', 'T', '*', '*', '*', '*'> > type; }; // According to OGC, doesn't apply to P/P // Using the above mask the result would be always false template struct static_mask_touches_impl : not_implemented::type, typename geometry::tag::type> {}; template struct static_mask_touches_type : static_mask_touches_impl {}; // WITHIN typedef static_mask<'T', '*', 'F', '*', '*', 'F', '*', '*', '*'> static_mask_within; // COVERED_BY (non OGC) typedef boost::mpl::vector< static_mask<'T', '*', 'F', '*', '*', 'F', '*', '*', '*'>, static_mask<'*', 'T', 'F', '*', '*', 'F', '*', '*', '*'>, static_mask<'*', '*', 'F', 'T', '*', 'F', '*', '*', '*'>, static_mask<'*', '*', 'F', '*', 'T', 'F', '*', '*', '*'> > static_mask_covered_by; // CROSSES // dim(G1) < dim(G2) - P/L P/A L/A template ::value, std::size_t Dim2 = topological_dimension::value, bool D1LessD2 = (Dim1 < Dim2) > struct static_mask_crosses_impl { typedef static_mask<'T', '*', 'T', '*', '*', '*', '*', '*', '*'> type; }; // TODO: I'm not sure if this one below should be available! // dim(G1) > dim(G2) - L/P A/P A/L template struct static_mask_crosses_impl { typedef static_mask<'T', '*', '*', '*', '*', '*', 'T', '*', '*'> type; }; // dim(G1) == dim(G2) - P/P A/A template struct static_mask_crosses_impl : not_implemented::type, typename geometry::tag::type> {}; // dim(G1) == 1 && dim(G2) == 1 - L/L template struct static_mask_crosses_impl { typedef static_mask<'0', '*', '*', '*', '*', '*', '*', '*', '*'> type; }; template struct static_mask_crosses_type : static_mask_crosses_impl {}; // OVERLAPS // dim(G1) != dim(G2) - NOT P/P, L/L, A/A template ::value, std::size_t Dim2 = topological_dimension::value > struct static_mask_overlaps_impl : not_implemented::type, typename geometry::tag::type> {}; // dim(G1) == D && dim(G2) == D - P/P A/A template struct static_mask_overlaps_impl { typedef static_mask<'T', '*', 'T', '*', '*', '*', 'T', '*', '*'> type; }; // dim(G1) == 1 && dim(G2) == 1 - L/L template struct static_mask_overlaps_impl { typedef static_mask<'1', '*', 'T', '*', '*', '*', 'T', '*', '*'> type; }; template struct static_mask_overlaps_type : static_mask_overlaps_impl {}; // RESULTS/HANDLERS UTILS 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); } template inline void set(Result & res) { res.template set(); res.template set(); res.template set(); res.template set(); res.template set(); res.template set(); res.template set(); res.template set(); res.template set(); } template inline void set(Result & res) { res.template set(); res.template set(); res.template set(); res.template set(); res.template set(); res.template set(); res.template set(); res.template set(); res.template set(); } 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); } 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); } template inline Result return_result() { Result res; set(res); return res; } 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