inline
+int point_in_geometry(P const& p, G const& g)
+{
+ typedef typename point_type::type point_type1;
+ typedef typename point_type::type point_type2;
+
+ typedef typename strategy::within::services::default_strategy
+ <
+ typename tag::type,
+ typename tag::type,
+ typename tag::type,
+ typename tag_cast::type, areal_tag>::type,
+ typename tag_cast
+ <
+ typename cs_tag::type, spherical_tag
+ >::type,
+ typename tag_cast
+ <
+ typename cs_tag::type, spherical_tag
+ >::type,
+ P,
+ G
+ >::type strategy_type;
+
+ return point_in_geometry(p, g, strategy_type());
+}
+
+}} // namespace detail::within
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_POINT_IN_GEOMETRY_HPP
diff --git a/include/boost/geometry/algorithms/detail/within/within_no_turns.hpp b/include/boost/geometry/algorithms/detail/within/within_no_turns.hpp
new file mode 100644
index 000000000..3540985af
--- /dev/null
+++ b/include/boost/geometry/algorithms/detail/within/within_no_turns.hpp
@@ -0,0 +1,216 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// This file was modified by Oracle on 2013.
+// Modifications copyright (c) 2013, Oracle and/or its affiliates.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// 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_WITHIN_WITHIN_NO_TURNS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_WITHIN_NO_TURNS_HPP
+
+#include
+#include
+
+namespace boost { namespace geometry {
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace within {
+
+// returns true if G1 is within G2
+// this function should be called only if there are no intersection points
+// otherwise it may return invalid result
+// e.g. when non-first point of G1 is outside G2 or when some rings of G1 are the same as rings of G2
+
+template ::type, typename T2 = typename geometry::tag::type>
+struct within_no_turns_dispatch
+{
+ template static inline
+ bool apply(G1 const& g1, G2 const& g2, S const& s)
+ {
+ typedef typename geometry::point_type::type point1_type;
+ point1_type p;
+ if ( !geometry::point_on_border(p, g1) )
+ return false;
+
+ return point_in_geometry(p, g2, s) >= 0;
+ }
+};
+
+template
+struct within_no_turns_dispatch
+{
+ template static inline
+ bool apply(G1 const& g1, G2 const& g2, S const& s)
+ {
+ typedef typename geometry::point_type::type point1_type;
+ typedef typename geometry::point_type::type point2_type;
+ point1_type p;
+ if ( !geometry::point_on_border(p, g1) )
+ return false;
+ // check if one of ring points is outside the polygon
+ if ( point_in_geometry(p, g2, s) < 0 )
+ return false;
+ // Now check if holes of G2 aren't inside G1
+ typedef typename boost::range_const_iterator
+ <
+ typename geometry::interior_type::type
+ >::type iterator;
+ for ( iterator it = boost::begin(geometry::interior_rings(g2)) ;
+ it != boost::end(geometry::interior_rings(g2)) ;
+ ++it )
+ {
+ point2_type p;
+ if ( !geometry::point_on_border(p, *it) )
+ return false;
+ if ( point_in_geometry(p, g1, s) > 0 )
+ return false;
+ }
+ return true;
+ }
+};
+
+template
+struct within_no_turns_dispatch
+{
+ template static inline
+ bool apply(G1 const& g1, G2 const& g2, S const& s)
+ {
+ typedef typename geometry::point_type::type point1_type;
+ typedef typename geometry::point_type::type point2_type;
+ point1_type p;
+ if ( !geometry::point_on_border(p, g1) )
+ return false;
+ // check if one of ring points is outside the polygon
+ if ( point_in_geometry(p, g2, s) < 0 )
+ return false;
+ // Now check if holes of G2 aren't inside G1
+ typedef typename boost::range_const_iterator
+ <
+ typename geometry::interior_type::type
+ >::type iterator2;
+ for ( iterator2 it = boost::begin(geometry::interior_rings(g2)) ;
+ it != boost::end(geometry::interior_rings(g2)) ;
+ ++it )
+ {
+ point2_type p2;
+ if ( !geometry::point_on_border(p2, *it) )
+ return false;
+ // if the hole of G2 is inside G1
+ if ( point_in_geometry(p2, g1, s) > 0 )
+ {
+ // if it's also inside one of the G1 holes, it's ok
+ bool ok = false;
+ typedef typename boost::range_const_iterator
+ <
+ typename geometry::interior_type::type
+ >::type iterator1;
+ for ( iterator1 it1 = boost::begin(geometry::interior_rings(g1)) ;
+ it1 != boost::end(geometry::interior_rings(g1)) ;
+ ++it1 )
+ {
+ if ( point_in_geometry(p2, *it1, s) < 0 )
+ {
+ ok = true;
+ break;
+ }
+ }
+ if ( !ok )
+ return false;
+ }
+ }
+ return true;
+ }
+};
+
+// TODO: later move it to directory boost/geometry/multi/algorithms/detail/within
+
+template ::type,
+ typename T2 = typename geometry::tag::type,
+ bool IsMulti1 = boost::is_base_of::value,
+ bool IsMulti2 = boost::is_base_of::value>
+struct within_no_turns_multi_dispatch
+{
+ template static inline
+ bool apply(G1 const& g1, G2 const& g2, S const& s)
+ {
+ return within_no_turns_dispatch::apply(g1, g2, s);
+ }
+};
+
+template
+struct within_no_turns_multi_dispatch
+{
+ template static inline
+ bool apply(G1 const& g1, G2 const& g2, S const& s)
+ {
+ // All values of G1 must be inside G2
+ typedef typename boost::range_value::type subgeometry1;
+ typedef typename boost::range_const_iterator::type iterator;
+ for ( iterator it = boost::begin(g1) ; it != boost::end(g1) ; ++it )
+ {
+ if ( !within_no_turns_dispatch::apply(*it, g2, s) )
+ return false;
+ }
+ return true;
+ }
+};
+
+template
+struct within_no_turns_multi_dispatch
+{
+ template static inline
+ bool apply(G1 const& g1, G2 const& g2, S const& s)
+ {
+ // G1 must be within at least one value of G2
+ typedef typename boost::range_value::type subgeometry2;
+ typedef typename boost::range_const_iterator::type iterator;
+ for ( iterator it = boost::begin(g2) ; it != boost::end(g2) ; ++it )
+ {
+ if ( within_no_turns_dispatch::apply(g1, *it, s) )
+ return true;
+ }
+ return false;
+ }
+};
+
+template
+struct within_no_turns_multi_dispatch
+{
+ template static inline
+ bool apply(G1 const& g1, G2 const& g2, S const& s)
+ {
+ // each value of G1 must be inside at least one value of G2
+ typedef typename boost::range_value::type subgeometry1;
+ typedef typename boost::range_const_iterator::type iterator;
+ for ( iterator it = boost::begin(g1) ; it != boost::end(g1) ; ++it )
+ {
+ if ( !within_no_turns_multi_dispatch::apply(*it, g2, s) )
+ return false;
+ }
+ return true;
+ }
+};
+
+template inline
+bool within_no_turns(G1 const& g1, G2 const& g2, S const& s)
+{
+ return within_no_turns_multi_dispatch::apply(g1, g2, s);
+}
+
+}} // namespace detail::within
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_WITHIN_NO_TURNS_HPP
diff --git a/include/boost/geometry/algorithms/disjoint.hpp b/include/boost/geometry/algorithms/disjoint.hpp
index d7bc4d58a..239f83145 100644
--- a/include/boost/geometry/algorithms/disjoint.hpp
+++ b/include/boost/geometry/algorithms/disjoint.hpp
@@ -5,6 +5,9 @@
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland.
+// This file was modified by Oracle on 2013.
+// Modifications copyright (c) 2013, Oracle and/or its affiliates.
+
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -42,6 +45,10 @@
#include
+#include
+#include
+#include
+
namespace boost { namespace geometry
{
@@ -115,21 +122,20 @@ struct disjoint_linear
typedef overlay::turn_info turn_info;
std::deque turns;
+ static const bool reverse1 = overlay::do_reverse::value>::value; // should be false
+ static const bool reverse2 = overlay::do_reverse::value>::value; // should be false
+
// Specify two policies:
// 1) Stop at any intersection
// 2) In assignment, include also degenerate points (which are normally skipped)
disjoint_interrupt_policy policy;
geometry::get_turns
<
- false, false,
+ reverse1, reverse2,
assign_disjoint_policy
>(geometry1, geometry2, detail::no_rescale_policy(), turns, policy);
- if (policy.has_intersections)
- {
- return false;
- }
- return true;
+ return !policy.has_intersections;
}
};
@@ -230,6 +236,59 @@ struct disjoint_linestring_box
}
};
+template
+struct disjoint_point_linear
+{
+ static inline
+ bool apply(Point const& pt, Geometry const& g)
+ {
+ return !geometry::covered_by(pt, g);
+ }
+};
+
+// computes disjointness of segment and linestring
+template
+struct disjoint_linestring_segment
+{
+ static inline
+ bool apply(Linestring const& ls, Segment const& seg)
+ {
+ return disjoint_linear
+ <
+ Linestring, segment_view
+ >::apply(ls, geometry::segment_view(seg));
+ }
+};
+
+template
+struct disjoint_linear_areal
+{
+ static inline
+ bool apply(Geometry1 const& g1, Geometry2 const& g2)
+ {
+ // if there are intersections - return false
+ if ( !disjoint_linear::apply(g1, g2) )
+ return false;
+
+ typedef typename point_type::type point1_type;
+ point1_type p;
+ geometry::point_on_border(p, g1);
+ return !geometry::covered_by(p, g2);
+ }
+};
+
+template
+struct disjoint_segment_areal
+{
+ static inline
+ bool apply(Segment const& seg, Geometry const& g)
+ {
+ return disjoint_linear_areal
+ <
+ segment_view, Geometry
+ >::apply(segment_view(seg), g);
+ }
+};
}} // namespace detail::disjoint
#endif // DOXYGEN_NO_DETAIL
@@ -312,11 +371,6 @@ struct disjoint
: detail::disjoint::disjoint_segment
{};
-template
-struct disjoint
- : detail::disjoint::disjoint_linear
-{};
-
template
struct disjoint
: detail::disjoint::disjoint_segment_box
@@ -327,6 +381,72 @@ struct disjoint
{};
+//template
+//struct disjoint
+// : detail::disjoint::disjoint_linear
+//{};
+template
+struct disjoint
+ : detail::disjoint::disjoint_linestring_segment
+{};
+
+template
+struct disjoint
+ : detail::disjoint::disjoint_segment_areal
+{};
+
+template
+struct disjoint
+{
+ static inline
+ bool apply(Polygon const& g1, Segment const& g2)
+ {
+ return detail::disjoint::disjoint_segment_areal::apply(g2, g1);
+ }
+};
+
+template
+struct disjoint
+ : public detail::disjoint::disjoint_linear_areal
+{};
+
+template
+struct disjoint
+ : public detail::disjoint::disjoint_linear_areal
+{};
+
+// move the following specializations to multi/algorithms/disjoint.hpp?
+
+template
+struct disjoint
+ : public detail::disjoint::disjoint_linear_areal
+{};
+
+template
+struct disjoint
+ : public detail::disjoint::disjoint_linear_areal
+{};
+
+template
+struct disjoint
+ : public detail::disjoint::disjoint_linear_areal
+{};
+
+template
+struct disjoint
+ : public detail::disjoint::disjoint_linear_areal
+{};
+
+template
+struct disjoint
+ : public detail::disjoint::disjoint_point_linear
+{};
+
+template
+struct disjoint
+ : public detail::disjoint::disjoint_point_linear
+{};
+
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
diff --git a/include/boost/geometry/algorithms/touches.hpp b/include/boost/geometry/algorithms/touches.hpp
index 18c37c86d..2523a26d2 100644
--- a/include/boost/geometry/algorithms/touches.hpp
+++ b/include/boost/geometry/algorithms/touches.hpp
@@ -5,6 +5,9 @@
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland.
+// This file was modified by Oracle on 2013.
+// Modifications copyright (c) 2013, Oracle and/or its affiliates.
+
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -26,6 +29,7 @@
#include
#include
+#include
namespace boost { namespace geometry
{
@@ -34,55 +38,210 @@ namespace boost { namespace geometry
namespace detail { namespace touches
{
-template
-inline bool ok_for_touch(Turn const& turn)
+struct areal_interrupt_policy
{
- return turn.both(detail::overlay::operation_union)
- || turn.both(detail::overlay::operation_blocked)
- || turn.combination(detail::overlay::operation_union, detail::overlay::operation_blocked)
- ;
-}
+ static bool const enabled = true;
+ bool found_touch;
+ bool found_not_touch;
-template
-inline bool has_only_turns(Turns const& turns)
-{
- bool has_touch = false;
- typedef typename boost::range_iterator::type iterator_type;
- for (iterator_type it = boost::begin(turns); it != boost::end(turns); ++it)
+ // dummy variable required by self_get_turn_points::get_turns
+ static bool const has_intersections = false;
+
+ inline bool result()
{
- if (it->has(detail::overlay::operation_intersection))
+ return found_touch && !found_not_touch;
+ }
+
+ inline areal_interrupt_policy()
+ : found_touch(false), found_not_touch(false)
+ {}
+
+ template
+ inline bool apply(Range const& range)
+ {
+ // if already rejected (temp workaround?)
+ if ( found_not_touch )
+ return true;
+
+ typedef typename boost::range_iterator::type iterator;
+ for ( iterator it = boost::begin(range) ; it != boost::end(range) ; ++it )
{
- return false;
+ if ( it->has(overlay::operation_intersection) )
+ {
+ found_not_touch = true;
+ return true;
+ }
+
+ switch(it->method)
+ {
+ case overlay::method_crosses:
+ found_not_touch = true;
+ return true;
+ case overlay::method_equal:
+ // Segment spatially equal means: at the right side
+ // the polygon internally overlaps. So return false.
+ found_not_touch = true;
+ return true;
+ case overlay::method_touch:
+ case overlay::method_touch_interior:
+ case overlay::method_collinear:
+ if ( ok_for_touch(*it) )
+ {
+ found_touch = true;
+ }
+ else
+ {
+ found_not_touch = true;
+ return true;
+ }
+ break;
+ case overlay::method_none :
+ case overlay::method_disjoint :
+ case overlay::method_error :
+ break;
+ }
}
- switch(it->method)
+ return false;
+ }
+
+ template
+ inline bool ok_for_touch(Turn const& turn)
+ {
+ return turn.both(overlay::operation_union)
+ || turn.both(overlay::operation_blocked)
+ || turn.combination(overlay::operation_union, overlay::operation_blocked)
+ ;
+ }
+};
+
+template
+struct linear_areal_interrupt_policy
+{
+ static bool const enabled = true;
+ bool found_touch;
+ bool found_not_touch;
+
+ Linear const& linear;
+
+ // dummy variable required by self_get_turn_points::get_turns
+ static bool const has_intersections = false;
+
+ inline bool result()
+ {
+ return found_touch && !found_not_touch;
+ }
+
+ inline linear_areal_interrupt_policy(Linear const& l)
+ : found_touch(false), found_not_touch(false), linear(l)
+ {}
+
+ template
+ inline bool apply(Range const& range)
+ {
+ // if already rejected (temp workaround?)
+ if ( found_not_touch )
+ return true;
+
+ typedef typename boost::range_iterator::type iterator;
+ for ( iterator it = boost::begin(range) ; it != boost::end(range) ; ++it )
{
- case detail::overlay::method_crosses:
- return false;
- case detail::overlay::method_equal:
- // Segment spatially equal means: at the right side
- // the polygon internally overlaps. So return false.
- return false;
- case detail::overlay::method_touch:
- case detail::overlay::method_touch_interior:
- case detail::overlay::method_collinear:
- if (ok_for_touch(*it))
+ if ( it->operations[0].operation == overlay::operation_intersection )
+ {
+ if ( it->operations[1].operation == overlay::operation_union &&
+ is_turn_on_last_point(*it) )
{
- has_touch = true;
+ found_touch = true;
+ continue;
}
else
{
- return false;
+ found_not_touch = true;
+ return true;
}
- break;
- case detail::overlay::method_none :
- case detail::overlay::method_disjoint :
- case detail::overlay::method_error :
- break;
+ }
+
+ switch(it->method)
+ {
+ case overlay::method_crosses:
+ found_not_touch = true;
+ return true;
+ case overlay::method_equal:
+ case overlay::method_touch:
+ case overlay::method_touch_interior:
+ case overlay::method_collinear:
+ if ( ok_for_touch(*it) )
+ {
+ found_touch = true;
+ }
+ else
+ {
+ found_not_touch = true;
+ return true;
+ }
+ break;
+ case overlay::method_none :
+ case overlay::method_disjoint :
+ case overlay::method_error :
+ break;
+ }
}
+
+ return false;
}
- return has_touch;
-}
+
+ template
+ inline bool ok_for_touch(Turn const& turn)
+ {
+ return turn.both(overlay::operation_union)
+ || turn.both(overlay::operation_blocked)
+ || turn.combination(overlay::operation_union, overlay::operation_blocked)
+
+ || turn.both(overlay::operation_continue)
+ || turn.combination(overlay::operation_union, overlay::operation_intersection)
+ ;
+ }
+
+ template
+ inline bool is_turn_on_last_point(Turn const& turn)
+ {
+ typename sub_geometry::result_type::type
+ g = sub_geometry::get(linear, turn.operations[0].seg_id);
+
+ std::size_t s = boost::size(g);
+
+ if ( s == 0 )
+ return false; // shouldn't return here
+ else if ( s == 1 )
+ return equals::equals_point_point(turn.point, *boost::begin(g)); // nor here
+ else
+ return equals::equals_point_point(turn.point, *(boost::end(g)-1));
+ }
+};
+
+template
+struct turns_count_interrupt_policy
+{
+ static bool const enabled = true;
+ std::size_t turns_count;
+
+ // dummy variable required by self_get_turn_points::get_turns
+ static bool const has_intersections = false;
+
+ inline turns_count_interrupt_policy()
+ : turns_count(0)
+ {}
+
+ template
+ inline bool apply(Range const& range)
+ {
+ turns_count += boost::size(range);
+ if ( Max < turns_count )
+ return true;
+ return false;
+ }
+};
+
template
struct check_each_ring_for_within
@@ -107,6 +266,8 @@ struct check_each_ring_for_within
}
};
+// TODO: currently this function checks if a point of at least one range from g2 is within g1
+// shouldn't it check the opposite?
template
inline bool rings_containing(FirstGeometry const& geometry1,
@@ -117,10 +278,180 @@ inline bool rings_containing(FirstGeometry const& geometry1,
return checker.has_within;
}
+template
+struct areal_areal
+{
+ static inline
+ bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
+ {
+ typedef detail::overlay::turn_info
+ <
+ typename geometry::point_type::type
+ > turn_info;
+
+ typedef detail::overlay::get_turn_info
+ <
+ detail::overlay::assign_null_policy
+ > policy_type;
+
+ std::deque turns;
+ detail::touches::areal_interrupt_policy policy;
+ boost::geometry::get_turns
+ <
+ detail::overlay::do_reverse::value>::value,
+ detail::overlay::do_reverse::value>::value,
+ detail::overlay::assign_null_policy
+ >(geometry1, geometry2, detail::no_rescale_policy(), turns, policy);
+
+ return policy.result()
+ && ! geometry::detail::touches::rings_containing(geometry1, geometry2)
+ && ! geometry::detail::touches::rings_containing(geometry2, geometry1);
+ }
+};
+
+template
+struct linear_areal
+{
+ static inline
+ bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
+ {
+ typedef detail::overlay::turn_info
+ <
+ typename geometry::point_type::type
+ > turn_info;
+
+ typedef detail::overlay::get_turn_info
+ <
+ detail::overlay::assign_null_policy
+ > policy_type;
+
+ std::deque turns;
+ detail::touches::linear_areal_interrupt_policy policy(geometry1);
+ boost::geometry::get_turns
+ <
+ detail::overlay::do_reverse::value>::value,
+ detail::overlay::do_reverse::value>::value,
+ detail::overlay::assign_null_policy
+ >(geometry1, geometry2, detail::no_rescale_policy(), turns, policy);
+
+ return policy.result()
+ && ! geometry::detail::touches::rings_containing(geometry2, geometry1);
+ }
+};
+
+template
+struct point_geometry
+{
+ static inline
+ bool apply(Point const& point, Geometry const& geometry)
+ {
+ return detail::within::point_in_geometry(point, geometry) == 0;
+ }
+};
+
+template
+struct linestring_linestring
+{
+ static inline
+ bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
+ {
+ std::size_t s1 = boost::size(geometry1);
+ std::size_t s2 = boost::size(geometry2);
+ // TODO: throw on empty input?
+ if ( s1 == 0 || s2 == 0 )
+ return false;
+
+ typedef detail::overlay::turn_info
+ <
+ typename geometry::point_type::type
+ > turn_info;
+
+ typedef detail::overlay::get_turn_info
+ <
+ detail::overlay::assign_null_policy
+ > policy_type;
+
+ std::deque