updated boost on windows

This commit is contained in:
Bassem Girgis
2019-08-13 21:48:48 -05:00
parent 7d77d485fd
commit b40a3bee82
5162 changed files with 473027 additions and 116452 deletions

View File

@@ -91,19 +91,23 @@ template <typename Polygon, typename Point>
struct point_to_polygon
{
typedef typename ring_type<Polygon>::type ring_type;
typedef typename ring_return_type<Polygon>::type exterior_ring_type;
typedef typename interior_return_type<Polygon>::type interior_ring_range_type;
static inline void apply(Polygon& polygon, Point const& point,
int ring_index, int = 0)
{
if (ring_index == -1)
{
exterior_ring_type ext_ring = exterior_ring(polygon);
append_point<ring_type, Point>::apply(
exterior_ring(polygon), point);
ext_ring, point);
}
else if (ring_index < int(num_interior_rings(polygon)))
{
interior_ring_range_type int_rings = interior_rings(polygon);
append_point<ring_type, Point>::apply(
range::at(interior_rings(polygon), ring_index), point);
range::at(int_rings, ring_index), point);
}
}
};
@@ -113,19 +117,23 @@ template <typename Polygon, typename Range>
struct range_to_polygon
{
typedef typename ring_type<Polygon>::type ring_type;
typedef typename ring_return_type<Polygon>::type exterior_ring_type;
typedef typename interior_return_type<Polygon>::type interior_ring_range_type;
static inline void apply(Polygon& polygon, Range const& range,
int ring_index, int = 0)
{
if (ring_index == -1)
{
exterior_ring_type ext_ring = exterior_ring(polygon);
append_range<ring_type, Range>::apply(
exterior_ring(polygon), range);
ext_ring, range);
}
else if (ring_index < int(num_interior_rings(polygon)))
{
interior_ring_range_type int_rings = interior_rings(polygon);
append_range<ring_type, Range>::apply(
range::at(interior_rings(polygon), ring_index), range);
range::at(int_rings, ring_index), range);
}
}
};

View File

@@ -3,9 +3,10 @@
// 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.
// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2017.
// Modifications copyright (c) 2017 Oracle and/or its affiliates.
// This file was modified by Oracle on 2017, 2018.
// Modifications copyright (c) 2017-2018 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
@@ -19,7 +20,7 @@
#define BOOST_GEOMETRY_ALGORITHMS_AREA_HPP
#include <boost/concept_check.hpp>
#include <boost/mpl/if.hpp>
#include <boost/core/ignore_unused.hpp>
#include <boost/range/functions.hpp>
#include <boost/range/metafunctions.hpp>
@@ -43,7 +44,9 @@
#include <boost/geometry/algorithms/detail/multi_sum.hpp>
#include <boost/geometry/strategies/area.hpp>
#include <boost/geometry/strategies/area_result.hpp>
#include <boost/geometry/strategies/default_area_result.hpp>
#include <boost/geometry/strategies/default_strategy.hpp>
#include <boost/geometry/strategies/concepts/area_concept.hpp>
@@ -56,6 +59,7 @@
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace area
{
@@ -83,14 +87,14 @@ template
struct ring_area
{
template <typename Ring, typename Strategy>
static inline typename Strategy::return_type
static inline typename area_result<Ring, Strategy>::type
apply(Ring const& ring, Strategy const& strategy)
{
BOOST_CONCEPT_ASSERT( (geometry::concepts::AreaStrategy<Strategy>) );
BOOST_CONCEPT_ASSERT( (geometry::concepts::AreaStrategy<Ring, Strategy>) );
assert_dimension<Ring, 2>();
// Ignore warning (because using static method sometimes) on strategy
boost::ignore_unused_variable_warning(strategy);
boost::ignore_unused(strategy);
// An open ring has at least three points,
// A closed ring has at least four points,
@@ -98,7 +102,7 @@ struct ring_area
if (boost::size(ring)
< core_detail::closure::minimum_ring_size<Closure>::value)
{
return typename Strategy::return_type();
return typename area_result<Ring, Strategy>::type();
}
typedef typename reversible_view<Ring const, Direction>::type rview_type;
@@ -110,7 +114,7 @@ struct ring_area
rview_type rview(ring);
view_type view(rview);
typename Strategy::state_type state;
typename Strategy::template state<Ring> state;
iterator_type it = boost::begin(view);
iterator_type end = boost::end(view);
@@ -144,9 +148,13 @@ template
struct area : detail::calculate_null
{
template <typename Strategy>
static inline typename Strategy::return_type apply(Geometry const& geometry, Strategy const& strategy)
static inline typename area_result<Geometry, Strategy>::type
apply(Geometry const& geometry, Strategy const& strategy)
{
return calculate_null::apply<typename Strategy::return_type>(geometry, strategy);
return calculate_null::apply
<
typename area_result<Geometry, Strategy>::type
>(geometry, strategy);
}
};
@@ -170,10 +178,11 @@ template <typename Polygon>
struct area<Polygon, polygon_tag> : detail::calculate_polygon_sum
{
template <typename Strategy>
static inline typename Strategy::return_type apply(Polygon const& polygon, Strategy const& strategy)
static inline typename area_result<Polygon, Strategy>::type
apply(Polygon const& polygon, Strategy const& strategy)
{
return calculate_polygon_sum::apply<
typename Strategy::return_type,
typename area_result<Polygon, Strategy>::type,
detail::area::ring_area
<
order_as_direction<geometry::point_order<Polygon>::value>::value,
@@ -188,12 +197,12 @@ template <typename MultiGeometry>
struct area<MultiGeometry, multi_polygon_tag> : detail::multi_sum
{
template <typename Strategy>
static inline typename Strategy::return_type
static inline typename area_result<MultiGeometry, Strategy>::type
apply(MultiGeometry const& multi, Strategy const& strategy)
{
return multi_sum::apply
<
typename Strategy::return_type,
typename area_result<MultiGeometry, Strategy>::type,
area<typename boost::range_value<MultiGeometry>::type>
>(multi, strategy);
}
@@ -204,39 +213,78 @@ struct area<MultiGeometry, multi_polygon_tag> : detail::multi_sum
#endif // DOXYGEN_NO_DISPATCH
namespace resolve_variant {
namespace resolve_strategy
{
template <typename Strategy>
struct area
{
template <typename Geometry>
static inline typename area_result<Geometry, Strategy>::type
apply(Geometry const& geometry, Strategy const& strategy)
{
return dispatch::area<Geometry>::apply(geometry, strategy);
}
};
template <>
struct area<default_strategy>
{
template <typename Geometry>
static inline typename area_result<Geometry>::type
apply(Geometry const& geometry, default_strategy)
{
typedef typename strategy::area::services::default_strategy
<
typename cs_tag<Geometry>::type
>::type strategy_type;
return dispatch::area<Geometry>::apply(geometry, strategy_type());
}
};
} // namespace resolve_strategy
namespace resolve_variant
{
template <typename Geometry>
struct area
{
template <typename Strategy>
static inline typename Strategy::return_type apply(Geometry const& geometry,
Strategy const& strategy)
static inline typename area_result<Geometry, Strategy>::type
apply(Geometry const& geometry, Strategy const& strategy)
{
return dispatch::area<Geometry>::apply(geometry, strategy);
return resolve_strategy::area<Strategy>::apply(geometry, strategy);
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct area<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
{
typedef boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> variant_type;
template <typename Strategy>
struct visitor: boost::static_visitor<typename Strategy::return_type>
struct visitor
: boost::static_visitor<typename area_result<variant_type, Strategy>::type>
{
Strategy const& m_strategy;
visitor(Strategy const& strategy): m_strategy(strategy) {}
template <typename Geometry>
typename Strategy::return_type operator()(Geometry const& geometry) const
typename area_result<variant_type, Strategy>::type
operator()(Geometry const& geometry) const
{
return area<Geometry>::apply(geometry, m_strategy);
}
};
template <typename Strategy>
static inline typename Strategy::return_type
apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
static inline typename area_result<variant_type, Strategy>::type
apply(variant_type const& geometry,
Strategy const& strategy)
{
return boost::apply_visitor(visitor<Strategy>(strategy), geometry);
@@ -268,22 +316,14 @@ and Geographic as well.
\qbk{[area] [area_output]}
*/
template <typename Geometry>
inline typename default_area_result<Geometry>::type area(Geometry const& geometry)
inline typename area_result<Geometry>::type
area(Geometry const& geometry)
{
concepts::check<Geometry const>();
// TODO put this into a resolve_strategy stage
// (and take the return type from resolve_variant)
typedef typename point_type<Geometry>::type point_type;
typedef typename strategy::area::services::default_strategy
<
typename cs_tag<point_type>::type,
point_type
>::type strategy_type;
// detail::throw_on_empty_input(geometry);
return resolve_variant::area<Geometry>::apply(geometry, strategy_type());
return resolve_variant::area<Geometry>::apply(geometry, default_strategy());
}
/*!
@@ -301,19 +341,19 @@ inline typename default_area_result<Geometry>::type area(Geometry const& geometr
\qbk{
[include reference/algorithms/area.qbk]
[heading Available Strategies]
\* [link geometry.reference.strategies.strategy_area_cartesian Cartesian]
\* [link geometry.reference.strategies.strategy_area_spherical Spherical]
\* [link geometry.reference.strategies.strategy_area_geographic Geographic]
[heading Example]
[area_with_strategy]
[area_with_strategy_output]
[heading Available Strategies]
\* [link geometry.reference.strategies.strategy_area_surveyor Surveyor (cartesian)]
\* [link geometry.reference.strategies.strategy_area_spherical Spherical]
[/link geometry.reference.strategies.strategy_area_geographic Geographic]
}
*/
template <typename Geometry, typename Strategy>
inline typename Strategy::return_type area(
Geometry const& geometry, Strategy const& strategy)
inline typename area_result<Geometry, Strategy>::type
area(Geometry const& geometry, Strategy const& strategy)
{
concepts::check<Geometry const>();

View File

@@ -37,52 +37,12 @@
#include <boost/geometry/geometries/box.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/algorithms/detail/buffer/buffer_box.hpp>
#include <boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace buffer
{
template <typename BoxIn, typename BoxOut, typename T, std::size_t C, std::size_t D, std::size_t N>
struct box_loop
{
typedef typename coordinate_type<BoxOut>::type coordinate_type;
static inline void apply(BoxIn const& box_in, T const& distance, BoxOut& box_out)
{
coordinate_type d = distance;
set<C, D>(box_out, get<C, D>(box_in) + d);
box_loop<BoxIn, BoxOut, T, C, D + 1, N>::apply(box_in, distance, box_out);
}
};
template <typename BoxIn, typename BoxOut, typename T, std::size_t C, std::size_t N>
struct box_loop<BoxIn, BoxOut, T, C, N, N>
{
static inline void apply(BoxIn const&, T const&, BoxOut&) {}
};
// Extends a box with the same amount in all directions
template<typename BoxIn, typename BoxOut, typename T>
inline void buffer_box(BoxIn const& box_in, T const& distance, BoxOut& box_out)
{
assert_dimension_equal<BoxIn, BoxOut>();
static const std::size_t N = dimension<BoxIn>::value;
box_loop<BoxIn, BoxOut, T, min_corner, 0, N>::apply(box_in, -distance, box_out);
box_loop<BoxIn, BoxOut, T, max_corner, 0, N>::apply(box_in, distance, box_out);
}
}} // namespace detail::buffer
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{

View File

@@ -5,6 +5,10 @@
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2017.
// Modifications copyright (c) 2017, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -29,10 +33,8 @@
#include <boost/geometry/arithmetic/arithmetic.hpp>
#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/algorithms/append.hpp>
#include <boost/geometry/algorithms/clear.hpp>
#include <boost/geometry/algorithms/for_each.hpp>
#include <boost/geometry/algorithms/detail/assign_values.hpp>
#include <boost/geometry/algorithms/detail/assign_box_corners.hpp>
#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp>
#include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
@@ -153,7 +155,23 @@ struct range_to_range
geometry::closure<Range1>::value
>::type view_type;
struct default_policy
{
template <typename Point1, typename Point2>
static inline void apply(Point1 const& point1, Point2 & point2)
{
geometry::detail::conversion::convert_point_to_point(point1, point2);
}
};
static inline void apply(Range1 const& source, Range2& destination)
{
apply(source, destination, default_policy());
}
template <typename ConvertPointPolicy>
static inline ConvertPointPolicy apply(Range1 const& source, Range2& destination,
ConvertPointPolicy convert_point)
{
geometry::clear(destination);
@@ -179,8 +197,12 @@ struct range_to_range
it != boost::end(view) && i < n;
++it, ++i)
{
geometry::append(destination, *it);
typename boost::range_value<Range2>::type point;
convert_point.apply(*it, point);
range::push_back(destination, point);
}
return convert_point;
}
};

View File

@@ -3,7 +3,11 @@
// 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.
// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
// Copyright (c) 2014-2017 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2017.
// Modifications copyright (c) 2017 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -28,6 +32,7 @@
#include <boost/variant/static_visitor.hpp>
#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/algorithms/correct_closure.hpp>
#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
#include <boost/geometry/core/closure.hpp>
@@ -41,7 +46,6 @@
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/algorithms/area.hpp>
#include <boost/geometry/algorithms/disjoint.hpp>
#include <boost/geometry/algorithms/detail/multi_modify.hpp>
#include <boost/geometry/util/order_as_direction.hpp>
@@ -61,7 +65,8 @@ namespace detail { namespace correct
template <typename Geometry>
struct correct_nop
{
static inline void apply(Geometry& )
template <typename Strategy>
static inline void apply(Geometry& , Strategy const& )
{}
};
@@ -104,8 +109,8 @@ struct correct_box_loop<Box, DimensionCount, DimensionCount>
template <typename Box>
struct correct_box
{
static inline void apply(Box& box)
template <typename Strategy>
static inline void apply(Box& box, Strategy const& )
{
// Currently only for Cartesian coordinates
// (or spherical without crossing dateline)
@@ -119,18 +124,12 @@ struct correct_box
// Close a ring, if not closed
template <typename Ring, typename Predicate>
template <typename Ring, template <typename> class Predicate>
struct correct_ring
{
typedef typename point_type<Ring>::type point_type;
typedef typename coordinate_type<Ring>::type coordinate_type;
typedef typename strategy::area::services::default_strategy
<
typename cs_tag<point_type>::type,
point_type
>::type strategy_type;
typedef detail::area::ring_area
<
order_as_direction<geometry::point_order<Ring>::value>::value,
@@ -138,30 +137,17 @@ struct correct_ring
> ring_area_type;
static inline void apply(Ring& r)
template <typename Strategy>
static inline void apply(Ring& r, Strategy const& strategy)
{
// Check close-ness
if (boost::size(r) > 2)
{
// check if closed, if not, close it
bool const disjoint = geometry::disjoint(*boost::begin(r), *(boost::end(r) - 1));
closure_selector const s = geometry::closure<Ring>::value;
// Correct closure if necessary
detail::correct_closure::close_or_open_ring<Ring>::apply(r);
if (disjoint && (s == closed))
{
geometry::append(r, *boost::begin(r));
}
if (! disjoint && s != closed)
{
// Open it by removing last point
geometry::traits::resize<Ring>::apply(r, boost::size(r) - 1);
}
}
// Check area
Predicate predicate;
typedef typename default_area_result<Ring>::type area_result_type;
area_result_type const zero = area_result_type();
if (predicate(ring_area_type::apply(r, strategy_type()), zero))
typedef typename area_result<Ring, Strategy>::type area_result_type;
Predicate<area_result_type> predicate;
area_result_type const zero = 0;
if (predicate(ring_area_type::apply(r, strategy), zero))
{
std::reverse(boost::begin(r), boost::end(r));
}
@@ -174,15 +160,15 @@ template <typename Polygon>
struct correct_polygon
{
typedef typename ring_type<Polygon>::type ring_type;
typedef typename default_area_result<Polygon>::type area_result_type;
static inline void apply(Polygon& poly)
template <typename Strategy>
static inline void apply(Polygon& poly, Strategy const& strategy)
{
correct_ring
<
ring_type,
std::less<area_result_type>
>::apply(exterior_ring(poly));
std::less
>::apply(exterior_ring(poly), strategy);
typename interior_return_type<Polygon>::type
rings = interior_rings(poly);
@@ -192,8 +178,8 @@ struct correct_polygon
correct_ring
<
ring_type,
std::greater<area_result_type>
>::apply(*it);
std::greater
>::apply(*it, strategy);
}
}
};
@@ -237,7 +223,7 @@ struct correct<Ring, ring_tag>
: detail::correct::correct_ring
<
Ring,
std::less<typename default_area_result<Ring>::type>
std::less
>
{};
@@ -281,29 +267,36 @@ namespace resolve_variant {
template <typename Geometry>
struct correct
{
static inline void apply(Geometry& geometry)
template <typename Strategy>
static inline void apply(Geometry& geometry, Strategy const& strategy)
{
concepts::check<Geometry const>();
dispatch::correct<Geometry>::apply(geometry);
dispatch::correct<Geometry>::apply(geometry, strategy);
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct correct<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
{
template <typename Strategy>
struct visitor: boost::static_visitor<void>
{
Strategy const& m_strategy;
visitor(Strategy const& strategy): m_strategy(strategy) {}
template <typename Geometry>
void operator()(Geometry& geometry) const
{
correct<Geometry>::apply(geometry);
correct<Geometry>::apply(geometry, m_strategy);
}
};
template <typename Strategy>
static inline void
apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry)
apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry, Strategy const& strategy)
{
boost::apply_visitor(visitor(), geometry);
boost::apply_visitor(visitor<Strategy>(strategy), geometry);
}
};
@@ -325,7 +318,36 @@ struct correct<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
template <typename Geometry>
inline void correct(Geometry& geometry)
{
resolve_variant::correct<Geometry>::apply(geometry);
typedef typename point_type<Geometry>::type point_type;
typedef typename strategy::area::services::default_strategy
<
typename cs_tag<point_type>::type
>::type strategy_type;
resolve_variant::correct<Geometry>::apply(geometry, strategy_type());
}
/*!
\brief Corrects a geometry
\details Corrects a geometry: all rings which are wrongly oriented with respect
to their expected orientation are reversed. To all rings which do not have a
closing point and are typed as they should have one, the first point is
appended. Also boxes can be corrected.
\ingroup correct
\tparam Geometry \tparam_geometry
\tparam Strategy \tparam_strategy{Area}
\param geometry \param_geometry which will be corrected if necessary
\param strategy \param_strategy{area}
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/correct.qbk]}
*/
template <typename Geometry, typename Strategy>
inline void correct(Geometry& geometry, Strategy const& strategy)
{
resolve_variant::correct<Geometry>::apply(geometry, strategy);
}
#if defined(_MSC_VER)

View File

@@ -0,0 +1,235 @@
// Boost.Geometry
// Copyright (c) 2017 Barend Gehrels, 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_CORRECT_CLOSURE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_CORRECT_CLOSURE_HPP
#include <cstddef>
#include <boost/range.hpp>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/ring_type.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/algorithms/disjoint.hpp>
#include <boost/geometry/algorithms/detail/multi_modify.hpp>
namespace boost { namespace geometry
{
// Silence warning C4127: conditional expression is constant
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable : 4127)
#endif
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace correct_closure
{
template <typename Geometry>
struct nop
{
static inline void apply(Geometry& )
{}
};
// Close a ring, if not closed, or open it
template <typename Ring>
struct close_or_open_ring
{
static inline void apply(Ring& r)
{
if (boost::size(r) <= 2)
{
return;
}
bool const disjoint = geometry::disjoint(*boost::begin(r),
*(boost::end(r) - 1));
closure_selector const s = geometry::closure<Ring>::value;
if (disjoint && s == closed)
{
// Close it by adding first point
geometry::append(r, *boost::begin(r));
}
else if (! disjoint && s != closed)
{
// Open it by removing last point
geometry::traits::resize<Ring>::apply(r, boost::size(r) - 1);
}
}
};
// Close/open exterior ring and all its interior rings
template <typename Polygon>
struct close_or_open_polygon
{
typedef typename ring_type<Polygon>::type ring_type;
static inline void apply(Polygon& poly)
{
close_or_open_ring<ring_type>::apply(exterior_ring(poly));
typename interior_return_type<Polygon>::type
rings = interior_rings(poly);
for (typename detail::interior_iterator<Polygon>::type
it = boost::begin(rings); it != boost::end(rings); ++it)
{
close_or_open_ring<ring_type>::apply(*it);
}
}
};
}} // namespace detail::correct_closure
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Geometry, typename Tag = typename tag<Geometry>::type>
struct correct_closure: not_implemented<Tag>
{};
template <typename Point>
struct correct_closure<Point, point_tag>
: detail::correct_closure::nop<Point>
{};
template <typename LineString>
struct correct_closure<LineString, linestring_tag>
: detail::correct_closure::nop<LineString>
{};
template <typename Segment>
struct correct_closure<Segment, segment_tag>
: detail::correct_closure::nop<Segment>
{};
template <typename Box>
struct correct_closure<Box, box_tag>
: detail::correct_closure::nop<Box>
{};
template <typename Ring>
struct correct_closure<Ring, ring_tag>
: detail::correct_closure::close_or_open_ring<Ring>
{};
template <typename Polygon>
struct correct_closure<Polygon, polygon_tag>
: detail::correct_closure::close_or_open_polygon<Polygon>
{};
template <typename MultiPoint>
struct correct_closure<MultiPoint, multi_point_tag>
: detail::correct_closure::nop<MultiPoint>
{};
template <typename MultiLineString>
struct correct_closure<MultiLineString, multi_linestring_tag>
: detail::correct_closure::nop<MultiLineString>
{};
template <typename Geometry>
struct correct_closure<Geometry, multi_polygon_tag>
: detail::multi_modify
<
Geometry,
detail::correct_closure::close_or_open_polygon
<
typename boost::range_value<Geometry>::type
>
>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
namespace resolve_variant
{
template <typename Geometry>
struct correct_closure
{
static inline void apply(Geometry& geometry)
{
concepts::check<Geometry const>();
dispatch::correct_closure<Geometry>::apply(geometry);
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct correct_closure<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
{
struct visitor: boost::static_visitor<void>
{
template <typename Geometry>
void operator()(Geometry& geometry) const
{
correct_closure<Geometry>::apply(geometry);
}
};
static inline void
apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry)
{
visitor vis;
boost::apply_visitor(vis, geometry);
}
};
} // namespace resolve_variant
/*!
\brief Closes or opens a geometry, according to its type
\details Corrects a geometry w.r.t. closure points to all rings which do not
have a closing point and are typed as they should have one, the first point
is appended.
\ingroup correct_closure
\tparam Geometry \tparam_geometry
\param geometry \param_geometry which will be corrected if necessary
*/
template <typename Geometry>
inline void correct_closure(Geometry& geometry)
{
resolve_variant::correct_closure<Geometry>::apply(geometry);
}
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_CORRECT_CLOSURE_HPP

View File

@@ -20,443 +20,8 @@
#define BOOST_GEOMETRY_ALGORITHMS_COVERED_BY_HPP
#include <cstddef>
#include <boost/geometry/algorithms/detail/covered_by/interface.hpp>
#include <boost/geometry/algorithms/detail/covered_by/implementation.hpp>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/algorithms/within.hpp>
#include <boost/geometry/strategies/cartesian/point_in_box.hpp>
#include <boost/geometry/strategies/cartesian/box_in_box.hpp>
#include <boost/geometry/strategies/default_strategy.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace covered_by {
struct use_point_in_geometry
{
template <typename Geometry1, typename Geometry2, typename Strategy>
static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
{
return detail::within::point_in_geometry(geometry1, geometry2, strategy) >= 0;
}
};
struct use_relate
{
template <typename Geometry1, typename Geometry2, typename Strategy>
static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
{
typedef typename detail::de9im::static_mask_covered_by_type
<
Geometry1, Geometry2
>::type covered_by_mask;
return geometry::relate(geometry1, geometry2, covered_by_mask(), strategy);
}
};
}} // namespace detail::covered_by
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template
<
typename Geometry1,
typename Geometry2,
typename Tag1 = typename tag<Geometry1>::type,
typename Tag2 = typename tag<Geometry2>::type
>
struct covered_by
: not_implemented<Tag1, Tag2>
{};
template <typename Point, typename Box>
struct covered_by<Point, Box, point_tag, box_tag>
{
template <typename Strategy>
static inline bool apply(Point const& point, Box const& box, Strategy const& strategy)
{
::boost::ignore_unused_variable_warning(strategy);
return strategy.apply(point, box);
}
};
template <typename Box1, typename Box2>
struct covered_by<Box1, Box2, box_tag, box_tag>
{
template <typename Strategy>
static inline bool apply(Box1 const& box1, Box2 const& box2, Strategy const& strategy)
{
assert_dimension_equal<Box1, Box2>();
::boost::ignore_unused_variable_warning(strategy);
return strategy.apply(box1, box2);
}
};
// P/P
template <typename Point1, typename Point2>
struct covered_by<Point1, Point2, point_tag, point_tag>
: public detail::covered_by::use_point_in_geometry
{};
template <typename Point, typename MultiPoint>
struct covered_by<Point, MultiPoint, point_tag, multi_point_tag>
: public detail::covered_by::use_point_in_geometry
{};
// P/L
template <typename Point, typename Segment>
struct covered_by<Point, Segment, point_tag, segment_tag>
: public detail::covered_by::use_point_in_geometry
{};
template <typename Point, typename Linestring>
struct covered_by<Point, Linestring, point_tag, linestring_tag>
: public detail::covered_by::use_point_in_geometry
{};
template <typename Point, typename MultiLinestring>
struct covered_by<Point, MultiLinestring, point_tag, multi_linestring_tag>
: public detail::covered_by::use_point_in_geometry
{};
// P/A
template <typename Point, typename Ring>
struct covered_by<Point, Ring, point_tag, ring_tag>
: public detail::covered_by::use_point_in_geometry
{};
template <typename Point, typename Polygon>
struct covered_by<Point, Polygon, point_tag, polygon_tag>
: public detail::covered_by::use_point_in_geometry
{};
template <typename Point, typename MultiPolygon>
struct covered_by<Point, MultiPolygon, point_tag, multi_polygon_tag>
: public detail::covered_by::use_point_in_geometry
{};
// L/L
template <typename Linestring1, typename Linestring2>
struct covered_by<Linestring1, Linestring2, linestring_tag, linestring_tag>
: public detail::covered_by::use_relate
{};
template <typename Linestring, typename MultiLinestring>
struct covered_by<Linestring, MultiLinestring, linestring_tag, multi_linestring_tag>
: public detail::covered_by::use_relate
{};
template <typename MultiLinestring, typename Linestring>
struct covered_by<MultiLinestring, Linestring, multi_linestring_tag, linestring_tag>
: public detail::covered_by::use_relate
{};
template <typename MultiLinestring1, typename MultiLinestring2>
struct covered_by<MultiLinestring1, MultiLinestring2, multi_linestring_tag, multi_linestring_tag>
: public detail::covered_by::use_relate
{};
// L/A
template <typename Linestring, typename Ring>
struct covered_by<Linestring, Ring, linestring_tag, ring_tag>
: public detail::covered_by::use_relate
{};
template <typename MultiLinestring, typename Ring>
struct covered_by<MultiLinestring, Ring, multi_linestring_tag, ring_tag>
: public detail::covered_by::use_relate
{};
template <typename Linestring, typename Polygon>
struct covered_by<Linestring, Polygon, linestring_tag, polygon_tag>
: public detail::covered_by::use_relate
{};
template <typename MultiLinestring, typename Polygon>
struct covered_by<MultiLinestring, Polygon, multi_linestring_tag, polygon_tag>
: public detail::covered_by::use_relate
{};
template <typename Linestring, typename MultiPolygon>
struct covered_by<Linestring, MultiPolygon, linestring_tag, multi_polygon_tag>
: public detail::covered_by::use_relate
{};
template <typename MultiLinestring, typename MultiPolygon>
struct covered_by<MultiLinestring, MultiPolygon, multi_linestring_tag, multi_polygon_tag>
: public detail::covered_by::use_relate
{};
// A/A
template <typename Ring1, typename Ring2>
struct covered_by<Ring1, Ring2, ring_tag, ring_tag>
: public detail::covered_by::use_relate
{};
template <typename Ring, typename Polygon>
struct covered_by<Ring, Polygon, ring_tag, polygon_tag>
: public detail::covered_by::use_relate
{};
template <typename Polygon, typename Ring>
struct covered_by<Polygon, Ring, polygon_tag, ring_tag>
: public detail::covered_by::use_relate
{};
template <typename Polygon1, typename Polygon2>
struct covered_by<Polygon1, Polygon2, polygon_tag, polygon_tag>
: public detail::covered_by::use_relate
{};
template <typename Ring, typename MultiPolygon>
struct covered_by<Ring, MultiPolygon, ring_tag, multi_polygon_tag>
: public detail::covered_by::use_relate
{};
template <typename MultiPolygon, typename Ring>
struct covered_by<MultiPolygon, Ring, multi_polygon_tag, ring_tag>
: public detail::covered_by::use_relate
{};
template <typename Polygon, typename MultiPolygon>
struct covered_by<Polygon, MultiPolygon, polygon_tag, multi_polygon_tag>
: public detail::covered_by::use_relate
{};
template <typename MultiPolygon, typename Polygon>
struct covered_by<MultiPolygon, Polygon, multi_polygon_tag, polygon_tag>
: public detail::covered_by::use_relate
{};
template <typename MultiPolygon1, typename MultiPolygon2>
struct covered_by<MultiPolygon1, MultiPolygon2, multi_polygon_tag, multi_polygon_tag>
: public detail::covered_by::use_relate
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
namespace resolve_strategy {
struct covered_by
{
template <typename Geometry1, typename Geometry2, typename Strategy>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
concepts::within::check
<
typename tag<Geometry1>::type,
typename tag<Geometry2>::type,
typename tag_cast<typename tag<Geometry2>::type, areal_tag>::type,
Strategy
>();
concepts::check<Geometry1 const>();
concepts::check<Geometry2 const>();
assert_dimension_equal<Geometry1, Geometry2>();
return dispatch::covered_by<Geometry1, Geometry2>::apply(geometry1,
geometry2,
strategy);
}
template <typename Geometry1, typename Geometry2>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
default_strategy)
{
typedef typename strategy::covered_by::services::default_strategy
<
Geometry1,
Geometry2
>::type strategy_type;
return covered_by::apply(geometry1, geometry2, strategy_type());
}
};
} // namespace resolve_strategy
namespace resolve_variant {
template <typename Geometry1, typename Geometry2>
struct covered_by
{
template <typename Strategy>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
return resolve_strategy::covered_by
::apply(geometry1, geometry2, strategy);
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
struct covered_by<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
{
template <typename Strategy>
struct visitor: boost::static_visitor<bool>
{
Geometry2 const& m_geometry2;
Strategy const& m_strategy;
visitor(Geometry2 const& geometry2, Strategy const& strategy)
: m_geometry2(geometry2), m_strategy(strategy) {}
template <typename Geometry1>
bool operator()(Geometry1 const& geometry1) const
{
return covered_by<Geometry1, Geometry2>
::apply(geometry1, m_geometry2, m_strategy);
}
};
template <typename Strategy>
static inline bool
apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
return boost::apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1);
}
};
template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct covered_by<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
{
template <typename Strategy>
struct visitor: boost::static_visitor<bool>
{
Geometry1 const& m_geometry1;
Strategy const& m_strategy;
visitor(Geometry1 const& geometry1, Strategy const& strategy)
: m_geometry1(geometry1), m_strategy(strategy) {}
template <typename Geometry2>
bool operator()(Geometry2 const& geometry2) const
{
return covered_by<Geometry1, Geometry2>
::apply(m_geometry1, geometry2, m_strategy);
}
};
template <typename Strategy>
static inline bool
apply(Geometry1 const& geometry1,
boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2,
Strategy const& strategy)
{
return boost::apply_visitor(visitor<Strategy>(geometry1, strategy), geometry2);
}
};
template <
BOOST_VARIANT_ENUM_PARAMS(typename T1),
BOOST_VARIANT_ENUM_PARAMS(typename T2)
>
struct covered_by<
boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>,
boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>
>
{
template <typename Strategy>
struct visitor: boost::static_visitor<bool>
{
Strategy const& m_strategy;
visitor(Strategy const& strategy): m_strategy(strategy) {}
template <typename Geometry1, typename Geometry2>
bool operator()(Geometry1 const& geometry1,
Geometry2 const& geometry2) const
{
return covered_by<Geometry1, Geometry2>
::apply(geometry1, geometry2, m_strategy);
}
};
template <typename Strategy>
static inline bool
apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1,
boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2,
Strategy const& strategy)
{
return boost::apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2);
}
};
} // namespace resolve_variant
/*!
\brief \brief_check12{is inside or on border}
\ingroup covered_by
\details \details_check12{covered_by, is inside or on border}.
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\param geometry1 \param_geometry which might be inside or on the border of the second geometry
\param geometry2 \param_geometry which might cover the first geometry
\return true if geometry1 is inside of or on the border of geometry2,
else false
\note The default strategy is used for covered_by detection
\qbk{[include reference/algorithms/covered_by.qbk]}
*/
template<typename Geometry1, typename Geometry2>
inline bool covered_by(Geometry1 const& geometry1, Geometry2 const& geometry2)
{
return resolve_variant::covered_by<Geometry1, Geometry2>
::apply(geometry1, geometry2, default_strategy());
}
/*!
\brief \brief_check12{is inside or on border} \brief_strategy
\ingroup covered_by
\details \details_check12{covered_by, is inside or on border}, \brief_strategy. \details_strategy_reasons
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\param geometry1 \param_geometry which might be inside or on the border of the second geometry
\param geometry2 \param_geometry which might cover the first geometry
\param strategy strategy to be used
\return true if geometry1 is inside of or on the border of geometry2,
else false
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/covered_by.qbk]}
*/
template<typename Geometry1, typename Geometry2, typename Strategy>
inline bool covered_by(Geometry1 const& geometry1, Geometry2 const& geometry2,
Strategy const& strategy)
{
return resolve_variant::covered_by<Geometry1, Geometry2>
::apply(geometry1, geometry2, strategy);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_COVERED_BY_HPP

View File

@@ -0,0 +1,432 @@
// Boost.Geometry
// Copyright (c) 2017-2018, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_ALGORITHMS_DENSIFY_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DENSIFY_HPP
#include <boost/geometry/algorithms/clear.hpp>
#include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/exception.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/strategies/default_strategy.hpp>
#include <boost/geometry/strategies/densify.hpp>
#include <boost/geometry/util/condition.hpp>
#include <boost/geometry/util/range.hpp>
#include <boost/range/size.hpp>
#include <boost/range/value_type.hpp>
#include <boost/throw_exception.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace densify
{
template <typename Range>
struct push_back_policy
{
typedef typename boost::range_value<Range>::type point_type;
inline explicit push_back_policy(Range & rng)
: m_rng(rng)
{}
inline void apply(point_type const& p)
{
range::push_back(m_rng, p);
}
private:
Range & m_rng;
};
template <typename Range, typename Point>
inline void convert_and_push_back(Range & range, Point const& p)
{
typename boost::range_value<Range>::type p2;
geometry::detail::conversion::convert_point_to_point(p, p2);
range::push_back(range, p2);
}
template <bool AppendLastPoint = true>
struct densify_range
{
template <typename FwdRng, typename MutRng, typename T, typename Strategy>
static inline void apply(FwdRng const& rng, MutRng & rng_out,
T const& len, Strategy const& strategy)
{
typedef typename boost::range_iterator<FwdRng const>::type iterator_t;
typedef typename boost::range_value<FwdRng>::type point_t;
iterator_t it = boost::begin(rng);
iterator_t end = boost::end(rng);
if (it == end) // empty(rng)
{
return;
}
push_back_policy<MutRng> policy(rng_out);
iterator_t prev = it;
for ( ++it ; it != end ; prev = it++)
{
point_t const& p0 = *prev;
point_t const& p1 = *it;
convert_and_push_back(rng_out, p0);
strategy.apply(p0, p1, policy, len);
}
if (BOOST_GEOMETRY_CONDITION(AppendLastPoint))
{
convert_and_push_back(rng_out, *prev); // back(rng)
}
}
};
template <bool IsClosed1, bool IsClosed2> // false, X
struct densify_ring
{
template <typename Geometry, typename GeometryOut, typename T, typename Strategy>
static inline void apply(Geometry const& ring, GeometryOut & ring_out,
T const& len, Strategy const& strategy)
{
geometry::detail::densify::densify_range<true>
::apply(ring, ring_out, len, strategy);
if (boost::size(ring) <= 1)
return;
typedef typename point_type<Geometry>::type point_t;
point_t const& p0 = range::back(ring);
point_t const& p1 = range::front(ring);
push_back_policy<GeometryOut> policy(ring_out);
strategy.apply(p0, p1, policy, len);
if (BOOST_GEOMETRY_CONDITION(IsClosed2))
{
convert_and_push_back(ring_out, p1);
}
}
};
template <>
struct densify_ring<true, true>
: densify_range<true>
{};
template <>
struct densify_ring<true, false>
: densify_range<false>
{};
}} // namespace detail::densify
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template
<
typename Geometry,
typename GeometryOut,
typename Tag1 = typename tag<Geometry>::type,
typename Tag2 = typename tag<GeometryOut>::type
>
struct densify
: not_implemented<Tag1, Tag2>
{};
template <typename Geometry, typename GeometryOut>
struct densify<Geometry, GeometryOut, linestring_tag, linestring_tag>
: geometry::detail::densify::densify_range<>
{};
template <typename Geometry, typename GeometryOut>
struct densify<Geometry, GeometryOut, multi_linestring_tag, multi_linestring_tag>
{
template <typename T, typename Strategy>
static void apply(Geometry const& mls, GeometryOut & mls_out,
T const& len, Strategy const& strategy)
{
std::size_t count = boost::size(mls);
range::resize(mls_out, count);
for (std::size_t i = 0 ; i < count ; ++i)
{
geometry::detail::densify::densify_range<>
::apply(range::at(mls, i), range::at(mls_out, i),
len, strategy);
}
}
};
template <typename Geometry, typename GeometryOut>
struct densify<Geometry, GeometryOut, ring_tag, ring_tag>
: geometry::detail::densify::densify_ring
<
geometry::closure<Geometry>::value != geometry::open,
geometry::closure<GeometryOut>::value != geometry::open
>
{};
template <typename Geometry, typename GeometryOut>
struct densify<Geometry, GeometryOut, polygon_tag, polygon_tag>
{
template <typename T, typename Strategy>
static void apply(Geometry const& poly, GeometryOut & poly_out,
T const& len, Strategy const& strategy)
{
apply_ring(exterior_ring(poly), exterior_ring(poly_out),
len, strategy);
std::size_t count = boost::size(interior_rings(poly));
range::resize(interior_rings(poly_out), count);
for (std::size_t i = 0 ; i < count ; ++i)
{
apply_ring(range::at(interior_rings(poly), i),
range::at(interior_rings(poly_out), i),
len, strategy);
}
}
template <typename Ring, typename RingOut, typename T, typename Strategy>
static void apply_ring(Ring const& ring, RingOut & ring_out,
T const& len, Strategy const& strategy)
{
densify<Ring, RingOut, ring_tag, ring_tag>
::apply(ring, ring_out, len, strategy);
}
};
template <typename Geometry, typename GeometryOut>
struct densify<Geometry, GeometryOut, multi_polygon_tag, multi_polygon_tag>
{
template <typename T, typename Strategy>
static void apply(Geometry const& mpoly, GeometryOut & mpoly_out,
T const& len, Strategy const& strategy)
{
std::size_t count = boost::size(mpoly);
range::resize(mpoly_out, count);
for (std::size_t i = 0 ; i < count ; ++i)
{
apply_poly(range::at(mpoly, i),
range::at(mpoly_out, i),
len, strategy);
}
}
template <typename Poly, typename PolyOut, typename T, typename Strategy>
static void apply_poly(Poly const& poly, PolyOut & poly_out,
T const& len, Strategy const& strategy)
{
densify<Poly, PolyOut, polygon_tag, polygon_tag>::
apply(poly, poly_out, len, strategy);
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
namespace resolve_strategy
{
struct densify
{
template <typename Geometry, typename Distance, typename Strategy>
static inline void apply(Geometry const& geometry,
Geometry& out,
Distance const& max_distance,
Strategy const& strategy)
{
dispatch::densify<Geometry, Geometry>
::apply(geometry, out, max_distance, strategy);
}
template <typename Geometry, typename Distance>
static inline void apply(Geometry const& geometry,
Geometry& out,
Distance const& max_distance,
default_strategy)
{
typedef typename strategy::densify::services::default_strategy
<
typename cs_tag<Geometry>::type
>::type strategy_type;
/*BOOST_CONCEPT_ASSERT(
(concepts::DensifyStrategy<strategy_type>)
);*/
apply(geometry, out, max_distance, strategy_type());
}
};
} // namespace resolve_strategy
namespace resolve_variant {
template <typename Geometry>
struct densify
{
template <typename Distance, typename Strategy>
static inline void apply(Geometry const& geometry,
Geometry& out,
Distance const& max_distance,
Strategy const& strategy)
{
resolve_strategy::densify::apply(geometry, out, max_distance, strategy);
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct densify<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
{
template <typename Distance, typename Strategy>
struct visitor: boost::static_visitor<void>
{
Distance const& m_max_distance;
Strategy const& m_strategy;
visitor(Distance const& max_distance, Strategy const& strategy)
: m_max_distance(max_distance)
, m_strategy(strategy)
{}
template <typename Geometry>
void operator()(Geometry const& geometry, Geometry& out) const
{
densify<Geometry>::apply(geometry, out, m_max_distance, m_strategy);
}
};
template <typename Distance, typename Strategy>
static inline void
apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& out,
Distance const& max_distance,
Strategy const& strategy)
{
boost::apply_visitor(
visitor<Distance, Strategy>(max_distance, strategy),
geometry,
out
);
}
};
} // namespace resolve_variant
/*!
\brief Densify a geometry using a specified strategy
\ingroup densify
\tparam Geometry \tparam_geometry
\tparam Distance A numerical distance measure
\tparam Strategy A type fulfilling a DensifyStrategy concept
\param geometry Input geometry, to be densified
\param out Output geometry, densified version of the input geometry
\param max_distance Distance threshold (in units depending on strategy)
\param strategy Densify strategy to be used for densification
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/densify.qbk]}
\qbk{
[heading Available Strategies]
\* [link geometry.reference.strategies.strategy_densify_cartesian Cartesian]
\* [link geometry.reference.strategies.strategy_densify_spherical Spherical]
\* [link geometry.reference.strategies.strategy_densify_geographic Geographic]
[heading Example]
[densify_strategy]
[densify_strategy_output]
[heading See also]
\* [link geometry.reference.algorithms.line_interpolate line_interpolate]
}
*/
template <typename Geometry, typename Distance, typename Strategy>
inline void densify(Geometry const& geometry,
Geometry& out,
Distance const& max_distance,
Strategy const& strategy)
{
concepts::check<Geometry>();
if (max_distance <= Distance(0))
{
BOOST_THROW_EXCEPTION(geometry::invalid_input_exception());
}
geometry::clear(out);
resolve_variant::densify
<
Geometry
>::apply(geometry, out, max_distance, strategy);
}
/*!
\brief Densify a geometry
\ingroup densify
\tparam Geometry \tparam_geometry
\tparam Distance A numerical distance measure
\param geometry Input geometry, to be densified
\param out Output geometry, densified version of the input geometry
\param max_distance Distance threshold (in units depending on coordinate system)
\qbk{[include reference/algorithms/densify.qbk]}
\qbk{
[heading Example]
[densify]
[densify_output]
[heading See also]
\* [link geometry.reference.algorithms.line_interpolate line_interpolate]
}
*/
template <typename Geometry, typename Distance>
inline void densify(Geometry const& geometry,
Geometry& out,
Distance const& max_distance)
{
densify(geometry, out, max_distance, default_strategy());
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DENSIFY_HPP

View File

@@ -7,6 +7,11 @@
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2018.
// Modifications copyright (c) 2018, Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, 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)
@@ -34,6 +39,7 @@
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/util/is_inverse_spheroidal_coordinates.hpp>
#include <boost/geometry/util/for_each_coordinate.hpp>
@@ -86,12 +92,13 @@ struct assign_inverse_box_or_segment
typedef typename coordinate_type<point_type>::type bound_type;
initialize<0, 0, dimension<BoxOrSegment>::type::value>::apply(
geometry, boost::numeric::bounds<bound_type>::highest()
geometry, geometry::bounds<bound_type>::highest()
);
initialize<1, 0, dimension<BoxOrSegment>::type::value>::apply(
geometry, boost::numeric::bounds<bound_type>::lowest()
geometry, geometry::bounds<bound_type>::lowest()
);
}
};

View File

@@ -15,18 +15,22 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_AZIMUTH_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_AZIMUTH_HPP
#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/radian_access.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/formulas/spherical.hpp>
#include <boost/geometry/formulas/vincenty_inverse.hpp>
#include <boost/geometry/srs/spheroid.hpp>
#include <boost/geometry/util/math.hpp>
namespace boost { namespace geometry
{

View File

@@ -0,0 +1,62 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2018-2019 Barend Gehrels, 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_BUFFER_BUFFER_BOX_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_BOX_HPP
#include <cstddef>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/access.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace buffer
{
template <typename BoxIn, typename BoxOut, typename T, std::size_t C, std::size_t D, std::size_t N>
struct box_loop
{
typedef typename coordinate_type<BoxOut>::type coordinate_type;
static inline void apply(BoxIn const& box_in, T const& distance, BoxOut& box_out)
{
coordinate_type d = distance;
set<C, D>(box_out, get<C, D>(box_in) + d);
box_loop<BoxIn, BoxOut, T, C, D + 1, N>::apply(box_in, distance, box_out);
}
};
template <typename BoxIn, typename BoxOut, typename T, std::size_t C, std::size_t N>
struct box_loop<BoxIn, BoxOut, T, C, N, N>
{
static inline void apply(BoxIn const&, T const&, BoxOut&) {}
};
// Extends a box with the same amount in all directions
template<typename BoxIn, typename BoxOut, typename T>
inline void buffer_box(BoxIn const& box_in, T const& distance, BoxOut& box_out)
{
assert_dimension_equal<BoxIn, BoxOut>();
static const std::size_t N = dimension<BoxIn>::value;
box_loop<BoxIn, BoxOut, T, min_corner, 0, N>::apply(box_in, -distance, box_out);
box_loop<BoxIn, BoxOut, T, max_corner, 0, N>::apply(box_in, distance, box_out);
}
}} // namespace detail::buffer
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_BOX_HPP

View File

@@ -41,10 +41,6 @@
#include <boost/geometry/views/detail/normalized_view.hpp>
#if defined(BOOST_GEOMETRY_BUFFER_SIMPLIFY_WITH_AX)
#include <boost/geometry/strategies/cartesian/distance_projected_point_ax.hpp>
#endif
namespace boost { namespace geometry
{
@@ -67,45 +63,21 @@ inline void simplify_input(Range const& range,
// sensitive to small scale input features, however the result will
// look better.
// It also gets rid of duplicate points
#if ! defined(BOOST_GEOMETRY_BUFFER_SIMPLIFY_WITH_AX)
geometry::simplify(range, simplified, distance.simplify_distance());
#else
typedef typename boost::range_value<Range>::type point_type;
typedef strategy::distance::detail::projected_point_ax<> ax_type;
typedef typename strategy::distance::services::return_type
typedef typename geometry::point_type<Range>::type point_type;
typedef typename strategy::distance::services::default_strategy
<
strategy::distance::detail::projected_point_ax<>,
point_type,
point_type
>::type return_type;
typedef strategy::distance::detail::projected_point_ax_less
point_tag, segment_tag, point_type
>::type ds_strategy_type;
typedef strategy::simplify::douglas_peucker
<
return_type
> comparator_type;
point_type, ds_strategy_type
> strategy_type;
typedef strategy::simplify::detail::douglas_peucker
<
point_type,
strategy::distance::detail::projected_point_ax<>,
comparator_type
> dp_ax;
geometry::detail::simplify::simplify_range<2>::apply(range,
simplified, distance.simplify_distance(),
strategy_type());
return_type max_distance(distance.simplify_distance() * 2.0,
distance.simplify_distance());
comparator_type comparator(max_distance);
dp_ax strategy(comparator);
geometry::simplify(range, simplified, max_distance, strategy);
#endif
if (boost::size(simplified) == 2
&& geometry::equals(geometry::range::front(simplified),
geometry::range::back(simplified)))
{
traits::resize<Range>::apply(simplified, 1);
}
}
@@ -122,7 +94,8 @@ struct buffer_range
typename DistanceStrategy,
typename JoinStrategy,
typename EndStrategy,
typename RobustPolicy
typename RobustPolicy,
typename Strategy
>
static inline
void add_join(Collection& collection,
@@ -133,18 +106,19 @@ struct buffer_range
Point const& input,
output_point_type const& perp1,
output_point_type const& perp2,
strategy::buffer::buffer_side_selector side,
geometry::strategy::buffer::buffer_side_selector side,
DistanceStrategy const& distance,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
RobustPolicy const& )
RobustPolicy const& ,
Strategy const& strategy) // side strategy
{
output_point_type intersection_point;
geometry::assign_zero(intersection_point);
strategy::buffer::join_selector join
= get_join_type(penultimate_input, previous_input, input);
if (join == strategy::buffer::join_convex)
geometry::strategy::buffer::join_selector join
= get_join_type(penultimate_input, previous_input, input, strategy);
if (join == geometry::strategy::buffer::join_convex)
{
// Calculate the intersection-point formed by the two sides.
// It might be that the two sides are not convex, but continue
@@ -157,23 +131,23 @@ struct buffer_range
switch(join)
{
case strategy::buffer::join_continue :
case geometry::strategy::buffer::join_continue :
// No join, we get two consecutive sides
break;
case strategy::buffer::join_concave :
case geometry::strategy::buffer::join_concave :
{
std::vector<output_point_type> range_out;
range_out.push_back(prev_perp2);
range_out.push_back(previous_input);
collection.add_piece(strategy::buffer::buffered_concave, previous_input, range_out);
collection.add_piece(geometry::strategy::buffer::buffered_concave, previous_input, range_out);
range_out.clear();
range_out.push_back(previous_input);
range_out.push_back(perp1);
collection.add_piece(strategy::buffer::buffered_concave, previous_input, range_out);
collection.add_piece(geometry::strategy::buffer::buffered_concave, previous_input, range_out);
}
break;
case strategy::buffer::join_spike :
case geometry::strategy::buffer::join_spike :
{
// For linestrings, only add spike at one side to avoid
// duplicates
@@ -183,7 +157,7 @@ struct buffer_range
collection.set_current_ring_concave();
}
break;
case strategy::buffer::join_convex :
case geometry::strategy::buffer::join_convex :
{
// The corner is convex, we create a join
// TODO (future) - avoid a separate vector, add the piece directly
@@ -193,7 +167,7 @@ struct buffer_range
distance.apply(previous_input, input, side),
range_out))
{
collection.add_piece(strategy::buffer::buffered_join,
collection.add_piece(geometry::strategy::buffer::buffered_join,
previous_input, range_out);
}
}
@@ -201,27 +175,24 @@ struct buffer_range
}
}
static inline strategy::buffer::join_selector get_join_type(
template <typename Strategy>
static inline geometry::strategy::buffer::join_selector get_join_type(
output_point_type const& p0,
output_point_type const& p1,
output_point_type const& p2)
output_point_type const& p2,
Strategy const& strategy) // side strategy
{
typedef typename strategy::side::services::default_strategy
<
typename cs_tag<output_point_type>::type
>::type side_strategy;
int const side = side_strategy::apply(p0, p1, p2);
return side == -1 ? strategy::buffer::join_convex
: side == 1 ? strategy::buffer::join_concave
int const side = strategy.apply(p0, p1, p2);
return side == -1 ? geometry::strategy::buffer::join_convex
: side == 1 ? geometry::strategy::buffer::join_concave
: parallel_continue
(
get<0>(p2) - get<0>(p1),
get<1>(p2) - get<1>(p1),
get<0>(p1) - get<0>(p0),
get<1>(p1) - get<1>(p0)
) ? strategy::buffer::join_continue
: strategy::buffer::join_spike;
) ? geometry::strategy::buffer::join_continue
: geometry::strategy::buffer::join_spike;
}
template
@@ -232,16 +203,19 @@ struct buffer_range
typename SideStrategy,
typename JoinStrategy,
typename EndStrategy,
typename RobustPolicy
typename RobustPolicy,
typename Strategy
>
static inline strategy::buffer::result_code iterate(Collection& collection,
static inline geometry::strategy::buffer::result_code iterate(Collection& collection,
Iterator begin, Iterator end,
strategy::buffer::buffer_side_selector side,
geometry::strategy::buffer::buffer_side_selector side,
DistanceStrategy const& distance_strategy,
SideStrategy const& side_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
RobustPolicy const& robust_policy,
Strategy const& strategy, // side strategy
bool linear,
output_point_type& first_p1,
output_point_type& first_p2,
output_point_type& last_p1,
@@ -273,7 +247,11 @@ struct buffer_range
* pup: penultimate_point
*/
strategy::buffer::result_code result = strategy::buffer::result_no_output;
bool const mark_flat
= linear
&& end_strategy.get_piece_type() == geometry::strategy::buffer::buffered_flat_end;
geometry::strategy::buffer::result_code result = geometry::strategy::buffer::result_no_output;
bool first = true;
Iterator it = begin;
@@ -284,25 +262,25 @@ struct buffer_range
for (Iterator prev = it++; it != end; ++it)
{
generated_side.clear();
strategy::buffer::result_code error_code
geometry::strategy::buffer::result_code error_code
= side_strategy.apply(*prev, *it, side,
distance_strategy, generated_side);
if (error_code == strategy::buffer::result_no_output)
if (error_code == geometry::strategy::buffer::result_no_output)
{
// Because input is simplified, this is improbable,
// but it can happen for degenerate geometries
// Further handling of this side is skipped
continue;
}
else if (error_code == strategy::buffer::result_error_numerical)
else if (error_code == geometry::strategy::buffer::result_error_numerical)
{
return error_code;
}
BOOST_GEOMETRY_ASSERT(! generated_side.empty());
result = strategy::buffer::result_normal;
result = geometry::strategy::buffer::result_normal;
if (! first)
{
@@ -312,11 +290,16 @@ struct buffer_range
*it, generated_side.front(), generated_side.back(),
side,
distance_strategy, join_strategy, end_strategy,
robust_policy);
robust_policy, strategy);
}
collection.add_side_piece(*prev, *it, generated_side, first);
if (first && mark_flat)
{
collection.mark_flat_start();
}
penultimate_point = *prev;
ultimate_point = *it;
last_p1 = generated_side.front();
@@ -330,6 +313,12 @@ struct buffer_range
first_p2 = generated_side.back();
}
}
if (mark_flat)
{
collection.mark_flat_end();
}
return result;
}
};
@@ -350,7 +339,8 @@ struct buffer_multi
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
typename RobustPolicy
typename RobustPolicy,
typename Strategy
>
static inline void apply(Multi const& multi,
Collection& collection,
@@ -359,7 +349,8 @@ struct buffer_multi
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
PointStrategy const& point_strategy,
RobustPolicy const& robust_policy)
RobustPolicy const& robust_policy,
Strategy const& strategy) // side strategy
{
for (typename boost::range_iterator<Multi const>::type
it = boost::begin(multi);
@@ -369,7 +360,7 @@ struct buffer_multi
Policy::apply(*it, collection,
distance_strategy, side_strategy,
join_strategy, end_strategy, point_strategy,
robust_policy);
robust_policy, strategy);
}
}
};
@@ -393,12 +384,12 @@ inline void buffer_point(Point const& point, Collection& collection,
DistanceStrategy const& distance_strategy,
PointStrategy const& point_strategy)
{
collection.start_new_ring();
collection.start_new_ring(false);
std::vector<OutputPointType> range_out;
point_strategy.apply(point, distance_strategy, range_out);
collection.add_piece(strategy::buffer::buffered_point, range_out, false);
collection.add_piece(geometry::strategy::buffer::buffered_point, range_out, false);
collection.set_piece_center(point);
collection.finish_ring(strategy::buffer::result_normal);
collection.finish_ring(geometry::strategy::buffer::result_normal);
}
@@ -436,7 +427,8 @@ struct buffer_inserter<point_tag, Point, RingOutput>
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
typename RobustPolicy
typename RobustPolicy,
typename Strategy
>
static inline void apply(Point const& point, Collection& collection,
DistanceStrategy const& distance_strategy,
@@ -444,7 +436,8 @@ struct buffer_inserter<point_tag, Point, RingOutput>
JoinStrategy const& ,
EndStrategy const& ,
PointStrategy const& point_strategy,
RobustPolicy const& )
RobustPolicy const& ,
Strategy const& ) // side strategy
{
detail::buffer::buffer_point
<
@@ -472,29 +465,32 @@ struct buffer_inserter_ring
typename SideStrategy,
typename JoinStrategy,
typename EndStrategy,
typename RobustPolicy
typename RobustPolicy,
typename Strategy
>
static inline strategy::buffer::result_code iterate(Collection& collection,
static inline geometry::strategy::buffer::result_code iterate(Collection& collection,
Iterator begin, Iterator end,
strategy::buffer::buffer_side_selector side,
geometry::strategy::buffer::buffer_side_selector side,
DistanceStrategy const& distance_strategy,
SideStrategy const& side_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
RobustPolicy const& robust_policy)
RobustPolicy const& robust_policy,
Strategy const& strategy) // side strategy
{
output_point_type first_p1, first_p2, last_p1, last_p2;
typedef detail::buffer::buffer_range<RingOutput> buffer_range;
strategy::buffer::result_code result
geometry::strategy::buffer::result_code result
= buffer_range::iterate(collection, begin, end,
side,
distance_strategy, side_strategy, join_strategy, end_strategy, robust_policy,
first_p1, first_p2, last_p1, last_p2);
distance_strategy, side_strategy, join_strategy, end_strategy,
robust_policy, strategy,
false, first_p1, first_p2, last_p1, last_p2);
// Generate closing join
if (result == strategy::buffer::result_normal)
if (result == geometry::strategy::buffer::result_normal)
{
buffer_range::add_join(collection,
*(end - 2),
@@ -502,7 +498,7 @@ struct buffer_inserter_ring
*(begin + 1), first_p1, first_p2,
side,
distance_strategy, join_strategy, end_strategy,
robust_policy);
robust_policy, strategy);
}
// Buffer is closed automatically by last closing corner
@@ -517,21 +513,23 @@ struct buffer_inserter_ring
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
typename RobustPolicy
typename RobustPolicy,
typename Strategy
>
static inline strategy::buffer::result_code apply(RingInput const& ring,
static inline geometry::strategy::buffer::result_code apply(RingInput const& ring,
Collection& collection,
DistanceStrategy const& distance,
SideStrategy const& side_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
PointStrategy const& point_strategy,
RobustPolicy const& robust_policy)
RobustPolicy const& robust_policy,
Strategy const& strategy) // side strategy
{
RingInput simplified;
detail::buffer::simplify_input(ring, distance, simplified);
strategy::buffer::result_code code = strategy::buffer::result_no_output;
geometry::strategy::buffer::result_code code = geometry::strategy::buffer::result_no_output;
std::size_t n = boost::size(simplified);
std::size_t const min_points = core_detail::closure::minimum_ring_size
@@ -546,18 +544,20 @@ struct buffer_inserter_ring
{
// Walk backwards (rings will be reversed afterwards)
code = iterate(collection, boost::rbegin(view), boost::rend(view),
strategy::buffer::buffer_side_right,
distance, side_strategy, join_strategy, end_strategy, robust_policy);
geometry::strategy::buffer::buffer_side_right,
distance, side_strategy, join_strategy, end_strategy,
robust_policy, strategy);
}
else
{
code = iterate(collection, boost::begin(view), boost::end(view),
strategy::buffer::buffer_side_left,
distance, side_strategy, join_strategy, end_strategy, robust_policy);
geometry::strategy::buffer::buffer_side_left,
distance, side_strategy, join_strategy, end_strategy,
robust_policy, strategy);
}
}
if (code == strategy::buffer::result_no_output && n >= 1)
if (code == geometry::strategy::buffer::result_no_output && n >= 1)
{
// Use point_strategy to buffer degenerated ring
detail::buffer::buffer_point<output_point_type>
@@ -586,23 +586,25 @@ struct buffer_inserter<ring_tag, RingInput, RingOutput>
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
typename RobustPolicy
typename RobustPolicy,
typename Strategy
>
static inline strategy::buffer::result_code apply(RingInput const& ring,
static inline geometry::strategy::buffer::result_code apply(RingInput const& ring,
Collection& collection,
DistanceStrategy const& distance,
SideStrategy const& side_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
PointStrategy const& point_strategy,
RobustPolicy const& robust_policy)
RobustPolicy const& robust_policy,
Strategy const& strategy) // side strategy
{
collection.start_new_ring();
strategy::buffer::result_code const code
collection.start_new_ring(distance.negative());
geometry::strategy::buffer::result_code const code
= buffer_inserter_ring<RingInput, RingOutput>::apply(ring,
collection, distance,
side_strategy, join_strategy, end_strategy, point_strategy,
robust_policy);
robust_policy, strategy);
collection.finish_ring(code);
return code;
}
@@ -627,16 +629,18 @@ struct buffer_inserter<linestring_tag, Linestring, Polygon>
typename SideStrategy,
typename JoinStrategy,
typename EndStrategy,
typename RobustPolicy
typename RobustPolicy,
typename Strategy
>
static inline strategy::buffer::result_code iterate(Collection& collection,
static inline geometry::strategy::buffer::result_code iterate(Collection& collection,
Iterator begin, Iterator end,
strategy::buffer::buffer_side_selector side,
geometry::strategy::buffer::buffer_side_selector side,
DistanceStrategy const& distance_strategy,
SideStrategy const& side_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
RobustPolicy const& robust_policy,
Strategy const& strategy, // side strategy
output_point_type& first_p1)
{
input_point_type const& ultimate_point = *(end - 1);
@@ -647,18 +651,18 @@ struct buffer_inserter<linestring_tag, Linestring, Polygon>
// we have it already from the first phase (left).
// But for the first pass, we have to generate it
output_point_type reverse_p1;
if (side == strategy::buffer::buffer_side_right)
if (side == geometry::strategy::buffer::buffer_side_right)
{
reverse_p1 = first_p1;
}
else
{
std::vector<output_point_type> generated_side;
strategy::buffer::result_code code
geometry::strategy::buffer::result_code code
= side_strategy.apply(ultimate_point, penultimate_point,
strategy::buffer::buffer_side_right,
geometry::strategy::buffer::buffer_side_right,
distance_strategy, generated_side);
if (code != strategy::buffer::result_normal)
if (code != geometry::strategy::buffer::result_normal)
{
// No output or numerical error
return code;
@@ -668,16 +672,18 @@ struct buffer_inserter<linestring_tag, Linestring, Polygon>
output_point_type first_p2, last_p1, last_p2;
strategy::buffer::result_code result
geometry::strategy::buffer::result_code result
= detail::buffer::buffer_range<output_ring_type>::iterate(collection,
begin, end, side,
distance_strategy, side_strategy, join_strategy, end_strategy, robust_policy,
first_p1, first_p2, last_p1, last_p2);
distance_strategy, side_strategy, join_strategy, end_strategy,
robust_policy, strategy,
true, first_p1, first_p2, last_p1, last_p2);
if (result == strategy::buffer::result_normal)
if (result == geometry::strategy::buffer::result_normal)
{
std::vector<output_point_type> range_out;
end_strategy.apply(penultimate_point, last_p2, ultimate_point, reverse_p1, side, distance_strategy, range_out);
end_strategy.apply(penultimate_point, last_p2, ultimate_point, reverse_p1,
side, distance_strategy, range_out);
collection.add_endcap(end_strategy, range_out, ultimate_point);
}
return result;
@@ -691,42 +697,47 @@ struct buffer_inserter<linestring_tag, Linestring, Polygon>
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
typename RobustPolicy
typename RobustPolicy,
typename Strategy
>
static inline strategy::buffer::result_code apply(Linestring const& linestring, Collection& collection,
static inline geometry::strategy::buffer::result_code apply(Linestring const& linestring,
Collection& collection,
DistanceStrategy const& distance,
SideStrategy const& side_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
PointStrategy const& point_strategy,
RobustPolicy const& robust_policy)
RobustPolicy const& robust_policy,
Strategy const& strategy) // side strategy
{
Linestring simplified;
detail::buffer::simplify_input(linestring, distance, simplified);
strategy::buffer::result_code code = strategy::buffer::result_no_output;
geometry::strategy::buffer::result_code code = geometry::strategy::buffer::result_no_output;
std::size_t n = boost::size(simplified);
if (n > 1)
{
collection.start_new_ring();
collection.start_new_ring(false);
output_point_type first_p1;
code = iterate(collection,
boost::begin(simplified), boost::end(simplified),
strategy::buffer::buffer_side_left,
distance, side_strategy, join_strategy, end_strategy, robust_policy,
geometry::strategy::buffer::buffer_side_left,
distance, side_strategy, join_strategy, end_strategy,
robust_policy, strategy,
first_p1);
if (code == strategy::buffer::result_normal)
if (code == geometry::strategy::buffer::result_normal)
{
code = iterate(collection,
boost::rbegin(simplified), boost::rend(simplified),
strategy::buffer::buffer_side_right,
distance, side_strategy, join_strategy, end_strategy, robust_policy,
geometry::strategy::buffer::buffer_side_right,
distance, side_strategy, join_strategy, end_strategy,
robust_policy, strategy,
first_p1);
}
collection.finish_ring(code);
}
if (code == strategy::buffer::result_no_output && n >= 1)
if (code == geometry::strategy::buffer::result_no_output && n >= 1)
{
// Use point_strategy to buffer degenerated linestring
detail::buffer::buffer_point<output_point_type>
@@ -763,7 +774,8 @@ private:
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
typename RobustPolicy
typename RobustPolicy,
typename Strategy
>
static inline
void iterate(Iterator begin, Iterator end,
@@ -774,15 +786,22 @@ private:
EndStrategy const& end_strategy,
PointStrategy const& point_strategy,
RobustPolicy const& robust_policy,
Strategy const& strategy, // side strategy
bool is_interior)
{
for (Iterator it = begin; it != end; ++it)
{
collection.start_new_ring();
strategy::buffer::result_code const code
// For exterior rings, it deflates if distance is negative.
// For interior rings, it is vice versa
bool const deflate = is_interior
? ! distance.negative()
: distance.negative();
collection.start_new_ring(deflate);
geometry::strategy::buffer::result_code const code
= policy::apply(*it, collection, distance, side_strategy,
join_strategy, end_strategy, point_strategy,
robust_policy);
robust_policy, strategy);
collection.finish_ring(code, is_interior);
}
@@ -797,7 +816,8 @@ private:
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
typename RobustPolicy
typename RobustPolicy,
typename Strategy
>
static inline
void apply_interior_rings(InteriorRings const& interior_rings,
@@ -807,12 +827,13 @@ private:
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
PointStrategy const& point_strategy,
RobustPolicy const& robust_policy)
RobustPolicy const& robust_policy,
Strategy const& strategy) // side strategy
{
iterate(boost::begin(interior_rings), boost::end(interior_rings),
collection, distance, side_strategy,
join_strategy, end_strategy, point_strategy,
robust_policy, true);
robust_policy, strategy, true);
}
public:
@@ -824,7 +845,8 @@ public:
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
typename RobustPolicy
typename RobustPolicy,
typename Strategy
>
static inline void apply(PolygonInput const& polygon,
Collection& collection,
@@ -833,16 +855,17 @@ public:
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
PointStrategy const& point_strategy,
RobustPolicy const& robust_policy)
RobustPolicy const& robust_policy,
Strategy const& strategy) // side strategy
{
{
collection.start_new_ring();
collection.start_new_ring(distance.negative());
strategy::buffer::result_code const code
geometry::strategy::buffer::result_code const code
= policy::apply(exterior_ring(polygon), collection,
distance, side_strategy,
join_strategy, end_strategy, point_strategy,
robust_policy);
robust_policy, strategy);
collection.finish_ring(code, false,
geometry::num_interior_rings(polygon) > 0u);
@@ -851,7 +874,7 @@ public:
apply_interior_rings(interior_rings(polygon),
collection, distance, side_strategy,
join_strategy, end_strategy, point_strategy,
robust_policy);
robust_policy, strategy);
}
};
@@ -927,11 +950,6 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator
typename tag_cast<typename tag<GeometryInput>::type, areal_tag>::type,
areal_tag
>::type::value;
bool const linear = boost::is_same
<
typename tag_cast<typename tag<GeometryInput>::type, linear_tag>::type,
linear_tag
>::type::value;
dispatch::buffer_inserter
<
@@ -945,10 +963,10 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator
>::apply(geometry_input, collection,
distance_strategy, side_strategy, join_strategy,
end_strategy, point_strategy,
robust_policy);
robust_policy, intersection_strategy.get_side_strategy());
collection.get_turns();
collection.classify_turns(linear);
collection.classify_turns();
if (BOOST_GEOMETRY_CONDITION(areal))
{
collection.check_remaining_points(distance_strategy);

View File

@@ -2,8 +2,8 @@
// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2017.
// Modifications copyright (c) 2017, Oracle and/or its affiliates.
// This file was modified by Oracle on 2017, 2018.
// Modifications copyright (c) 2017-2018, 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,
@@ -13,10 +13,6 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_POLICIES_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_POLICIES_HPP
#if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS)
# define BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION
#endif
#include <cstddef>
#include <boost/range.hpp>
@@ -26,6 +22,7 @@
#include <boost/geometry/algorithms/covered_by.hpp>
#include <boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp>
#include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
#include <boost/geometry/strategies/buffer.hpp>
@@ -127,6 +124,10 @@ public :
void visit_traverse_reject(Turns const& , Turn const& , Operation const& ,
detail::overlay::traverse_error_type )
{}
template <typename Rings>
void visit_generated_rings(Rings const& )
{}
};
@@ -177,9 +178,7 @@ struct buffer_turn_info
intersection_location_type location;
#if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
robust_point_type rob_pi, rob_pj, rob_qi, rob_qj;
#endif
std::size_t count_within;
@@ -189,9 +188,7 @@ struct buffer_turn_info
std::size_t count_on_offsetted;
std::size_t count_on_helper;
#if ! defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
std::size_t count_within_near_offsetted;
#endif
bool remove_on_multi;
@@ -208,9 +205,7 @@ struct buffer_turn_info
, count_in_original(0)
, count_on_offsetted(0)
, count_on_helper(0)
#if ! defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
, count_within_near_offsetted(0)
#endif
, remove_on_multi(false)
, count_on_occupied(0)
, count_on_multi(0)

View File

@@ -1,9 +1,10 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2016-2017.
// Modifications copyright (c) 2016-2017 Oracle and/or its affiliates.
// This file was modified by Oracle on 2016-2018.
// Modifications copyright (c) 2016-2018 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,
@@ -46,6 +47,7 @@
#include <boost/geometry/algorithms/detail/overlay/enrichment_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp>
#include <boost/geometry/algorithms/detail/overlay/ring_properties.hpp>
#include <boost/geometry/algorithms/detail/overlay/select_rings.hpp>
#include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/traverse.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
@@ -142,10 +144,34 @@ struct buffered_piece_collection
robust_point_type
>::type robust_comparable_radius_type;
typedef typename strategy::side::services::default_strategy
typedef typename IntersectionStrategy::side_strategy_type side_strategy_type;
typedef typename IntersectionStrategy::envelope_strategy_type envelope_strategy_type;
typedef typename IntersectionStrategy::expand_strategy_type expand_strategy_type;
typedef typename IntersectionStrategy::template area_strategy
<
typename cs_tag<point_type>::type
>::type side_strategy;
point_type
>::type area_strategy_type;
typedef typename IntersectionStrategy::template area_strategy
<
robust_point_type
>::type robust_area_strategy_type;
typedef typename area_strategy_type::template result_type
<
point_type
>::type area_result_type;
typedef typename robust_area_strategy_type::template result_type
<
robust_point_type
>::type robust_area_result_type;
typedef typename strategy::point_in_geometry::services::default_strategy
<
robust_point_type,
robust_ring_type
>::type point_in_geometry_strategy_type;
typedef typename geometry::rescale_policy_type
<
@@ -206,7 +232,10 @@ struct buffered_piece_collection
// 2: half, not part of offsetted rings - part of robust ring
std::vector<point_type> helper_points; // 4 points for side, 3 points for join - 0 points for flat-end
#endif
bool is_flat_start;
bool is_flat_end;
bool is_deflated;
bool is_convex;
bool is_monotonic_increasing[2]; // 0=x, 1=y
bool is_monotonic_decreasing[2]; // 0=x, 1=y
@@ -234,6 +263,9 @@ struct buffered_piece_collection
, right_index(-1)
, last_segment_index(-1)
, offsetted_count(-1)
, is_flat_start(false)
, is_flat_end(false)
, is_deflated(false)
, is_convex(false)
, robust_min_comparable_radius(0)
, robust_max_comparable_radius(0)
@@ -256,12 +288,14 @@ struct buffered_piece_collection
{}
inline robust_original(robust_ring_type const& ring,
bool is_interior, bool has_interiors)
bool is_interior, bool has_interiors,
envelope_strategy_type const& envelope_strategy,
expand_strategy_type const& expand_strategy)
: m_ring(ring)
, m_is_interior(is_interior)
, m_has_interiors(has_interiors)
{
geometry::envelope(m_ring, m_box);
geometry::envelope(m_ring, m_box, envelope_strategy);
// create monotonic sections in x-dimension
// The dimension is critical because the direction is later used
@@ -269,7 +303,8 @@ struct buffered_piece_collection
// and this strategy is scanning in x direction.
typedef boost::mpl::vector_c<std::size_t, 0> dimensions;
geometry::sectionalize<false, dimensions>(m_ring,
detail::no_rescale_policy(), m_sections);
detail::no_rescale_policy(), m_sections,
envelope_strategy, expand_strategy);
}
robust_ring_type m_ring;
@@ -285,6 +320,8 @@ struct buffered_piece_collection
piece_vector_type m_pieces;
turn_vector_type m_turns;
signed_size_type m_first_piece_index;
bool m_deflate;
bool m_has_deflated;
buffered_ring_collection<buffered_ring<Ring> > offsetted_rings; // indexed by multi_index
std::vector<robust_original> robust_originals; // robust representation of the original(s)
@@ -306,7 +343,13 @@ struct buffered_piece_collection
cluster_type m_clusters;
IntersectionStrategy const& m_intersection_strategy;
IntersectionStrategy m_intersection_strategy;
side_strategy_type m_side_strategy;
area_strategy_type m_area_strategy;
envelope_strategy_type m_envelope_strategy;
expand_strategy_type m_expand_strategy;
robust_area_strategy_type m_robust_area_strategy;
RobustPolicy const& m_robust_policy;
struct redundant_turn
@@ -320,7 +363,14 @@ struct buffered_piece_collection
buffered_piece_collection(IntersectionStrategy const& intersection_strategy,
RobustPolicy const& robust_policy)
: m_first_piece_index(-1)
, m_deflate(false)
, m_has_deflated(false)
, m_intersection_strategy(intersection_strategy)
, m_side_strategy(intersection_strategy.get_side_strategy())
, m_area_strategy(intersection_strategy.template get_area_strategy<point_type>())
, m_envelope_strategy(intersection_strategy.get_envelope_strategy())
, m_expand_strategy(intersection_strategy.get_expand_strategy())
, m_robust_area_strategy(intersection_strategy.template get_area_strategy<robust_point_type>())
, m_robust_policy(robust_policy)
{}
@@ -478,11 +528,11 @@ struct buffered_piece_collection
for (typename occupation_map_type::iterator it = occupation_map.begin();
it != occupation_map.end(); ++it)
{
it->second.get_left_turns(it->first, m_turns);
it->second.get_left_turns(it->first, m_turns, m_side_strategy);
}
}
inline void classify_turns(bool linear)
inline void classify_turns()
{
for (typename boost::range_iterator<turn_vector_type>::type it =
boost::begin(m_turns); it != boost::end(m_turns); ++it)
@@ -491,11 +541,10 @@ struct buffered_piece_collection
{
it->location = inside_buffer;
}
if (it->count_on_original_boundary > 0 && ! linear)
if (it->count_on_original_boundary > 0)
{
it->location = inside_buffer;
}
#if ! defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
if (it->count_within_near_offsetted > 0)
{
// Within can have in rare cases a rounding issue. We don't discard this
@@ -504,7 +553,94 @@ struct buffered_piece_collection
it->operations[0].enriched.startable = false;
it->operations[1].enriched.startable = false;
}
#endif
}
}
struct deflate_properties
{
bool has_inflated;
std::size_t count;
inline deflate_properties()
: has_inflated(false)
, count(0u)
{}
};
inline void discard_turns_for_deflate()
{
// Deflate cases should have at least 3 points PER deflated original
// to form a correct triangle
// But if there are intersections between a deflated ring and another
// ring, it is all accepted
// In deflate most turns are i/u by nature, but u/u is also possible
std::map<signed_size_type, deflate_properties> properties;
for (typename boost::range_iterator<turn_vector_type const>::type it =
boost::begin(m_turns); it != boost::end(m_turns); ++it)
{
const buffer_turn_info_type& turn = *it;
if (turn.location == location_ok)
{
const buffer_turn_operation_type& op0 = turn.operations[0];
const buffer_turn_operation_type& op1 = turn.operations[1];
if (! m_pieces[op0.seg_id.piece_index].is_deflated
|| ! m_pieces[op1.seg_id.piece_index].is_deflated)
{
properties[op0.seg_id.multi_index].has_inflated = true;
properties[op1.seg_id.multi_index].has_inflated = true;
continue;
}
// It is deflated, update counts
for (int i = 0; i < 2; i++)
{
const buffer_turn_operation_type& op = turn.operations[i];
if (op.operation == detail::overlay::operation_union
|| op.operation == detail::overlay::operation_continue)
{
properties[op.seg_id.multi_index].count++;
}
}
}
}
for (typename boost::range_iterator<turn_vector_type>::type it =
boost::begin(m_turns); it != boost::end(m_turns); ++it)
{
buffer_turn_info_type& turn = *it;
if (turn.location == location_ok)
{
const buffer_turn_operation_type& op0 = turn.operations[0];
const buffer_turn_operation_type& op1 = turn.operations[1];
signed_size_type const multi0 = op0.seg_id.multi_index;
signed_size_type const multi1 = op1.seg_id.multi_index;
if (multi0 == multi1)
{
const deflate_properties& prop = properties[multi0];
// NOTE: Keep brackets around prop.count
// avoid gcc-bug "parse error in template argument list"
// GCC versions 5.4 and 5.5 (and probably more)
if (! prop.has_inflated && (prop.count) < 3)
{
// Property is not inflated
// Not enough points, this might be caused by <float> where
// detection turn-in-original failed because of numeric errors
turn.location = location_discard;
}
}
else
{
// Two different (possibly deflated) rings
}
}
}
}
@@ -513,6 +649,15 @@ struct buffered_piece_collection
{
// Check if a turn is inside any of the originals
typedef turn_in_original_ovelaps_box
<
typename IntersectionStrategy::disjoint_point_box_strategy_type
> turn_in_original_ovelaps_box_type;
typedef original_ovelaps_box
<
typename IntersectionStrategy::disjoint_box_box_strategy_type
> original_ovelaps_box_type;
turn_in_original_visitor<turn_vector_type> visitor(m_turns);
geometry::partition
<
@@ -520,8 +665,8 @@ struct buffered_piece_collection
include_turn_policy,
detail::partition::include_all_policy
>::apply(m_turns, robust_originals, visitor,
turn_get_box(), turn_in_original_ovelaps_box(),
original_get_box(), original_ovelaps_box());
turn_get_box(), turn_in_original_ovelaps_box_type(),
original_get_box(), original_ovelaps_box_type());
bool const deflate = distance_strategy.negative();
@@ -533,7 +678,7 @@ struct buffered_piece_collection
{
if (deflate && turn.count_in_original <= 0)
{
// For deflate: it is not in original, discard
// For deflate/negative buffers: it is not in original, discard
turn.location = location_discard;
}
else if (! deflate && turn.count_in_original > 0)
@@ -543,6 +688,12 @@ struct buffered_piece_collection
}
}
}
if (m_has_deflated)
{
// Either strategy was negative, or there were interior rings
discard_turns_for_deflate();
}
}
inline bool assert_indices_in_robust_rings() const
@@ -599,46 +750,47 @@ struct buffered_piece_collection
}
}
#if ! defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
// Insert all rescaled turn-points into these rings, to form a
// reliable integer-based ring. All turns can be compared (inside) to this
// rings to see if they are inside.
for (typename boost::range_iterator<piece_vector_type>::type
it = boost::begin(m_pieces); it != boost::end(m_pieces); ++it)
if (! use_side_of_intersection<typename geometry::cs_tag<point_type>::type>::value)
{
piece& pc = *it;
signed_size_type piece_segment_index = pc.first_seg_id.segment_index;
if (! pc.robust_turns.empty())
// Insert all rescaled turn-points into these rings, to form a
// reliable integer-based ring. All turns can be compared (inside) to this
// rings to see if they are inside.
for (typename boost::range_iterator<piece_vector_type>::type
it = boost::begin(m_pieces); it != boost::end(m_pieces); ++it)
{
if (pc.robust_turns.size() > 1u)
piece& pc = *it;
signed_size_type piece_segment_index = pc.first_seg_id.segment_index;
if (! pc.robust_turns.empty())
{
std::sort(pc.robust_turns.begin(), pc.robust_turns.end(), buffer_operation_less());
}
// Walk through them, in reverse to insert at right index
signed_size_type index_offset = static_cast<signed_size_type>(pc.robust_turns.size()) - 1;
for (typename boost::range_reverse_iterator<const std::vector<robust_turn> >::type
rit = boost::const_rbegin(pc.robust_turns);
rit != boost::const_rend(pc.robust_turns);
++rit, --index_offset)
{
signed_size_type const index_in_vector = 1 + rit->seg_id.segment_index - piece_segment_index;
BOOST_GEOMETRY_ASSERT
(
index_in_vector > 0
&& index_in_vector < pc.offsetted_count
);
if (pc.robust_turns.size() > 1u)
{
std::sort(pc.robust_turns.begin(), pc.robust_turns.end(), buffer_operation_less());
}
// Walk through them, in reverse to insert at right index
signed_size_type index_offset = static_cast<signed_size_type>(pc.robust_turns.size()) - 1;
for (typename boost::range_reverse_iterator<const std::vector<robust_turn> >::type
rit = boost::const_rbegin(pc.robust_turns);
rit != boost::const_rend(pc.robust_turns);
++rit, --index_offset)
{
signed_size_type const index_in_vector = 1 + rit->seg_id.segment_index - piece_segment_index;
BOOST_GEOMETRY_ASSERT
(
index_in_vector > 0
&& index_in_vector < pc.offsetted_count
);
pc.robust_ring.insert(boost::begin(pc.robust_ring) + index_in_vector, rit->point);
pc.offsetted_count++;
pc.robust_ring.insert(boost::begin(pc.robust_ring) + index_in_vector, rit->point);
pc.offsetted_count++;
m_turns[rit->turn_index].operations[rit->operation_index].index_in_robust_ring = index_in_vector + index_offset;
m_turns[rit->turn_index].operations[rit->operation_index].index_in_robust_ring = index_in_vector + index_offset;
}
}
}
}
BOOST_GEOMETRY_ASSERT(assert_indices_in_robust_rings());
#endif
BOOST_GEOMETRY_ASSERT(assert_indices_in_robust_rings());
}
}
template <std::size_t Dimension>
@@ -699,7 +851,7 @@ struct buffered_piece_collection
++it)
{
piece& pc = *it;
if (geometry::area(pc.robust_ring) < 0)
if (geometry::area(pc.robust_ring, m_robust_area_strategy) < 0)
{
// Rings can be ccw:
// - in a concave piece
@@ -714,7 +866,8 @@ struct buffered_piece_collection
// create monotonic sections in y-dimension
typedef boost::mpl::vector_c<std::size_t, 1> dimensions;
geometry::sectionalize<false, dimensions>(pc.robust_ring,
detail::no_rescale_policy(), pc.sections);
detail::no_rescale_policy(), pc.sections,
m_envelope_strategy, m_expand_strategy);
// Determine min/max radius
typedef geometry::model::referring_segment<robust_point_type const>
@@ -778,12 +931,21 @@ struct buffered_piece_collection
> visitor(m_pieces, offsetted_rings, m_turns,
m_intersection_strategy, m_robust_policy);
typedef detail::section::get_section_box
<
typename IntersectionStrategy::expand_box_strategy_type
> get_section_box_type;
typedef detail::section::overlaps_section_box
<
typename IntersectionStrategy::disjoint_box_box_strategy_type
> overlaps_section_box_type;
geometry::partition
<
robust_box_type
>::apply(monotonic_sections, visitor,
detail::section::get_section_box(),
detail::section::overlaps_section_box());
get_section_box_type(),
overlaps_section_box_type());
}
insert_rescaled_piece_turns();
@@ -798,20 +960,31 @@ struct buffered_piece_collection
// Check if it is inside any of the pieces
turn_in_piece_visitor
<
turn_vector_type, piece_vector_type
> visitor(m_turns, m_pieces);
typename geometry::cs_tag<point_type>::type,
turn_vector_type, piece_vector_type,
point_in_geometry_strategy_type
> visitor(m_turns, m_pieces, point_in_geometry_strategy_type());
typedef turn_ovelaps_box
<
typename IntersectionStrategy::disjoint_point_box_strategy_type
> turn_ovelaps_box_type;
typedef piece_ovelaps_box
<
typename IntersectionStrategy::disjoint_box_box_strategy_type
> piece_ovelaps_box_type;
geometry::partition
<
robust_box_type
>::apply(m_turns, m_pieces, visitor,
turn_get_box(), turn_ovelaps_box(),
piece_get_box(), piece_ovelaps_box());
turn_get_box(), turn_ovelaps_box_type(),
piece_get_box(), piece_ovelaps_box_type());
}
}
inline void start_new_ring()
inline void start_new_ring(bool deflate)
{
signed_size_type const n = static_cast<signed_size_type>(offsetted_rings.size());
current_segment_id.source_index = 0;
@@ -823,6 +996,13 @@ struct buffered_piece_collection
current_robust_ring.clear();
m_first_piece_index = static_cast<signed_size_type>(boost::size(m_pieces));
m_deflate = deflate;
if (deflate)
{
// Pieces contain either deflated exterior rings, or inflated
// interior rings which are effectively deflated too
m_has_deflated = true;
}
}
inline void abort_ring()
@@ -922,7 +1102,7 @@ struct buffered_piece_collection
robust_originals.push_back(
robust_original(current_robust_ring,
is_interior, has_interiors));
is_interior, has_interiors, m_envelope_strategy, m_expand_strategy));
}
}
@@ -957,12 +1137,12 @@ struct buffered_piece_collection
piece pc;
pc.type = type;
pc.index = static_cast<signed_size_type>(boost::size(m_pieces));
pc.is_deflated = m_deflate;
current_segment_id.piece_index = pc.index;
pc.first_seg_id = current_segment_id;
// Assign left/right (for first/last piece per ring they will be re-assigned later)
pc.left_index = pc.index - 1;
pc.right_index = pc.index + 1;
@@ -1039,7 +1219,7 @@ struct buffered_piece_collection
return;
}
geometry::envelope(pc.robust_ring, pc.robust_envelope);
geometry::envelope(pc.robust_ring, pc.robust_envelope, m_envelope_strategy);
geometry::assign_inverse(pc.robust_offsetted_envelope);
for (signed_size_type i = 0; i < pc.offsetted_count; i++)
@@ -1216,18 +1396,31 @@ struct buffered_piece_collection
}
}
inline void mark_flat_start()
{
if (! m_pieces.empty())
{
piece& back = m_pieces.back();
back.is_flat_start = true;
}
}
inline void mark_flat_end()
{
if (! m_pieces.empty())
{
piece& back = m_pieces.back();
back.is_flat_end = true;
}
}
//-------------------------------------------------------------------------
inline void enrich()
{
typedef typename strategy::side::services::default_strategy
<
typename cs_tag<Ring>::type
>::type side_strategy_type;
enrich_intersection_points<false, false, overlay_buffer>(m_turns,
m_clusters, offsetted_rings, offsetted_rings,
m_robust_policy, side_strategy_type());
m_robust_policy, m_side_strategy);
}
// Discards all rings which do have not-OK intersection points only.
@@ -1252,6 +1445,8 @@ struct buffered_piece_collection
inline bool point_coveredby_original(point_type const& point)
{
typedef typename IntersectionStrategy::disjoint_point_box_strategy_type d_pb_strategy_type;
robust_point_type any_point;
geometry::recalculate(any_point, point, m_robust_policy);
@@ -1268,14 +1463,15 @@ struct buffered_piece_collection
{
robust_original const& original = *it;
if (detail::disjoint::disjoint_point_box(any_point,
original.m_box))
original.m_box,
d_pb_strategy_type()))
{
continue;
}
int const geometry_code
= detail::within::point_in_geometry(any_point,
original.m_ring);
original.m_ring, point_in_geometry_strategy_type());
if (geometry_code == -1)
{
@@ -1314,7 +1510,7 @@ struct buffered_piece_collection
buffered_ring<Ring>& ring = *it;
if (! ring.has_intersections()
&& boost::size(ring) > 0u
&& geometry::area(ring) < 0)
&& geometry::area(ring, m_area_strategy) < 0)
{
if (! point_coveredby_original(geometry::range::front(ring)))
{
@@ -1358,12 +1554,14 @@ struct buffered_piece_collection
overlay_buffer,
backtrack_for_buffer
> traverser;
std::map<ring_identifier, overlay::ring_turn_info> turn_info_per_ring;
traversed_rings.clear();
buffer_overlay_visitor visitor;
traverser::apply(offsetted_rings, offsetted_rings,
m_intersection_strategy, m_robust_policy,
m_turns, traversed_rings,
turn_info_per_ring,
m_clusters, visitor);
}
@@ -1391,7 +1589,7 @@ struct buffered_piece_collection
template <typename GeometryOutput, typename OutputIterator>
inline OutputIterator assign(OutputIterator out) const
{
typedef detail::overlay::ring_properties<point_type> properties;
typedef detail::overlay::ring_properties<point_type, area_result_type> properties;
std::map<ring_identifier, properties> selected;
@@ -1407,7 +1605,7 @@ struct buffered_piece_collection
if (! it->has_intersections()
&& ! it->is_untouched_outside_original)
{
properties p = properties(*it);
properties p = properties(*it, m_area_strategy);
if (p.valid)
{
ring_identifier id(0, index, -1);
@@ -1423,7 +1621,7 @@ struct buffered_piece_collection
it != boost::end(traversed_rings);
++it, ++index)
{
properties p = properties(*it);
properties p = properties(*it, m_area_strategy);
if (p.valid)
{
ring_identifier id(2, index, -1);
@@ -1431,8 +1629,10 @@ struct buffered_piece_collection
}
}
detail::overlay::assign_parents(offsetted_rings, traversed_rings, selected, true);
return detail::overlay::add_rings<GeometryOutput>(selected, offsetted_rings, traversed_rings, out);
detail::overlay::assign_parents<overlay_buffer>(offsetted_rings, traversed_rings,
selected, m_intersection_strategy);
return detail::overlay::add_rings<GeometryOutput>(selected, offsetted_rings, traversed_rings, out,
m_area_strategy);
}
};

View File

@@ -1,9 +1,10 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2017.
// Modifications copyright (c) 2017 Oracle and/or its affiliates.
// This file was modified by Oracle on 2017, 2018.
// Modifications copyright (c) 2017-2018 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,
@@ -13,8 +14,10 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_GET_PIECE_TURNS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_GET_PIECE_TURNS_HPP
#include <boost/core/ignore_unused.hpp>
#include <boost/range.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/algorithms/equals.hpp>
#include <boost/geometry/algorithms/expand.hpp>
#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
@@ -32,34 +35,81 @@ namespace boost { namespace geometry
namespace detail { namespace buffer
{
#if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
struct buffer_assign_turn
// Implements a unique_sub_range for a buffered piece,
// the range can return subsequent points
// known as "i", "j" and "k" (and further), indexed as 0,1,2,3
template <typename Ring>
struct unique_sub_range_from_piece
{
static bool const include_no_turn = false;
static bool const include_degenerate = false;
static bool const include_opposite = false;
typedef typename boost::range_iterator<Ring const>::type iterator_type;
typedef typename geometry::point_type<Ring const>::type point_type;
template
<
typename Info,
typename Point1,
typename Point2,
typename IntersectionInfo
>
static inline void apply(Info& info,
Point1 const& /*p1*/,
Point2 const& /*p2*/,
IntersectionInfo const& iinfo)
unique_sub_range_from_piece(Ring const& ring,
iterator_type iterator_at_i, iterator_type iterator_at_j)
: m_ring(ring)
, m_iterator_at_i(iterator_at_i)
, m_iterator_at_j(iterator_at_j)
, m_point_retrieved(false)
{}
static inline bool is_first_segment() { return false; }
static inline bool is_last_segment() { return false; }
static inline std::size_t size() { return 3u; }
inline point_type const& at(std::size_t index) const
{
info.rob_pi = iinfo.rpi();
info.rob_pj = iinfo.rpj();
info.rob_qi = iinfo.rqi();
info.rob_qj = iinfo.rqj();
BOOST_GEOMETRY_ASSERT(index < size());
switch (index)
{
case 0 : return *m_iterator_at_i;
case 1 : return *m_iterator_at_j;
case 2 : return get_point_k();
default : return *m_iterator_at_i;
}
}
private :
inline point_type const& get_point_k() const
{
if (! m_point_retrieved)
{
m_iterator_at_k = advance_one(m_iterator_at_j);
m_point_retrieved = true;
}
return *m_iterator_at_k;
}
inline void circular_advance_one(iterator_type& next) const
{
++next;
if (next == boost::end(m_ring))
{
next = boost::begin(m_ring) + 1;
}
}
inline iterator_type advance_one(iterator_type it) const
{
iterator_type result = it;
circular_advance_one(result);
// TODO: we could also use piece-boundaries
// to check if the point equals the last one
while (geometry::equals(*it, *result))
{
circular_advance_one(result);
}
return result;
}
Ring const& m_ring;
iterator_type m_iterator_at_i;
iterator_type m_iterator_at_j;
mutable iterator_type m_iterator_at_k;
mutable bool m_point_retrieved;
};
#endif
template
<
@@ -100,52 +150,34 @@ class piece_turn_visitor
return ! m_rings[piece1.first_seg_id.multi_index].has_concave;
}
template <typename Range, typename Iterator>
inline void move_to_next_point(Range const& range, Iterator& next) const
{
++next;
if (next == boost::end(range))
{
next = boost::begin(range) + 1;
}
}
template <typename Range, typename Iterator>
inline Iterator next_point(Range const& range, Iterator it) const
{
Iterator result = it;
move_to_next_point(range, result);
// TODO: we could use either piece-boundaries, or comparison with
// robust points, to check if the point equals the last one
while(geometry::equals(*it, *result))
{
move_to_next_point(range, result);
}
return result;
}
template <std::size_t Dimension, typename Iterator, typename Box>
inline void move_begin_iterator(Iterator& it_begin, Iterator it_beyond,
signed_size_type& index, int dir, Box const& other_bounding_box)
signed_size_type& index, int dir,
Box const& this_bounding_box,
Box const& other_bounding_box)
{
for(; it_begin != it_beyond
&& it_begin + 1 != it_beyond
&& detail::section::preceding<Dimension>(dir, *(it_begin + 1),
other_bounding_box, m_robust_policy);
this_bounding_box,
other_bounding_box,
m_robust_policy);
++it_begin, index++)
{}
}
template <std::size_t Dimension, typename Iterator, typename Box>
inline void move_end_iterator(Iterator it_begin, Iterator& it_beyond,
int dir, Box const& other_bounding_box)
int dir, Box const& this_bounding_box,
Box const& other_bounding_box)
{
while (it_beyond != it_begin
&& it_beyond - 1 != it_begin
&& it_beyond - 2 != it_begin)
{
if (detail::section::exceeding<Dimension>(dir, *(it_beyond - 2),
other_bounding_box, m_robust_policy))
this_bounding_box, other_bounding_box, m_robust_policy))
{
--it_beyond;
}
@@ -191,23 +223,23 @@ class piece_turn_visitor
// Set begin/end of monotonic ranges, in both x/y directions
signed_size_type index1 = sec1_first_index;
move_begin_iterator<0>(it1_first, it1_beyond, index1,
section1.directions[0], section2.bounding_box);
section1.directions[0], section1.bounding_box, section2.bounding_box);
move_end_iterator<0>(it1_first, it1_beyond,
section1.directions[0], section2.bounding_box);
section1.directions[0], section1.bounding_box, section2.bounding_box);
move_begin_iterator<1>(it1_first, it1_beyond, index1,
section1.directions[1], section2.bounding_box);
section1.directions[1], section1.bounding_box, section2.bounding_box);
move_end_iterator<1>(it1_first, it1_beyond,
section1.directions[1], section2.bounding_box);
section1.directions[1], section1.bounding_box, section2.bounding_box);
signed_size_type index2 = sec2_first_index;
move_begin_iterator<0>(it2_first, it2_beyond, index2,
section2.directions[0], section1.bounding_box);
section2.directions[0], section2.bounding_box, section1.bounding_box);
move_end_iterator<0>(it2_first, it2_beyond,
section2.directions[0], section1.bounding_box);
section2.directions[0], section2.bounding_box, section1.bounding_box);
move_begin_iterator<1>(it2_first, it2_beyond, index2,
section2.directions[1], section1.bounding_box);
section2.directions[1], section2.bounding_box, section1.bounding_box);
move_end_iterator<1>(it2_first, it2_beyond,
section2.directions[1], section1.bounding_box);
section2.directions[1], section2.bounding_box, section1.bounding_box);
turn_type the_model;
the_model.operations[0].piece_index = piece1.index;
@@ -222,15 +254,19 @@ class piece_turn_visitor
the_model.operations[1].piece_index = piece2.index;
the_model.operations[1].seg_id = piece2.first_seg_id;
the_model.operations[1].seg_id.segment_index = index2; // override
geometry::recalculate(the_model.rob_pi, *prev1, m_robust_policy);
geometry::recalculate(the_model.rob_pj, *it1, m_robust_policy);
iterator next1 = next_point(ring1, it1);
unique_sub_range_from_piece<ring_type> unique_sub_range1(ring1, prev1, it1);
iterator it2 = it2_first;
for (iterator prev2 = it2++;
it2 != it2_beyond;
prev2 = it2++, the_model.operations[1].seg_id.segment_index++)
{
iterator next2 = next_point(ring2, it2);
unique_sub_range_from_piece<ring_type> unique_sub_range2(ring2, prev2, it2);
geometry::recalculate(the_model.rob_qi, *prev2, m_robust_policy);
geometry::recalculate(the_model.rob_qj, *it2, m_robust_policy);
// TODO: internally get_turn_info calculates robust points.
// But they are already calculated.
@@ -239,20 +275,14 @@ class piece_turn_visitor
// and iterating in sync with them...
typedef detail::overlay::get_turn_info
<
#if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
buffer_assign_turn
#else
detail::overlay::assign_null_policy
#endif
> turn_policy;
turn_policy::apply(*prev1, *it1, *next1,
*prev2, *it2, *next2,
false, false, false, false,
the_model,
m_intersection_strategy,
m_robust_policy,
std::back_inserter(m_turns));
turn_policy::apply(unique_sub_range1, unique_sub_range2,
the_model,
m_intersection_strategy,
m_robust_policy,
std::back_inserter(m_turns));
}
}
}
@@ -272,10 +302,10 @@ public:
{}
template <typename Section>
inline void apply(Section const& section1, Section const& section2,
inline bool apply(Section const& section1, Section const& section2,
bool first = true)
{
boost::ignore_unused_variable_warning(first);
boost::ignore_unused(first);
typedef typename boost::range_value<Pieces const>::type piece_type;
piece_type const& piece1 = m_pieces[section1.ring_id.source_index];
@@ -285,12 +315,15 @@ public:
|| is_adjacent(piece1, piece2)
|| is_on_same_convex_ring(piece1, piece2)
|| detail::disjoint::disjoint_box_box(section1.bounding_box,
section2.bounding_box) )
section2.bounding_box,
m_intersection_strategy.get_disjoint_box_box_strategy()) )
{
return;
return true;
}
calculate_turns(piece1, piece2, section1, section2);
return true;
}
};

View File

@@ -2,8 +2,8 @@
// Copyright (c) 2014 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2016.
// Modifications copyright (c) 2016 Oracle and/or its affiliates.
// This file was modified by Oracle on 2016, 2018.
// Modifications copyright (c) 2016-2018 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,
@@ -16,6 +16,7 @@
#include <boost/core/ignore_unused.hpp>
#include <boost/geometry/algorithms/detail/buffer/buffer_policies.hpp>
#include <boost/geometry/algorithms/expand.hpp>
#include <boost/geometry/strategies/agnostic/point_in_poly_winding.hpp>
#include <boost/geometry/strategies/buffer.hpp>
@@ -38,12 +39,14 @@ struct original_get_box
}
};
template <typename DisjointBoxBoxStrategy>
struct original_ovelaps_box
{
template <typename Box, typename Original>
static inline bool apply(Box const& box, Original const& original)
{
return ! detail::disjoint::disjoint_box_box(box, original.m_box);
return ! detail::disjoint::disjoint_box_box(box, original.m_box,
DisjointBoxBoxStrategy());
}
};
@@ -56,6 +59,7 @@ struct include_turn_policy
}
};
template <typename DisjointPointBoxStrategy>
struct turn_in_original_ovelaps_box
{
template <typename Box, typename Turn>
@@ -68,7 +72,7 @@ struct turn_in_original_ovelaps_box
}
return ! geometry::detail::disjoint::disjoint_point_box(
turn.robust_point, box);
turn.robust_point, box, DisjointPointBoxStrategy());
}
};
@@ -212,27 +216,27 @@ public:
{}
template <typename Turn, typename Original>
inline void apply(Turn const& turn, Original const& original, bool first = true)
inline bool apply(Turn const& turn, Original const& original, bool first = true)
{
boost::ignore_unused_variable_warning(first);
boost::ignore_unused(first);
if (turn.location != location_ok || turn.within_original)
{
// Skip all points already processed
return;
return true;
}
if (geometry::disjoint(turn.robust_point, original.m_box))
{
// Skip all disjoint
return;
return true;
}
int const code = point_in_original(turn.robust_point, original);
if (code == -1)
{
return;
return true;
}
Turn& mutable_turn = m_mutable_turns[turn.turn_index];
@@ -259,6 +263,8 @@ public:
mutable_turn.within_original = true;
mutable_turn.count_in_original = 1;
}
return true;
}
private :

View File

@@ -1,9 +1,10 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2016.
// Modifications copyright (c) 2016 Oracle and/or its affiliates.
// This file was modified by Oracle on 2016, 2018.
// Modifications copyright (c) 2016-2018 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,
@@ -19,6 +20,7 @@
#include <boost/range.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/core/config.hpp>
#include <boost/geometry/arithmetic/dot_product.hpp>
#include <boost/geometry/algorithms/assign.hpp>
@@ -33,9 +35,8 @@
#include <boost/geometry/strategies/buffer.hpp>
#include <boost/geometry/algorithms/detail/buffer/buffer_policies.hpp>
#if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
#include <boost/geometry/strategies/cartesian/side_of_intersection.hpp>
#endif
#include <boost/geometry/strategies/agnostic/point_in_poly_winding.hpp>
namespace boost { namespace geometry
@@ -55,6 +56,7 @@ struct piece_get_box
}
};
template <typename DisjointBoxBoxStrategy>
struct piece_ovelaps_box
{
template <typename Box, typename Piece>
@@ -70,7 +72,8 @@ struct piece_ovelaps_box
return false;
}
return ! geometry::detail::disjoint::disjoint_box_box(box, piece.robust_envelope);
return ! geometry::detail::disjoint::disjoint_box_box(box, piece.robust_envelope,
DisjointBoxBoxStrategy());
}
};
@@ -83,12 +86,14 @@ struct turn_get_box
}
};
template <typename DisjointPointBoxStrategy>
struct turn_ovelaps_box
{
template <typename Box, typename Turn>
static inline bool apply(Box const& box, Turn const& turn)
{
return ! geometry::detail::disjoint::disjoint_point_box(turn.robust_point, box);
return ! geometry::detail::disjoint::disjoint_point_box(turn.robust_point, box,
DisjointPointBoxStrategy());
}
};
@@ -100,10 +105,8 @@ enum analyse_result
analyse_disjoint,
analyse_within,
analyse_on_original_boundary,
analyse_on_offsetted
#if ! defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
, analyse_near_offsetted
#endif
analyse_on_offsetted,
analyse_near_offsetted
};
template <typename Point>
@@ -120,85 +123,115 @@ inline bool in_box(Point const& previous,
return geometry::covered_by(point, box);
}
template <typename Point, typename Turn>
inline analyse_result check_segment(Point const& previous,
Point const& current, Turn const& turn,
bool from_monotonic)
{
#if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
typedef geometry::model::referring_segment<Point const> segment_type;
segment_type const p(turn.rob_pi, turn.rob_pj);
segment_type const q(turn.rob_qi, turn.rob_qj);
segment_type const r(previous, current);
int const side = strategy::side::side_of_intersection::apply(p, q, r,
turn.robust_point);
if (side == 0)
{
return analyse_on_offsetted;
}
if (side == -1 && from_monotonic)
{
return analyse_within;
}
if (side == 1 && from_monotonic)
{
return analyse_disjoint;
}
return analyse_continue;
// meta-programming-structure defining if to use side-of-intersection
// (only for cartesian / only necessary with rescaling)
template <typename Tag>
struct use_side_of_intersection {};
#if defined(BOOST_GEOMETRY_USE_RESCALING)
// With rescaling, let Cartesian use side-of-intersection
template <>
struct use_side_of_intersection<cartesian_tag> { static bool const value = true; };
#else
template <>
struct use_side_of_intersection<cartesian_tag> { static bool const value = false; };
#endif
typedef typename strategy::side::services::default_strategy
<
typename cs_tag<Point>::type
>::type side_strategy;
typedef typename geometry::coordinate_type<Point>::type coordinate_type;
template <>
struct use_side_of_intersection<spherical_tag> { static bool const value = false; };
coordinate_type const twice_area
= side_strategy::template side_value
<
coordinate_type,
coordinate_type
>(previous, current, turn.robust_point);
template <>
struct use_side_of_intersection<geographic_tag> { static bool const value = false; };
if (twice_area == 0)
template <bool UseSideOfIntersection>
struct check_segment {};
// Implementation using side-of-intersection
template <>
struct check_segment<true>
{
template <typename Point, typename Turn>
static inline analyse_result apply(Point const& previous,
Point const& current, Turn const& turn,
bool from_monotonic)
{
// Collinear, only on segment if it is covered by its bbox
if (in_box(previous, current, turn.robust_point))
typedef geometry::model::referring_segment<Point const> segment_type;
segment_type const p(turn.rob_pi, turn.rob_pj);
segment_type const q(turn.rob_qi, turn.rob_qj);
segment_type const r(previous, current);
int const side = strategy::side::side_of_intersection::apply(p, q, r,
turn.robust_point);
if (side == 0)
{
return analyse_on_offsetted;
}
}
else if (twice_area < 0)
{
// It is in the triangle right-of the segment where the
// segment is the hypothenusa. Check if it is close
// (within rounding-area)
if (twice_area * twice_area < geometry::comparable_distance(previous, current)
&& in_box(previous, current, turn.robust_point))
{
return analyse_near_offsetted;
}
else if (from_monotonic)
if (side == -1 && from_monotonic)
{
return analyse_within;
}
if (side == 1 && from_monotonic)
{
return analyse_disjoint;
}
return analyse_continue;
}
else if (twice_area > 0 && from_monotonic)
};
template <>
struct check_segment<false>
{
template <typename Point, typename Turn>
static inline analyse_result apply(Point const& previous,
Point const& current, Turn const& turn,
bool from_monotonic)
{
// Left of segment
return analyse_disjoint;
typedef typename strategy::side::services::default_strategy
<
typename cs_tag<Point>::type
>::type side_strategy;
int const side = side_strategy::apply(previous, current, turn.robust_point);
if (side == 0)
{
// Collinear, only on segment if it is covered by its bbox
if (in_box(previous, current, turn.robust_point))
{
return analyse_on_offsetted;
}
}
else if (side == -1)
{
// It is in the triangle right-of the segment where the
// segment is the hypothenusa. Check if it is close
// (within rounding-area)
if (in_box(previous, current, turn.robust_point))
{
return analyse_near_offsetted;
}
else if (from_monotonic)
{
return analyse_within;
}
}
else if (from_monotonic)
{
// Left of segment
return analyse_disjoint;
}
// Not monotonic, on left or right side: continue analysing
return analyse_continue;
}
};
// Not monotonic, on left or right side: continue analysing
return analyse_continue;
#endif
}
template <bool UseSideOfIntersection>
class analyse_turn_wrt_point_piece {};
class analyse_turn_wrt_point_piece
template <>
class analyse_turn_wrt_point_piece<true>
{
public :
template <typename Turn, typename Piece>
@@ -208,17 +241,9 @@ public :
typedef typename Turn::robust_point_type point_type;
typedef typename geometry::coordinate_type<point_type>::type coordinate_type;
#if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
typedef geometry::model::referring_segment<point_type const> segment_type;
segment_type const p(turn.rob_pi, turn.rob_pj);
segment_type const q(turn.rob_qi, turn.rob_qj);
#else
typedef strategy::within::winding<point_type> strategy_type;
typename strategy_type::state_type state;
strategy_type strategy;
boost::ignore_unused(strategy);
#endif
BOOST_GEOMETRY_ASSERT(! piece.sections.empty());
@@ -238,7 +263,6 @@ public :
point_type const& previous = piece.robust_ring[i - 1];
point_type const& current = piece.robust_ring[i];
#if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
// First check if it is in range - if it is not, the
// expensive side_of_intersection does not need to be
@@ -269,8 +293,51 @@ public :
return analyse_on_offsetted;
}
}
#else
analyse_result code = check_segment(previous, current, turn, false);
}
}
}
// It is nowhere outside, and not on segment, so it is within
return analyse_within;
}
};
template <>
class analyse_turn_wrt_point_piece<false>
{
public :
template <typename Turn, typename Piece>
static inline analyse_result apply(Turn const& turn, Piece const& piece)
{
typedef typename Piece::section_type section_type;
typedef typename Turn::robust_point_type point_type;
typedef typename geometry::coordinate_type<point_type>::type coordinate_type;
typedef strategy::within::winding<point_type> strategy_type;
typename strategy_type::state_type state;
strategy_type strategy;
BOOST_GEOMETRY_ASSERT(! piece.sections.empty());
coordinate_type const point_x = geometry::get<0>(turn.robust_point);
for (std::size_t s = 0; s < piece.sections.size(); s++)
{
section_type const& section = piece.sections[s];
// If point within horizontal range of monotonic section:
if (! section.duplicate
&& section.begin_index < section.end_index
&& point_x >= geometry::get<min_corner, 0>(section.bounding_box) - 1
&& point_x <= geometry::get<max_corner, 0>(section.bounding_box) + 1)
{
for (signed_size_type i = section.begin_index + 1; i <= section.end_index; i++)
{
point_type const& previous = piece.robust_ring[i - 1];
point_type const& current = piece.robust_ring[i];
analyse_result code = check_segment<false>::apply(previous, current, turn, false);
if (code != analyse_continue)
{
return code;
@@ -279,15 +346,10 @@ public :
// Get the state (to determine it is within), we don't have
// to cover the on-segment case (covered above)
strategy.apply(turn.robust_point, previous, current, state);
#endif
}
}
}
#if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
// It is nowhere outside, and not on segment, so it is within
return analyse_within;
#else
int const code = strategy.result(state);
if (code == 1)
{
@@ -300,21 +362,24 @@ public :
// Should normally not occur - on-segment is covered
return analyse_unknown;
#endif
}
};
class analyse_turn_wrt_piece
template <bool UseSideOfIntersection>
struct check_helper_segment {};
template <>
struct check_helper_segment<true>
{
template <typename Point, typename Turn>
static inline analyse_result check_helper_segment(Point const& s1,
static inline analyse_result apply(Point const& s1,
Point const& s2, Turn const& turn,
bool is_original,
Point const& offsetted)
{
boost::ignore_unused(offsetted);
#if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
boost::ignore_unused(is_original);
typedef geometry::model::referring_segment<Point const> segment_type;
segment_type const p(turn.rob_pi, turn.rob_pj);
segment_type const q(turn.rob_qi, turn.rob_qj);
@@ -339,11 +404,9 @@ class analyse_turn_wrt_piece
if (geometry::covered_by(turn.robust_point, box))
{
// Points on helper-segments are considered as within
// Points on original boundary are processed differently
return is_original
? analyse_on_original_boundary
: analyse_within;
// Points on helper-segments (and not on its corners)
// are considered as within
return analyse_within;
}
// It is collinear but not on the segment. Because these
@@ -355,7 +418,20 @@ class analyse_turn_wrt_piece
// right of segment
return analyse_continue;
#else
}
};
template <>
struct check_helper_segment<false>
{
template <typename Point, typename Turn>
static inline analyse_result apply(Point const& s1,
Point const& s2, Turn const& turn,
bool is_original,
Point const& offsetted)
{
boost::ignore_unused(offsetted);
typedef typename strategy::side::services::default_strategy
<
typename cs_tag<Point>::type
@@ -404,9 +480,12 @@ class analyse_turn_wrt_piece
// right of segment
return analyse_continue;
#endif
}
};
template <bool UseSideOfIntersection>
class analyse_turn_wrt_piece
{
template <typename Turn, typename Piece>
static inline analyse_result check_helper_segments(Turn const& turn, Piece const& piece)
{
@@ -423,6 +502,13 @@ class analyse_turn_wrt_piece
{
points[i] = piece.robust_ring[piece.offsetted_count + i];
}
// 3--offsetted outline--0
// | |
// left | | right
// | |
// 2===>==original===>===1
}
else if (helper_count == 3)
{
@@ -446,14 +532,20 @@ class analyse_turn_wrt_piece
{
return analyse_on_offsetted;
}
if (comparator(point, points[1]) || comparator(point, points[2]))
if (comparator(point, points[1]))
{
return analyse_on_original_boundary;
// On original, right corner
return piece.is_flat_end ? analyse_continue : analyse_on_original_boundary;
}
if (comparator(point, points[2]))
{
// On original, left corner
return piece.is_flat_start ? analyse_continue : analyse_on_original_boundary;
}
// Right side of the piece
analyse_result result
= check_helper_segment(points[0], points[1], turn,
= check_helper_segment<UseSideOfIntersection>::apply(points[0], points[1], turn,
false, points[0]);
if (result != analyse_continue)
{
@@ -461,7 +553,7 @@ class analyse_turn_wrt_piece
}
// Left side of the piece
result = check_helper_segment(points[2], points[3], turn,
result = check_helper_segment<UseSideOfIntersection>::apply(points[2], points[3], turn,
false, points[3]);
if (result != analyse_continue)
{
@@ -471,7 +563,7 @@ class analyse_turn_wrt_piece
if (! comparator(points[1], points[2]))
{
// Side of the piece at side of original geometry
result = check_helper_segment(points[1], points[2], turn,
result = check_helper_segment<UseSideOfIntersection>::apply(points[1], points[2], turn,
true, point);
if (result != analyse_continue)
{
@@ -518,7 +610,7 @@ class analyse_turn_wrt_piece
// w.r.t. specified direction, and prev points to a point smaller
// We now know if it is inside/outside
it_type prev = it - 1;
return check_segment(*prev, *it, turn, true);
return check_segment<UseSideOfIntersection>::apply(*prev, *it, turn, true);
}
return analyse_continue;
}
@@ -575,7 +667,7 @@ public :
// (on which any side or side-value would return 0)
if (! comparator(previous, current))
{
code = check_segment(previous, current, turn, false);
code = check_segment<UseSideOfIntersection>::apply(previous, current, turn, false);
if (code != analyse_continue)
{
return code;
@@ -588,45 +680,17 @@ public :
};
// Helper Structure, of which the apply method returns a side value in {-1, 0, 1}
template <bool UseSideOfIntersection>
struct turn_in_piece {};
template <typename Turns, typename Pieces>
class turn_in_piece_visitor
template <>
struct turn_in_piece<true>
{
Turns& m_turns; // because partition is currently operating on const input only
Pieces const& m_pieces; // to check for piece-type
template <typename Operation, typename Piece>
inline bool skip(Operation const& op, Piece const& piece) const
{
if (op.piece_index == piece.index)
{
return true;
}
Piece const& pc = m_pieces[op.piece_index];
if (pc.left_index == piece.index || pc.right_index == piece.index)
{
if (pc.type == strategy::buffer::buffered_flat_end)
{
// If it is a flat end, don't compare against its neighbor:
// it will always be located on one of the helper segments
return true;
}
if (pc.type == strategy::buffer::buffered_concave)
{
// If it is concave, the same applies: the IP will be
// located on one of the helper segments
return true;
}
}
return false;
}
#if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
// NOTE: this function returns a side value in {-1, 0, 1}
private :
template <typename Turn, typename Piece>
static inline int turn_in_convex_piece(Turn const& turn,
Piece const& piece)
static inline int in_convex_piece(Turn const& turn, Piece const& piece)
{
typedef typename Turn::robust_point_type point_type;
typedef typename Piece::piece_robust_ring_type ring_type;
@@ -675,43 +739,119 @@ class turn_in_piece_visitor
}
return 1; // inside
}
#endif
public :
template <typename Turn, typename Piece, typename Strategy>
static inline int apply(Turn const& turn, Piece const& piece,
Strategy const& strategy)
{
if (piece.is_convex)
{
return in_convex_piece(turn, piece);
}
else
{
// side-of-intersection only supported for convex pieces
// Call point_in_geometry, a performance-bottleneck
// TODO: might be replaced by extending analysing piece
return detail::within::point_in_geometry(turn.robust_point,
piece.robust_ring, strategy);
}
}
};
template <>
struct turn_in_piece<false>
{
public :
template <typename Turn, typename Piece, typename Strategy>
static inline int apply(Turn const& turn, Piece const& piece,
Strategy const& strategy)
{
return detail::within::point_in_geometry(turn.robust_point,
piece.robust_ring, strategy);
}
};
template
<
typename CsTag,
typename Turns,
typename Pieces,
typename PointInGeometryStrategy
>
class turn_in_piece_visitor
{
Turns& m_turns; // because partition is currently operating on const input only
Pieces const& m_pieces; // to check for piece-type
PointInGeometryStrategy const& m_point_in_geometry_strategy;
template <typename Operation, typename Piece>
inline bool skip(Operation const& op, Piece const& piece) const
{
if (op.piece_index == piece.index)
{
return true;
}
Piece const& pc = m_pieces[op.piece_index];
if (pc.left_index == piece.index || pc.right_index == piece.index)
{
if (pc.type == strategy::buffer::buffered_flat_end)
{
// If it is a flat end, don't compare against its neighbor:
// it will always be located on one of the helper segments
return true;
}
if (pc.type == strategy::buffer::buffered_concave)
{
// If it is concave, the same applies: the IP will be
// located on one of the helper segments
return true;
}
}
return false;
}
public:
inline turn_in_piece_visitor(Turns& turns, Pieces const& pieces)
inline turn_in_piece_visitor(Turns& turns, Pieces const& pieces,
PointInGeometryStrategy const& strategy)
: m_turns(turns)
, m_pieces(pieces)
, m_point_in_geometry_strategy(strategy)
{}
template <typename Turn, typename Piece>
inline void apply(Turn const& turn, Piece const& piece, bool first = true)
inline bool apply(Turn const& turn, Piece const& piece, bool first = true)
{
boost::ignore_unused_variable_warning(first);
boost::ignore_unused(first);
if (turn.count_within > 0)
{
// Already inside - no need to check again
return;
return true;
}
if (piece.type == strategy::buffer::buffered_flat_end
|| piece.type == strategy::buffer::buffered_concave)
{
// Turns cannot be located within flat-end or concave pieces
return;
return true;
}
if (! geometry::covered_by(turn.robust_point, piece.robust_envelope))
{
// Easy check: if the turn is not in the envelope, we can safely return
return;
return true;
}
if (skip(turn.operations[0], piece) || skip(turn.operations[1], piece))
{
return;
return true;
}
// TODO: mutable_piece to make some on-demand preparations in analyse
@@ -733,63 +873,51 @@ public:
if (cd < piece.robust_min_comparable_radius)
{
mutable_turn.count_within++;
return;
return true;
}
if (cd > piece.robust_max_comparable_radius)
{
return;
return true;
}
}
static const bool use_soi = use_side_of_intersection<CsTag>::value;
boost::ignore_unused(use_soi);
analyse_result analyse_code =
piece.type == geometry::strategy::buffer::buffered_point
? analyse_turn_wrt_point_piece::apply(turn, piece)
: analyse_turn_wrt_piece::apply(turn, piece);
? analyse_turn_wrt_point_piece<use_soi>::apply(turn, piece)
: analyse_turn_wrt_piece<use_soi>::apply(turn, piece);
switch(analyse_code)
{
case analyse_disjoint :
return;
return true;
case analyse_on_offsetted :
mutable_turn.count_on_offsetted++; // value is not used anymore
return;
return true;
case analyse_on_original_boundary :
mutable_turn.count_on_original_boundary++;
return;
return true;
case analyse_within :
mutable_turn.count_within++;
return;
#if ! defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
return true;
case analyse_near_offsetted :
mutable_turn.count_within_near_offsetted++;
return;
#endif
return true;
default :
break;
}
#if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
// We don't know (yet)
int geometry_code = 0;
if (piece.is_convex)
{
geometry_code = turn_in_convex_piece(turn, piece);
}
else
{
// TODO: this point_in_geometry is a performance-bottleneck here and
// will be replaced completely by extending analyse_piece functionality
geometry_code = detail::within::point_in_geometry(turn.robust_point, piece.robust_ring);
}
#else
int geometry_code = detail::within::point_in_geometry(turn.robust_point, piece.robust_ring);
#endif
int const geometry_code = turn_in_piece<use_soi>::apply(turn, piece,
m_point_in_geometry_strategy);
if (geometry_code == 1)
{
mutable_turn.count_within++;
}
return true;
}
};

View File

@@ -0,0 +1,279 @@
// 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, 2014, 2017, 2019.
// Modifications copyright (c) 2013-2019 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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_COVERED_BY_IMPLEMENTATION_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_COVERED_BY_IMPLEMENTATION_HPP
#include <cstddef>
#include <boost/core/ignore_unused.hpp>
#include <boost/geometry/algorithms/detail/covered_by/interface.hpp>
#include <boost/geometry/algorithms/detail/within/implementation.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace covered_by {
struct use_point_in_geometry
{
template <typename Geometry1, typename Geometry2, typename Strategy>
static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
{
return detail::within::covered_by_point_geometry(geometry1, geometry2, strategy);
}
};
struct use_relate
{
template <typename Geometry1, typename Geometry2, typename Strategy>
static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
{
typedef typename detail::de9im::static_mask_covered_by_type
<
Geometry1, Geometry2
>::type covered_by_mask;
return geometry::relate(geometry1, geometry2, covered_by_mask(), strategy);
}
};
}} // namespace detail::covered_by
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Point, typename Box>
struct covered_by<Point, Box, point_tag, box_tag>
{
template <typename Strategy>
static inline bool apply(Point const& point, Box const& box, Strategy const& strategy)
{
::boost::ignore_unused(strategy);
return strategy.apply(point, box);
}
};
template <typename Box1, typename Box2>
struct covered_by<Box1, Box2, box_tag, box_tag>
{
template <typename Strategy>
static inline bool apply(Box1 const& box1, Box2 const& box2, Strategy const& strategy)
{
assert_dimension_equal<Box1, Box2>();
::boost::ignore_unused(strategy);
return strategy.apply(box1, box2);
}
};
// P/P
template <typename Point1, typename Point2>
struct covered_by<Point1, Point2, point_tag, point_tag>
: public detail::covered_by::use_point_in_geometry
{};
template <typename Point, typename MultiPoint>
struct covered_by<Point, MultiPoint, point_tag, multi_point_tag>
: public detail::covered_by::use_point_in_geometry
{};
template <typename MultiPoint, typename Point>
struct covered_by<MultiPoint, Point, multi_point_tag, point_tag>
: public detail::within::multi_point_point
{};
template <typename MultiPoint1, typename MultiPoint2>
struct covered_by<MultiPoint1, MultiPoint2, multi_point_tag, multi_point_tag>
: public detail::within::multi_point_multi_point
{};
// P/L
template <typename Point, typename Segment>
struct covered_by<Point, Segment, point_tag, segment_tag>
: public detail::covered_by::use_point_in_geometry
{};
template <typename Point, typename Linestring>
struct covered_by<Point, Linestring, point_tag, linestring_tag>
: public detail::covered_by::use_point_in_geometry
{};
template <typename Point, typename MultiLinestring>
struct covered_by<Point, MultiLinestring, point_tag, multi_linestring_tag>
: public detail::covered_by::use_point_in_geometry
{};
template <typename MultiPoint, typename Segment>
struct covered_by<MultiPoint, Segment, multi_point_tag, segment_tag>
: public detail::within::multi_point_single_geometry<false>
{};
template <typename MultiPoint, typename Linestring>
struct covered_by<MultiPoint, Linestring, multi_point_tag, linestring_tag>
: public detail::within::multi_point_single_geometry<false>
{};
template <typename MultiPoint, typename MultiLinestring>
struct covered_by<MultiPoint, MultiLinestring, multi_point_tag, multi_linestring_tag>
: public detail::within::multi_point_multi_geometry<false>
{};
// P/A
template <typename Point, typename Ring>
struct covered_by<Point, Ring, point_tag, ring_tag>
: public detail::covered_by::use_point_in_geometry
{};
template <typename Point, typename Polygon>
struct covered_by<Point, Polygon, point_tag, polygon_tag>
: public detail::covered_by::use_point_in_geometry
{};
template <typename Point, typename MultiPolygon>
struct covered_by<Point, MultiPolygon, point_tag, multi_polygon_tag>
: public detail::covered_by::use_point_in_geometry
{};
template <typename MultiPoint, typename Ring>
struct covered_by<MultiPoint, Ring, multi_point_tag, ring_tag>
: public detail::within::multi_point_single_geometry<false>
{};
template <typename MultiPoint, typename Polygon>
struct covered_by<MultiPoint, Polygon, multi_point_tag, polygon_tag>
: public detail::within::multi_point_single_geometry<false>
{};
template <typename MultiPoint, typename MultiPolygon>
struct covered_by<MultiPoint, MultiPolygon, multi_point_tag, multi_polygon_tag>
: public detail::within::multi_point_multi_geometry<false>
{};
// L/L
template <typename Linestring1, typename Linestring2>
struct covered_by<Linestring1, Linestring2, linestring_tag, linestring_tag>
: public detail::covered_by::use_relate
{};
template <typename Linestring, typename MultiLinestring>
struct covered_by<Linestring, MultiLinestring, linestring_tag, multi_linestring_tag>
: public detail::covered_by::use_relate
{};
template <typename MultiLinestring, typename Linestring>
struct covered_by<MultiLinestring, Linestring, multi_linestring_tag, linestring_tag>
: public detail::covered_by::use_relate
{};
template <typename MultiLinestring1, typename MultiLinestring2>
struct covered_by<MultiLinestring1, MultiLinestring2, multi_linestring_tag, multi_linestring_tag>
: public detail::covered_by::use_relate
{};
// L/A
template <typename Linestring, typename Ring>
struct covered_by<Linestring, Ring, linestring_tag, ring_tag>
: public detail::covered_by::use_relate
{};
template <typename MultiLinestring, typename Ring>
struct covered_by<MultiLinestring, Ring, multi_linestring_tag, ring_tag>
: public detail::covered_by::use_relate
{};
template <typename Linestring, typename Polygon>
struct covered_by<Linestring, Polygon, linestring_tag, polygon_tag>
: public detail::covered_by::use_relate
{};
template <typename MultiLinestring, typename Polygon>
struct covered_by<MultiLinestring, Polygon, multi_linestring_tag, polygon_tag>
: public detail::covered_by::use_relate
{};
template <typename Linestring, typename MultiPolygon>
struct covered_by<Linestring, MultiPolygon, linestring_tag, multi_polygon_tag>
: public detail::covered_by::use_relate
{};
template <typename MultiLinestring, typename MultiPolygon>
struct covered_by<MultiLinestring, MultiPolygon, multi_linestring_tag, multi_polygon_tag>
: public detail::covered_by::use_relate
{};
// A/A
template <typename Ring1, typename Ring2>
struct covered_by<Ring1, Ring2, ring_tag, ring_tag>
: public detail::covered_by::use_relate
{};
template <typename Ring, typename Polygon>
struct covered_by<Ring, Polygon, ring_tag, polygon_tag>
: public detail::covered_by::use_relate
{};
template <typename Polygon, typename Ring>
struct covered_by<Polygon, Ring, polygon_tag, ring_tag>
: public detail::covered_by::use_relate
{};
template <typename Polygon1, typename Polygon2>
struct covered_by<Polygon1, Polygon2, polygon_tag, polygon_tag>
: public detail::covered_by::use_relate
{};
template <typename Ring, typename MultiPolygon>
struct covered_by<Ring, MultiPolygon, ring_tag, multi_polygon_tag>
: public detail::covered_by::use_relate
{};
template <typename MultiPolygon, typename Ring>
struct covered_by<MultiPolygon, Ring, multi_polygon_tag, ring_tag>
: public detail::covered_by::use_relate
{};
template <typename Polygon, typename MultiPolygon>
struct covered_by<Polygon, MultiPolygon, polygon_tag, multi_polygon_tag>
: public detail::covered_by::use_relate
{};
template <typename MultiPolygon, typename Polygon>
struct covered_by<MultiPolygon, Polygon, multi_polygon_tag, polygon_tag>
: public detail::covered_by::use_relate
{};
template <typename MultiPolygon1, typename MultiPolygon2>
struct covered_by<MultiPolygon1, MultiPolygon2, multi_polygon_tag, multi_polygon_tag>
: public detail::covered_by::use_relate
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_COVERED_BY_IMPLEMENTATION_HPP

View File

@@ -0,0 +1,255 @@
// 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, 2014, 2017, 2018.
// Modifications copyright (c) 2013-2018 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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_COVERED_BY_INTERFACE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_COVERED_BY_INTERFACE_HPP
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/algorithms/detail/within/interface.hpp>
#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/strategies/cartesian/point_in_box.hpp>
#include <boost/geometry/strategies/cartesian/box_in_box.hpp>
#include <boost/geometry/strategies/default_strategy.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template
<
typename Geometry1,
typename Geometry2,
typename Tag1 = typename tag<Geometry1>::type,
typename Tag2 = typename tag<Geometry2>::type
>
struct covered_by
: not_implemented<Tag1, Tag2>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
namespace resolve_strategy {
struct covered_by
{
template <typename Geometry1, typename Geometry2, typename Strategy>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
concepts::within::check<Geometry1, Geometry2, Strategy>();
concepts::check<Geometry1 const>();
concepts::check<Geometry2 const>();
assert_dimension_equal<Geometry1, Geometry2>();
return dispatch::covered_by<Geometry1, Geometry2>::apply(geometry1,
geometry2,
strategy);
}
template <typename Geometry1, typename Geometry2>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
default_strategy)
{
typedef typename strategy::covered_by::services::default_strategy
<
Geometry1,
Geometry2
>::type strategy_type;
return covered_by::apply(geometry1, geometry2, strategy_type());
}
};
} // namespace resolve_strategy
namespace resolve_variant {
template <typename Geometry1, typename Geometry2>
struct covered_by
{
template <typename Strategy>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
return resolve_strategy::covered_by
::apply(geometry1, geometry2, strategy);
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
struct covered_by<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
{
template <typename Strategy>
struct visitor: boost::static_visitor<bool>
{
Geometry2 const& m_geometry2;
Strategy const& m_strategy;
visitor(Geometry2 const& geometry2, Strategy const& strategy)
: m_geometry2(geometry2), m_strategy(strategy) {}
template <typename Geometry1>
bool operator()(Geometry1 const& geometry1) const
{
return covered_by<Geometry1, Geometry2>
::apply(geometry1, m_geometry2, m_strategy);
}
};
template <typename Strategy>
static inline bool
apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
return boost::apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1);
}
};
template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct covered_by<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
{
template <typename Strategy>
struct visitor: boost::static_visitor<bool>
{
Geometry1 const& m_geometry1;
Strategy const& m_strategy;
visitor(Geometry1 const& geometry1, Strategy const& strategy)
: m_geometry1(geometry1), m_strategy(strategy) {}
template <typename Geometry2>
bool operator()(Geometry2 const& geometry2) const
{
return covered_by<Geometry1, Geometry2>
::apply(m_geometry1, geometry2, m_strategy);
}
};
template <typename Strategy>
static inline bool
apply(Geometry1 const& geometry1,
boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2,
Strategy const& strategy)
{
return boost::apply_visitor(visitor<Strategy>(geometry1, strategy), geometry2);
}
};
template <
BOOST_VARIANT_ENUM_PARAMS(typename T1),
BOOST_VARIANT_ENUM_PARAMS(typename T2)
>
struct covered_by<
boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>,
boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>
>
{
template <typename Strategy>
struct visitor: boost::static_visitor<bool>
{
Strategy const& m_strategy;
visitor(Strategy const& strategy): m_strategy(strategy) {}
template <typename Geometry1, typename Geometry2>
bool operator()(Geometry1 const& geometry1,
Geometry2 const& geometry2) const
{
return covered_by<Geometry1, Geometry2>
::apply(geometry1, geometry2, m_strategy);
}
};
template <typename Strategy>
static inline bool
apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1,
boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2,
Strategy const& strategy)
{
return boost::apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2);
}
};
} // namespace resolve_variant
/*!
\brief \brief_check12{is inside or on border}
\ingroup covered_by
\details \details_check12{covered_by, is inside or on border}.
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\param geometry1 \param_geometry which might be inside or on the border of the second geometry
\param geometry2 \param_geometry which might cover the first geometry
\return true if geometry1 is inside of or on the border of geometry2,
else false
\note The default strategy is used for covered_by detection
\qbk{[include reference/algorithms/covered_by.qbk]}
*/
template<typename Geometry1, typename Geometry2>
inline bool covered_by(Geometry1 const& geometry1, Geometry2 const& geometry2)
{
return resolve_variant::covered_by<Geometry1, Geometry2>
::apply(geometry1, geometry2, default_strategy());
}
/*!
\brief \brief_check12{is inside or on border} \brief_strategy
\ingroup covered_by
\details \details_check12{covered_by, is inside or on border}, \brief_strategy. \details_strategy_reasons
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\param geometry1 \param_geometry which might be inside or on the border of the second geometry
\param geometry2 \param_geometry which might cover the first geometry
\param strategy strategy to be used
\return true if geometry1 is inside of or on the border of geometry2,
else false
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/covered_by.qbk]}
*/
template<typename Geometry1, typename Geometry2, typename Strategy>
inline bool covered_by(Geometry1 const& geometry1, Geometry2 const& geometry2,
Strategy const& strategy)
{
return resolve_variant::covered_by<Geometry1, Geometry2>
::apply(geometry1, geometry2, strategy);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_COVERED_BY_INTERFACE_HPP

View File

@@ -2,10 +2,11 @@
// Copyright (c) 2015 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2015.
// Modifications copyright (c) 2015 Oracle and/or its affiliates.
// This file was modified by Oracle on 2015, 2017.
// Modifications copyright (c) 2015-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// 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
@@ -17,14 +18,22 @@
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/select_coordinate_type.hpp>
#include <boost/geometry/util/normalize_spheroidal_coordinates.hpp>
#include <boost/mpl/assert.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
// TODO: remove
template <std::size_t Index, typename Point1, typename Point2>
inline int sign_of_difference(Point1 const& point1, Point2 const& point2)
{
@@ -37,6 +46,193 @@ inline int sign_of_difference(Point1 const& point1, Point2 const& point2)
}
template <typename Point, typename CSTag = typename cs_tag<Point>::type>
struct direction_code_impl
{
BOOST_MPL_ASSERT_MSG((false), NOT_IMPLEMENTED_FOR_THIS_CS, (CSTag));
};
template <typename Point>
struct direction_code_impl<Point, cartesian_tag>
{
template <typename Point1, typename Point2>
static inline int apply(Point1 const& segment_a, Point1 const& segment_b,
Point2 const& p)
{
typedef typename geometry::select_coordinate_type
<
Point1, Point2
>::type calc_t;
if ( (math::equals(geometry::get<0>(segment_b), geometry::get<0>(segment_a))
&& math::equals(geometry::get<1>(segment_b), geometry::get<1>(segment_a)))
|| (math::equals(geometry::get<0>(segment_b), geometry::get<0>(p))
&& math::equals(geometry::get<1>(segment_b), geometry::get<1>(p))) )
{
return 0;
}
calc_t x1 = geometry::get<0>(segment_b) - geometry::get<0>(segment_a);
calc_t y1 = geometry::get<1>(segment_b) - geometry::get<1>(segment_a);
calc_t x2 = geometry::get<0>(segment_b) - geometry::get<0>(p);
calc_t y2 = geometry::get<1>(segment_b) - geometry::get<1>(p);
calc_t ax = (std::min)(math::abs(x1), math::abs(x2));
calc_t ay = (std::min)(math::abs(y1), math::abs(y2));
int s1 = 0, s2 = 0;
if (ax >= ay)
{
s1 = x1 > 0 ? 1 : -1;
s2 = x2 > 0 ? 1 : -1;
}
else
{
s1 = y1 > 0 ? 1 : -1;
s2 = y2 > 0 ? 1 : -1;
}
return s1 == s2 ? -1 : 1;
}
};
template <typename Point>
struct direction_code_impl<Point, spherical_equatorial_tag>
{
template <typename Point1, typename Point2>
static inline int apply(Point1 const& segment_a, Point1 const& segment_b,
Point2 const& p)
{
typedef typename coordinate_type<Point1>::type coord1_t;
typedef typename coordinate_type<Point2>::type coord2_t;
typedef typename coordinate_system<Point1>::type::units units_t;
typedef typename coordinate_system<Point2>::type::units units2_t;
BOOST_MPL_ASSERT_MSG((boost::is_same<units_t, units2_t>::value),
NOT_IMPLEMENTED_FOR_DIFFERENT_UNITS,
(units_t, units2_t));
typedef typename geometry::select_coordinate_type <Point1, Point2>::type calc_t;
typedef math::detail::constants_on_spheroid<coord1_t, units_t> constants1;
typedef math::detail::constants_on_spheroid<coord2_t, units_t> constants2;
static coord1_t const pi_half1 = constants1::max_latitude();
static coord2_t const pi_half2 = constants2::max_latitude();
static calc_t const c0 = 0;
coord1_t const a0 = geometry::get<0>(segment_a);
coord1_t const a1 = geometry::get<1>(segment_a);
coord1_t const b0 = geometry::get<0>(segment_b);
coord1_t const b1 = geometry::get<1>(segment_b);
coord2_t const p0 = geometry::get<0>(p);
coord2_t const p1 = geometry::get<1>(p);
if ( (math::equals(b0, a0) && math::equals(b1, a1))
|| (math::equals(b0, p0) && math::equals(b1, p1)) )
{
return 0;
}
bool const is_a_pole = math::equals(pi_half1, math::abs(a1));
bool const is_b_pole = math::equals(pi_half1, math::abs(b1));
bool const is_p_pole = math::equals(pi_half2, math::abs(p1));
if ( is_b_pole && ((is_a_pole && math::sign(b1) == math::sign(a1))
|| (is_p_pole && math::sign(b1) == math::sign(p1))) )
{
return 0;
}
// NOTE: as opposed to the implementation for cartesian CS
// here point b is the origin
calc_t const dlon1 = math::longitude_distance_signed<units_t, calc_t>(b0, a0);
calc_t const dlon2 = math::longitude_distance_signed<units_t, calc_t>(b0, p0);
bool is_antilon1 = false, is_antilon2 = false;
calc_t const dlat1 = latitude_distance_signed<units_t, calc_t>(b1, a1, dlon1, is_antilon1);
calc_t const dlat2 = latitude_distance_signed<units_t, calc_t>(b1, p1, dlon2, is_antilon2);
calc_t mx = is_a_pole || is_b_pole || is_p_pole ?
c0 :
(std::min)(is_antilon1 ? c0 : math::abs(dlon1),
is_antilon2 ? c0 : math::abs(dlon2));
calc_t my = (std::min)(math::abs(dlat1),
math::abs(dlat2));
int s1 = 0, s2 = 0;
if (mx >= my)
{
s1 = dlon1 > 0 ? 1 : -1;
s2 = dlon2 > 0 ? 1 : -1;
}
else
{
s1 = dlat1 > 0 ? 1 : -1;
s2 = dlat2 > 0 ? 1 : -1;
}
return s1 == s2 ? -1 : 1;
}
template <typename Units, typename T>
static inline T latitude_distance_signed(T const& lat1, T const& lat2, T const& lon_ds, bool & is_antilon)
{
typedef math::detail::constants_on_spheroid<T, Units> constants;
static T const pi = constants::half_period();
static T const c0 = 0;
T res = lat2 - lat1;
is_antilon = math::equals(math::abs(lon_ds), pi);
if (is_antilon)
{
res = lat2 + lat1;
if (res >= c0)
res = pi - res;
else
res = -pi - res;
}
return res;
}
};
template <typename Point>
struct direction_code_impl<Point, spherical_polar_tag>
{
template <typename Point1, typename Point2>
static inline int apply(Point1 segment_a, Point1 segment_b,
Point2 p)
{
typedef math::detail::constants_on_spheroid
<
typename coordinate_type<Point1>::type,
typename coordinate_system<Point1>::type::units
> constants1;
typedef math::detail::constants_on_spheroid
<
typename coordinate_type<Point2>::type,
typename coordinate_system<Point2>::type::units
> constants2;
geometry::set<1>(segment_a,
constants1::max_latitude() - geometry::get<1>(segment_a));
geometry::set<1>(segment_b,
constants1::max_latitude() - geometry::get<1>(segment_b));
geometry::set<1>(p,
constants2::max_latitude() - geometry::get<1>(p));
return direction_code_impl
<
Point, spherical_equatorial_tag
>::apply(segment_a, segment_b, p);
}
};
template <typename Point>
struct direction_code_impl<Point, geographic_tag>
: direction_code_impl<Point, spherical_equatorial_tag>
{};
// Gives sense of direction for point p, collinear w.r.t. segment (a,b)
// Returns -1 if p goes backward w.r.t (a,b), so goes from b in direction of a
// Returns 1 if p goes forward, so extends (a,b)
@@ -44,28 +240,9 @@ inline int sign_of_difference(Point1 const& point1, Point2 const& point2)
// Note that it does not do any collinearity test, that should be done before
template <typename Point1, typename Point2>
inline int direction_code(Point1 const& segment_a, Point1 const& segment_b,
const Point2& p)
Point2 const& p)
{
// Suppose segment = (4 3,4 4) and p =(4 2)
// Then sign_a1 = 1 and sign_p1 = 1 -> goes backward -> return -1
int const sign_a0 = sign_of_difference<0>(segment_b, segment_a);
int const sign_a1 = sign_of_difference<1>(segment_b, segment_a);
if (sign_a0 == 0 && sign_a1 == 0)
{
return 0;
}
int const sign_p0 = sign_of_difference<0>(segment_b, p);
int const sign_p1 = sign_of_difference<1>(segment_b, p);
if (sign_p0 == 0 && sign_p1 == 0)
{
return 0;
}
return sign_a0 == sign_p0 && sign_a1 == sign_p1 ? -1 : 1;
return direction_code_impl<Point1>::apply(segment_a, segment_b, p);
}
@@ -73,7 +250,6 @@ inline int direction_code(Point1 const& segment_a, Point1 const& segment_b,
#endif //DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DIRECITON_CODE_HPP

View File

@@ -5,8 +5,8 @@
// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2013-2017.
// Modifications copyright (c) 2013-2017, Oracle and/or its affiliates.
// This file was modified by Oracle on 2013-2019.
// Modifications copyright (c) 2013-2019, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
@@ -28,6 +28,9 @@
#include <boost/geometry/algorithms/detail/point_on_border.hpp>
#include <boost/geometry/algorithms/detail/disjoint/linear_linear.hpp>
#include <boost/geometry/algorithms/detail/disjoint/segment_box.hpp>
#include <boost/geometry/iterators/segment_iterator.hpp>
namespace boost { namespace geometry
@@ -38,30 +41,15 @@ namespace boost { namespace geometry
namespace detail { namespace disjoint
{
template <typename Geometry, typename Tag = typename tag<Geometry>::type>
struct check_each_ring_for_within_call_covered_by
template <typename Geometry1, typename Geometry2, typename Strategy>
inline bool point_on_border_covered_by(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
/*!
\tparam Strategy point_in_geometry strategy
*/
template <typename Point, typename Strategy>
static inline bool apply(Point const& p, Geometry const& g, Strategy const& strategy)
{
return geometry::covered_by(p, g, strategy);
}
};
template <typename Geometry>
struct check_each_ring_for_within_call_covered_by<Geometry, box_tag>
{
template <typename Point, typename Strategy>
static inline bool apply(Point const& p, Geometry const& g, Strategy const& )
{
return geometry::covered_by(p, g);
}
};
typename geometry::point_type<Geometry1>::type pt;
return geometry::point_on_border(pt, geometry1)
&& geometry::covered_by(pt, geometry2, strategy);
}
/*!
\tparam Strategy point_in_geometry strategy
@@ -83,13 +71,8 @@ struct check_each_ring_for_within
template <typename Range>
inline void apply(Range const& range)
{
typename point_type<Range>::type pt;
not_disjoint = not_disjoint
|| ( geometry::point_on_border(pt, range)
&& check_each_ring_for_within_call_covered_by
<
Geometry
>::apply(pt, m_geometry, m_strategy) );
|| point_on_border_covered_by(range, m_geometry, m_strategy);
}
};
@@ -113,7 +96,7 @@ inline bool rings_containing(FirstGeometry const& geometry1,
template <typename Geometry1, typename Geometry2>
struct general_areal
struct areal_areal
{
/*!
\tparam Strategy relate (segments intersection) strategy
@@ -147,6 +130,56 @@ struct general_areal
};
template <typename Areal, typename Box>
struct areal_box
{
/*!
\tparam Strategy relate (segments intersection) strategy
*/
template <typename Strategy>
static inline bool apply(Areal const& areal,
Box const& box,
Strategy const& strategy)
{
if ( ! for_each_segment(geometry::segments_begin(areal),
geometry::segments_end(areal),
box,
strategy.get_disjoint_segment_box_strategy()) )
{
return false;
}
// If there is no intersection of any segment and box,
// the box might be located inside areal geometry
if ( point_on_border_covered_by(box, areal,
strategy.template get_point_in_geometry_strategy<Box, Areal>()) )
{
return false;
}
return true;
}
private:
template <typename SegIter, typename Strategy>
static inline bool for_each_segment(SegIter first,
SegIter last,
Box const& box,
Strategy const& strategy)
{
for ( ; first != last ; ++first)
{
if (! disjoint_segment_box::apply(*first, box, strategy))
{
return false;
}
}
return true;
}
};
}} // namespace detail::disjoint
#endif // DOXYGEN_NO_DETAIL
@@ -160,13 +193,13 @@ namespace dispatch
template <typename Areal1, typename Areal2>
struct disjoint<Areal1, Areal2, 2, areal_tag, areal_tag, false>
: detail::disjoint::general_areal<Areal1, Areal2>
: detail::disjoint::areal_areal<Areal1, Areal2>
{};
template <typename Areal, typename Box>
struct disjoint<Areal, Box, 2, areal_tag, box_tag, false>
: detail::disjoint::general_areal<Areal, Box>
: detail::disjoint::areal_box<Areal, Box>
{};

View File

@@ -5,8 +5,8 @@
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// Copyright (c) 2013-2015 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2013-2017.
// Modifications copyright (c) 2013-2017, Oracle and/or its affiliates.
// This file was modified by Oracle on 2013-2018.
// Modifications copyright (c) 2013-2018, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
@@ -23,130 +23,30 @@
#include <cstddef>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/dispatch/disjoint.hpp>
#include <boost/geometry/util/normalize_spheroidal_coordinates.hpp>
#include <boost/geometry/util/select_most_precise.hpp>
// For backward compatibility
#include <boost/geometry/strategies/cartesian/disjoint_box_box.hpp>
#include <boost/geometry/strategies/spherical/disjoint_box_box.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace disjoint
{
template
<
typename Box1, typename Box2,
std::size_t Dimension = 0,
std::size_t DimensionCount = dimension<Box1>::value,
typename CSTag = typename tag_cast
<
typename cs_tag<Box1>::type,
spherical_tag
>::type
>
struct box_box
{
template <typename Strategy>
static inline bool apply(Box1 const& box1, Box2 const& box2, Strategy const&)
{
return apply(box1, box2);
}
static inline bool apply(Box1 const& box1, Box2 const& box2)
{
if (get<max_corner, Dimension>(box1) < get<min_corner, Dimension>(box2))
{
return true;
}
if (get<min_corner, Dimension>(box1) > get<max_corner, Dimension>(box2))
{
return true;
}
return box_box
<
Box1, Box2,
Dimension + 1, DimensionCount
>::apply(box1, box2);
}
};
template <typename Box1, typename Box2, std::size_t DimensionCount, typename CSTag>
struct box_box<Box1, Box2, DimensionCount, DimensionCount, CSTag>
{
static inline bool apply(Box1 const& , Box2 const& )
{
return false;
}
};
template <typename Box1, typename Box2, std::size_t DimensionCount>
struct box_box<Box1, Box2, 0, DimensionCount, spherical_tag>
{
template <typename Strategy>
static inline bool apply(Box1 const& box1, Box2 const& box2, Strategy const&)
{
return apply(box1, box2);
}
static inline bool apply(Box1 const& box1, Box2 const& box2)
{
typedef typename geometry::select_most_precise
<
typename coordinate_type<Box1>::type,
typename coordinate_type<Box2>::type
>::type calc_t;
typedef typename coordinate_system<Box1>::type::units units_t;
typedef math::detail::constants_on_spheroid<calc_t, units_t> constants;
calc_t const b1_min = get<min_corner, 0>(box1);
calc_t const b1_max = get<max_corner, 0>(box1);
calc_t const b2_min = get<min_corner, 0>(box2);
calc_t const b2_max = get<max_corner, 0>(box2);
// min <= max <=> diff >= 0
calc_t const diff1 = b1_max - b1_min;
calc_t const diff2 = b2_max - b2_min;
// check the intersection if neither box cover the whole globe
if (diff1 < constants::period() && diff2 < constants::period())
{
// calculate positive longitude translation with b1_min as origin
calc_t const diff_min = math::longitude_distance_unsigned<units_t>(b1_min, b2_min);
calc_t const b2_min_transl = b1_min + diff_min; // always right of b1_min
if (b2_min_transl > b1_max // b2_min right of b1_max
&& b2_min_transl - constants::period() + diff2 < b1_min) // b2_max left of b1_min
{
return true;
}
}
return box_box
<
Box1, Box2,
1, DimensionCount
>::apply(box1, box2);
}
};
/*!
\brief Internal utility function to detect if boxes are disjoint
\note Is used from other algorithms, declared separately
to avoid circular references
*/
template <typename Box1, typename Box2>
inline bool disjoint_box_box(Box1 const& box1, Box2 const& box2)
template <typename Box1, typename Box2, typename Strategy>
inline bool disjoint_box_box(Box1 const& box1, Box2 const& box2, Strategy const&)
{
return box_box<Box1, Box2>::apply(box1, box2);
return Strategy::apply(box1, box2);
}
@@ -161,8 +61,13 @@ namespace dispatch
template <typename Box1, typename Box2, std::size_t DimensionCount>
struct disjoint<Box1, Box2, DimensionCount, box_tag, box_tag, false>
: detail::disjoint::box_box<Box1, Box2, 0, DimensionCount>
{};
{
template <typename Strategy>
static inline bool apply(Box1 const& box1, Box2 const& box2, Strategy const&)
{
return Strategy::apply(box1, box2);
}
};
} // namespace dispatch

View File

@@ -5,8 +5,8 @@
// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2013-2014.
// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates.
// This file was modified by Oracle on 2013-2017.
// Modifications copyright (c) 2013-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle

View File

@@ -5,8 +5,8 @@
// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2013-2017.
// Modifications copyright (c) 2013-2017, Oracle and/or its affiliates.
// This file was modified by Oracle on 2013-2018.
// Modifications copyright (c) 2013-2018, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
@@ -41,8 +41,9 @@
#include <boost/geometry/algorithms/detail/check_iterator_range.hpp>
#include <boost/geometry/algorithms/detail/point_on_border.hpp>
#include <boost/geometry/algorithms/detail/disjoint/multirange_geometry.hpp>
#include <boost/geometry/algorithms/detail/disjoint/linear_linear.hpp>
#include <boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.hpp>
#include <boost/geometry/algorithms/detail/disjoint/multirange_geometry.hpp>
#include <boost/geometry/algorithms/detail/disjoint/point_box.hpp>
#include <boost/geometry/algorithms/detail/disjoint/segment_box.hpp>

View File

@@ -93,18 +93,6 @@ struct assign_disjoint_policy
static bool const include_no_turn = true;
static bool const include_degenerate = true;
static bool const include_opposite = true;
// We don't assign extra info:
template
<
typename Info,
typename Point1,
typename Point2,
typename IntersectionInfo
>
static inline void apply(Info& , Point1 const& , Point2 const&,
IntersectionInfo const&)
{}
};

View File

@@ -1,7 +1,8 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014-2017, Oracle and/or its affiliates.
// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
// Copyright (c) 2014-2018, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -30,13 +31,16 @@
#include <boost/geometry/algorithms/detail/check_iterator_range.hpp>
#include <boost/geometry/algorithms/detail/partition.hpp>
#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
#include <boost/geometry/algorithms/detail/disjoint/multirange_geometry.hpp>
#include <boost/geometry/algorithms/detail/disjoint/point_box.hpp>
#include <boost/geometry/algorithms/detail/disjoint/point_point.hpp>
#include <boost/geometry/algorithms/detail/disjoint/point_geometry.hpp>
#include <boost/geometry/algorithms/detail/relate/less.hpp>
#include <boost/geometry/algorithms/dispatch/disjoint.hpp>
#include <boost/geometry/policies/compare.hpp>
namespace boost { namespace geometry
{
@@ -53,10 +57,10 @@ class multipoint_multipoint
private:
template <typename Iterator>
class unary_disjoint_predicate
: detail::relate::less
: geometry::less<>
{
private:
typedef detail::relate::less base_type;
typedef geometry::less<> base_type;
public:
unary_disjoint_predicate(Iterator first, Iterator last)
@@ -87,7 +91,7 @@ public:
std::vector<point1_type> points1(boost::begin(multipoint1),
boost::end(multipoint1));
std::sort(points1.begin(), points1.end(), detail::relate::less());
std::sort(points1.begin(), points1.end(), geometry::less<>());
typedef unary_disjoint_predicate
<
@@ -117,49 +121,49 @@ private:
}
};
// TODO: After adding non-cartesian Segment envelope to the library
// this policy should be modified to take envelope strategy.
template <typename EnvelopeStrategy>
struct expand_box_segment
{
explicit expand_box_segment(EnvelopeStrategy const& strategy)
: m_strategy(strategy)
{}
template <typename Box, typename Segment>
static inline void apply(Box& total, Segment const& segment)
inline void apply(Box& total, Segment const& segment) const
{
geometry::expand(total, geometry::return_envelope<Box>(segment));
geometry::expand(total,
geometry::return_envelope<Box>(segment, m_strategy));
}
EnvelopeStrategy const& m_strategy;
};
template <typename DisjointPointBoxStrategy>
struct overlaps_box_point
{
template <typename Box, typename Point>
static inline bool apply(Box const& box, Point const& point)
{
// The default strategy is enough in this case
typedef typename strategy::disjoint::services::default_strategy
<
Point, Box
>::type strategy_type;
return ! dispatch::disjoint<Point, Box>::apply(point, box, strategy_type());
return ! detail::disjoint::disjoint_point_box(point, box,
DisjointPointBoxStrategy());
}
};
// TODO: After implementing disjoint Segment/Box for non-cartesian geometries
// this strategy should be passed here.
// TODO: This Segment/Box strategy should somehow be derived from Point/Segment strategy
// which by default is winding containing CS-specific side strategy
// TODO: disjoint Segment/Box will be called in this case which may take
// quite long in non-cartesian CS. So we should consider passing range of bounding boxes
// of segments after calculating them once.
template <typename DisjointStrategy>
struct overlaps_box_segment
{
explicit overlaps_box_segment(DisjointStrategy const& strategy)
: m_strategy(strategy)
{}
template <typename Box, typename Segment>
static inline bool apply(Box const& box, Segment const& segment)
inline bool apply(Box const& box, Segment const& segment) const
{
typedef typename strategy::disjoint::services::default_strategy
<
Segment, Box
>::type strategy_type;
return ! dispatch::disjoint<Segment, Box>::apply(segment, box, strategy_type());
return ! dispatch::disjoint<Segment, Box>::apply(segment, box, m_strategy);
}
DisjointStrategy const& m_strategy;
};
template <typename PtSegStrategy>
@@ -172,13 +176,15 @@ private:
{}
template <typename Item1, typename Item2>
inline void apply(Item1 const& item1, Item2 const& item2)
inline bool apply(Item1 const& item1, Item2 const& item2)
{
if (! m_intersection_found
&& ! dispatch::disjoint<Item1, Item2>::apply(item1, item2, m_strategy))
{
m_intersection_found = true;
return false;
}
return true;
}
inline bool intersection_found() const { return m_intersection_found; }
@@ -219,12 +225,23 @@ public:
{
item_visitor_type<Strategy> visitor(strategy);
typedef typename Strategy::envelope_strategy_type envelope_strategy_type;
typedef typename Strategy::disjoint_strategy_type disjoint_strategy_type;
typedef typename Strategy::disjoint_point_box_strategy_type disjoint_pb_strategy_type;
// TODO: disjoint Segment/Box may be called in partition multiple times
// possibly for non-cartesian segments which could be slow. We should consider
// passing a range of bounding boxes of segments after calculating them once.
// Alternatively instead of a range of segments a range of Segment/Envelope pairs
// should be passed, where envelope would be lazily calculated when needed the first time
geometry::partition
<
geometry::model::box<typename point_type<MultiPoint>::type>
>::apply(multipoint, segment_range(linear), visitor,
expand_box_point(), overlaps_box_point(),
expand_box_segment(), overlaps_box_segment());
expand_box_point(),
overlaps_box_point<disjoint_pb_strategy_type>(),
expand_box_segment<envelope_strategy_type>(strategy.get_envelope_strategy()),
overlaps_box_segment<disjoint_strategy_type>(strategy.get_disjoint_strategy()));
return ! visitor.intersection_found();
}
@@ -237,6 +254,195 @@ public:
};
template <typename MultiPoint, typename SingleGeometry>
class multi_point_single_geometry
{
public:
template <typename Strategy>
static inline bool apply(MultiPoint const& multi_point,
SingleGeometry const& single_geometry,
Strategy const& strategy)
{
typedef typename Strategy::disjoint_point_box_strategy_type d_pb_strategy_type;
typedef typename point_type<MultiPoint>::type point1_type;
typedef typename point_type<SingleGeometry>::type point2_type;
typedef model::box<point2_type> box2_type;
box2_type box2;
geometry::envelope(single_geometry, box2, strategy.get_envelope_strategy());
geometry::detail::expand_by_epsilon(box2);
typedef typename boost::range_const_iterator<MultiPoint>::type iterator;
for ( iterator it = boost::begin(multi_point) ; it != boost::end(multi_point) ; ++it )
{
// The default strategy is enough for Point/Box
if (! detail::disjoint::disjoint_point_box(*it, box2, d_pb_strategy_type())
&& ! dispatch::disjoint<point1_type, SingleGeometry>::apply(*it, single_geometry, strategy))
{
return false;
}
}
return true;
}
template <typename Strategy>
static inline bool apply(SingleGeometry const& single_geometry, MultiPoint const& multi_point, Strategy const& strategy)
{
return apply(multi_point, single_geometry, strategy);
}
};
template <typename MultiPoint, typename MultiGeometry>
class multi_point_multi_geometry
{
private:
struct expand_box_point
{
template <typename Box, typename Point>
static inline void apply(Box& total, Point const& point)
{
geometry::expand(total, point);
}
};
struct expand_box_box_pair
{
template <typename Box, typename BoxPair>
inline void apply(Box& total, BoxPair const& box_pair) const
{
geometry::expand(total, box_pair.first);
}
};
template <typename DisjointPointBoxStrategy>
struct overlaps_box_point
{
template <typename Box, typename Point>
static inline bool apply(Box const& box, Point const& point)
{
// The default strategy is enough for Point/Box
return ! detail::disjoint::disjoint_point_box(point, box,
DisjointPointBoxStrategy());
}
};
template <typename DisjointBoxBoxStrategy>
struct overlaps_box_box_pair
{
template <typename Box, typename BoxPair>
inline bool apply(Box const& box, BoxPair const& box_pair) const
{
// The default strategy is enough for Box/Box
return ! detail::disjoint::disjoint_box_box(box_pair.first, box,
DisjointBoxBoxStrategy());
}
};
template <typename PtSegStrategy>
class item_visitor_type
{
public:
item_visitor_type(MultiGeometry const& multi_geometry,
PtSegStrategy const& strategy)
: m_intersection_found(false)
, m_multi_geometry(multi_geometry)
, m_strategy(strategy)
{}
template <typename Point, typename BoxPair>
inline bool apply(Point const& point, BoxPair const& box_pair)
{
typedef typename PtSegStrategy::disjoint_point_box_strategy_type d_pb_strategy_type;
typedef typename boost::range_value<MultiGeometry>::type single_type;
// The default strategy is enough for Point/Box
if (! m_intersection_found
&& ! detail::disjoint::disjoint_point_box(point, box_pair.first, d_pb_strategy_type())
&& ! dispatch::disjoint<Point, single_type>::apply(point, range::at(m_multi_geometry, box_pair.second), m_strategy))
{
m_intersection_found = true;
return false;
}
return true;
}
inline bool intersection_found() const { return m_intersection_found; }
private:
bool m_intersection_found;
MultiGeometry const& m_multi_geometry;
PtSegStrategy const& m_strategy;
};
// structs for partition -- end
public:
template <typename Strategy>
static inline bool apply(MultiPoint const& multi_point, MultiGeometry const& multi_geometry, Strategy const& strategy)
{
typedef typename point_type<MultiPoint>::type point1_type;
typedef typename point_type<MultiGeometry>::type point2_type;
typedef model::box<point1_type> box1_type;
typedef model::box<point2_type> box2_type;
typedef std::pair<box2_type, std::size_t> box_pair_type;
typename Strategy::envelope_strategy_type const
envelope_strategy = strategy.get_envelope_strategy();
std::size_t count2 = boost::size(multi_geometry);
std::vector<box_pair_type> boxes(count2);
for (std::size_t i = 0 ; i < count2 ; ++i)
{
geometry::envelope(range::at(multi_geometry, i), boxes[i].first, envelope_strategy);
geometry::detail::expand_by_epsilon(boxes[i].first);
boxes[i].second = i;
}
item_visitor_type<Strategy> visitor(multi_geometry, strategy);
typedef overlaps_box_point
<
typename Strategy::disjoint_point_box_strategy_type
> overlaps_box_point_type;
typedef overlaps_box_box_pair
<
typename Strategy::disjoint_box_box_strategy_type
> overlaps_box_box_pair_type;
geometry::partition
<
box1_type
>::apply(multi_point, boxes, visitor,
expand_box_point(),
overlaps_box_point_type(),
expand_box_box_pair(),
overlaps_box_box_pair_type());
return ! visitor.intersection_found();
}
template <typename Strategy>
static inline bool apply(MultiGeometry const& multi_geometry, MultiPoint const& multi_point, Strategy const& strategy)
{
return apply(multi_point, multi_geometry, strategy);
}
};
template <typename MultiPoint, typename Areal, typename Tag = typename tag<Areal>::type>
struct multipoint_areal
: multi_point_single_geometry<MultiPoint, Areal>
{};
template <typename MultiPoint, typename Areal>
struct multipoint_areal<MultiPoint, Areal, multi_polygon_tag>
: multi_point_multi_geometry<MultiPoint, Areal>
{};
}} // namespace detail::disjoint
#endif // DOXYGEN_NO_DETAIL
@@ -321,6 +527,22 @@ struct disjoint
{};
template <typename Areal, typename MultiPoint, std::size_t DimensionCount>
struct disjoint
<
Areal, MultiPoint, DimensionCount, areal_tag, multi_point_tag, false
> : detail::disjoint::multipoint_areal<MultiPoint, Areal>
{};
template <typename MultiPoint, typename Areal, std::size_t DimensionCount>
struct disjoint
<
MultiPoint, Areal, DimensionCount, multi_point_tag, areal_tag, false
> : detail::disjoint::multipoint_areal<MultiPoint, Areal>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH

View File

@@ -5,8 +5,8 @@
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// Copyright (c) 2013-2015 Adam Wulkiewicz, Lodz, Poland
// This file was modified by Oracle on 2013-2017.
// Modifications copyright (c) 2013-2017, Oracle and/or its affiliates.
// This file was modified by Oracle on 2013-2018.
// Modifications copyright (c) 2013-2018, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
@@ -41,16 +41,11 @@ namespace detail { namespace disjoint
/*!
\brief Internal utility function to detect if point/box are disjoint
*/
template <typename Point, typename Box>
inline bool disjoint_point_box(Point const& point, Box const& box)
template <typename Point, typename Box, typename Strategy>
inline bool disjoint_point_box(Point const& point, Box const& box, Strategy const& )
{
typedef typename strategy::disjoint::services::default_strategy
<
Point, Box
>::type strategy_type;
// ! covered_by(point, box)
return ! strategy_type::apply(point, box);
return ! Strategy::apply(point, box);
}

View File

@@ -5,8 +5,8 @@
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// Copyright (c) 2013-2015 Adam Wulkiewicz, Lodz, Poland
// This file was modified by Oracle on 2013, 2014, 2015, 2017.
// Modifications copyright (c) 2013-2017, Oracle and/or its affiliates.
// This file was modified by Oracle on 2013, 2014, 2015, 2017, 2018.
// Modifications copyright (c) 2013-2018, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
@@ -23,29 +23,15 @@
#include <cstddef>
#include <boost/type_traits/is_same.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/radian_access.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/core/coordinate_system.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/select_most_precise.hpp>
#include <boost/geometry/strategies/strategy_transform.hpp>
#include <boost/geometry/geometries/helper_geometry.hpp>
#include <boost/geometry/algorithms/transform.hpp>
#include <boost/geometry/algorithms/detail/normalize.hpp>
#include <boost/geometry/algorithms/dispatch/disjoint.hpp>
// For backward compatibility
#include <boost/geometry/strategies/disjoint.hpp>
#include <boost/geometry/strategies/cartesian/point_in_point.hpp>
#include <boost/geometry/strategies/spherical/point_in_point.hpp>
namespace boost { namespace geometry
{
@@ -56,169 +42,15 @@ namespace detail { namespace disjoint
{
template <std::size_t Dimension, std::size_t DimensionCount>
struct point_point_generic
{
template <typename Point1, typename Point2, typename Strategy>
static inline bool apply(Point1 const& p1, Point2 const& p2, Strategy const& )
{
return apply(p1, p2);
}
template <typename Point1, typename Point2>
static inline bool apply(Point1 const& p1, Point2 const& p2)
{
if (! geometry::math::equals(get<Dimension>(p1), get<Dimension>(p2)))
{
return true;
}
return
point_point_generic<Dimension + 1, DimensionCount>::apply(p1, p2);
}
};
template <std::size_t DimensionCount>
struct point_point_generic<DimensionCount, DimensionCount>
{
template <typename Point1, typename Point2>
static inline bool apply(Point1 const&, Point2 const& )
{
return false;
}
};
class point_point_on_spheroid
{
private:
template <typename Point1, typename Point2, bool SameUnits>
struct are_same_points
{
static inline bool apply(Point1 const& point1, Point2 const& point2)
{
typedef typename helper_geometry<Point1>::type helper_point_type1;
typedef typename helper_geometry<Point2>::type helper_point_type2;
helper_point_type1 point1_normalized
= return_normalized<helper_point_type1>(point1);
helper_point_type2 point2_normalized
= return_normalized<helper_point_type2>(point2);
return point_point_generic
<
0, dimension<Point1>::value
>::apply(point1_normalized, point2_normalized);
}
};
template <typename Point1, typename Point2>
struct are_same_points<Point1, Point2, false> // points have different units
{
static inline bool apply(Point1 const& point1, Point2 const& point2)
{
typedef typename geometry::select_most_precise
<
typename fp_coordinate_type<Point1>::type,
typename fp_coordinate_type<Point2>::type
>::type calculation_type;
typename helper_geometry
<
Point1, calculation_type, radian
>::type helper_point1, helper_point2;
Point1 point1_normalized = return_normalized<Point1>(point1);
Point2 point2_normalized = return_normalized<Point2>(point2);
geometry::transform(point1_normalized, helper_point1);
geometry::transform(point2_normalized, helper_point2);
return point_point_generic
<
0, dimension<Point1>::value
>::apply(helper_point1, helper_point2);
}
};
public:
template <typename Point1, typename Point2, typename Strategy>
static inline bool apply(Point1 const& point1, Point2 const& point2, Strategy const& )
{
return apply(point1, point2);
}
template <typename Point1, typename Point2>
static inline bool apply(Point1 const& point1, Point2 const& point2)
{
return are_same_points
<
Point1,
Point2,
boost::is_same
<
typename coordinate_system<Point1>::type::units,
typename coordinate_system<Point2>::type::units
>::value
>::apply(point1, point2);
}
};
template
<
typename Point1, typename Point2,
std::size_t Dimension, std::size_t DimensionCount,
typename CSTag1 = typename cs_tag<Point1>::type,
typename CSTag2 = CSTag1
>
struct point_point
: point_point<Point1, Point2, Dimension, DimensionCount, cartesian_tag>
{};
template
<
typename Point1, typename Point2,
std::size_t Dimension, std::size_t DimensionCount
>
struct point_point
<
Point1, Point2, Dimension, DimensionCount, spherical_equatorial_tag
> : point_point_on_spheroid
{};
template
<
typename Point1, typename Point2,
std::size_t Dimension, std::size_t DimensionCount
>
struct point_point
<
Point1, Point2, Dimension, DimensionCount, geographic_tag
> : point_point_on_spheroid
{};
template
<
typename Point1, typename Point2,
std::size_t Dimension, std::size_t DimensionCount
>
struct point_point<Point1, Point2, Dimension, DimensionCount, cartesian_tag>
: point_point_generic<Dimension, DimensionCount>
{};
/*!
\brief Internal utility function to detect of points are disjoint
\note To avoid circular references
*/
template <typename Point1, typename Point2>
inline bool disjoint_point_point(Point1 const& point1, Point2 const& point2)
template <typename Point1, typename Point2, typename Strategy>
inline bool disjoint_point_point(Point1 const& point1, Point2 const& point2,
Strategy const& )
{
return point_point
<
Point1, Point2,
0, dimension<Point1>::type::value
>::apply(point1, point2);
return ! Strategy::apply(point1, point2);
}
@@ -226,8 +58,6 @@ inline bool disjoint_point_point(Point1 const& point1, Point2 const& point2)
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
@@ -235,8 +65,14 @@ namespace dispatch
template <typename Point1, typename Point2, std::size_t DimensionCount>
struct disjoint<Point1, Point2, DimensionCount, point_tag, point_tag, false>
: detail::disjoint::point_point<Point1, Point2, 0, DimensionCount>
{};
{
template <typename Strategy>
static inline bool apply(Point1 const& point1, Point2 const& point2,
Strategy const& )
{
return ! Strategy::apply(point1, point2);
}
};
} // namespace dispatch

View File

@@ -5,11 +5,12 @@
// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2013-2017.
// Modifications copyright (c) 2013-2017, Oracle and/or its affiliates.
// This file was modified by Oracle on 2013-2019.
// Modifications copyright (c) 2013-2019, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -24,9 +25,22 @@
#include <cstddef>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/radian_access.hpp>
#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp>
#include <boost/geometry/algorithms/detail/disjoint/point_box.hpp>
#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
#include <boost/geometry/algorithms/detail/envelope/segment.hpp>
#include <boost/geometry/algorithms/detail/normalize.hpp>
#include <boost/geometry/algorithms/dispatch/disjoint.hpp>
#include <boost/geometry/algorithms/envelope.hpp>
#include <boost/geometry/formulas/vertex_longitude.hpp>
#include <boost/geometry/geometries/box.hpp>
// Temporary, for envelope_segment_impl
#include <boost/geometry/strategies/spherical/envelope_segment.hpp>
namespace boost { namespace geometry
{
@@ -36,10 +50,202 @@ namespace boost { namespace geometry
namespace detail { namespace disjoint
{
template <typename CS_Tag>
struct disjoint_segment_box_sphere_or_spheroid
{
struct disjoint_info
{
enum type
{
intersect,
disjoint_no_vertex,
disjoint_vertex
};
disjoint_info(type t) : m_(t){}
operator type () const {return m_;}
type m_;
private :
//prevent automatic conversion for any other built-in types
template <typename T>
operator T () const;
};
template
<
typename Segment, typename Box,
typename AzimuthStrategy,
typename NormalizeStrategy,
typename DisjointPointBoxStrategy,
typename DisjointBoxBoxStrategy
>
static inline bool apply(Segment const& segment,
Box const& box,
AzimuthStrategy const& azimuth_strategy,
NormalizeStrategy const& normalize_strategy,
DisjointPointBoxStrategy const& disjoint_point_box_strategy,
DisjointBoxBoxStrategy const& disjoint_box_box_strategy)
{
typedef typename point_type<Segment>::type segment_point;
segment_point vertex;
return apply(segment, box, vertex,
azimuth_strategy,
normalize_strategy,
disjoint_point_box_strategy,
disjoint_box_box_strategy) != disjoint_info::intersect;
}
template
<
typename Segment, typename Box,
typename P,
typename AzimuthStrategy,
typename NormalizeStrategy,
typename DisjointPointBoxStrategy,
typename DisjointBoxBoxStrategy
>
static inline disjoint_info apply(Segment const& segment,
Box const& box,
P& vertex,
AzimuthStrategy const& azimuth_strategy,
NormalizeStrategy const& ,
DisjointPointBoxStrategy const& disjoint_point_box_strategy,
DisjointBoxBoxStrategy const& disjoint_box_box_strategy)
{
assert_dimension_equal<Segment, Box>();
typedef typename point_type<Segment>::type segment_point_type;
segment_point_type p0, p1;
geometry::detail::assign_point_from_index<0>(segment, p0);
geometry::detail::assign_point_from_index<1>(segment, p1);
//vertex not computed here
disjoint_info disjoint_return_value = disjoint_info::disjoint_no_vertex;
// Simplest cases first
// Case 1: if box contains one of segment's endpoints then they are not disjoint
if ( ! disjoint_point_box(p0, box, disjoint_point_box_strategy)
|| ! disjoint_point_box(p1, box, disjoint_point_box_strategy) )
{
return disjoint_info::intersect;
}
// Case 2: disjoint if bounding boxes are disjoint
typedef typename coordinate_type<segment_point_type>::type CT;
segment_point_type p0_normalized;
NormalizeStrategy::apply(p0, p0_normalized);
segment_point_type p1_normalized;
NormalizeStrategy::apply(p1, p1_normalized);
CT lon1 = geometry::get_as_radian<0>(p0_normalized);
CT lat1 = geometry::get_as_radian<1>(p0_normalized);
CT lon2 = geometry::get_as_radian<0>(p1_normalized);
CT lat2 = geometry::get_as_radian<1>(p1_normalized);
if (lon1 > lon2)
{
std::swap(lon1, lon2);
std::swap(lat1, lat2);
}
geometry::model::box<segment_point_type> box_seg;
strategy::envelope::detail::envelope_segment_impl
<
CS_Tag
>::template apply<geometry::radian>(lon1, lat1,
lon2, lat2,
box_seg,
azimuth_strategy);
if (disjoint_box_box(box, box_seg, disjoint_box_box_strategy))
{
return disjoint_return_value;
}
// Case 3: test intersection by comparing angles
CT alp1, a_b0, a_b1, a_b2, a_b3;
CT b_lon_min = geometry::get_as_radian<geometry::min_corner, 0>(box);
CT b_lat_min = geometry::get_as_radian<geometry::min_corner, 1>(box);
CT b_lon_max = geometry::get_as_radian<geometry::max_corner, 0>(box);
CT b_lat_max = geometry::get_as_radian<geometry::max_corner, 1>(box);
azimuth_strategy.apply(lon1, lat1, lon2, lat2, alp1);
azimuth_strategy.apply(lon1, lat1, b_lon_min, b_lat_min, a_b0);
azimuth_strategy.apply(lon1, lat1, b_lon_max, b_lat_min, a_b1);
azimuth_strategy.apply(lon1, lat1, b_lon_min, b_lat_max, a_b2);
azimuth_strategy.apply(lon1, lat1, b_lon_max, b_lat_max, a_b3);
bool b0 = formula::azimuth_side_value(alp1, a_b0) > 0;
bool b1 = formula::azimuth_side_value(alp1, a_b1) > 0;
bool b2 = formula::azimuth_side_value(alp1, a_b2) > 0;
bool b3 = formula::azimuth_side_value(alp1, a_b3) > 0;
if (!(b0 && b1 && b2 && b3) && (b0 || b1 || b2 || b3))
{
return disjoint_info::intersect;
}
// Case 4: The only intersection case not covered above is when all four
// points of the box are above (below) the segment in northern (southern)
// hemisphere. Then we have to compute the vertex of the segment
CT vertex_lat;
CT lat_sum = lat1 + lat2;
if ((lat1 < b_lat_min && lat_sum > CT(0))
|| (lat1 > b_lat_max && lat_sum < CT(0)))
{
CT b_lat_below; //latitude of box closest to equator
if (lat_sum > CT(0))
{
vertex_lat = geometry::get_as_radian<geometry::max_corner, 1>(box_seg);
b_lat_below = b_lat_min;
} else {
vertex_lat = geometry::get_as_radian<geometry::min_corner, 1>(box_seg);
b_lat_below = b_lat_max;
}
//optimization TODO: computing the spherical longitude should suffice for
// the majority of cases
CT vertex_lon = geometry::formula::vertex_longitude<CT, CS_Tag>
::apply(lon1, lat1,
lon2, lat2,
vertex_lat,
alp1,
azimuth_strategy);
geometry::set_from_radian<0>(vertex, vertex_lon);
geometry::set_from_radian<1>(vertex, vertex_lat);
disjoint_return_value = disjoint_info::disjoint_vertex; //vertex_computed
// Check if the vertex point is within the band defined by the
// minimum and maximum longitude of the box; if yes, then return
// false if the point is above the min latitude of the box; return
// true in all other cases
if (vertex_lon >= b_lon_min && vertex_lon <= b_lon_max
&& std::abs(vertex_lat) > std::abs(b_lat_below))
{
return disjoint_info::intersect;
}
}
return disjoint_return_value;
}
};
struct disjoint_segment_box
{
template <typename Segment, typename Box, typename Strategy>
static inline bool apply(Segment const& segment, Box const& box, Strategy const& strategy)
static inline bool apply(Segment const& segment,
Box const& box,
Strategy const& strategy)
{
return strategy.apply(segment, box);
}
@@ -56,7 +262,7 @@ namespace dispatch
template <typename Segment, typename Box, std::size_t DimensionCount>
struct disjoint<Segment, Box, DimensionCount, segment_tag, box_tag, false>
: detail::disjoint::disjoint_segment_box
: detail::disjoint::disjoint_segment_box
{};

View File

@@ -110,6 +110,26 @@ struct default_strategy<Box1, Box2, box_tag, box_tag, false>
>
{};
template <typename Linear, typename Box>
struct default_strategy<Linear, Box, segment_tag, box_tag, false>
: strategy::distance::services::default_strategy
<
segment_tag, box_tag,
typename point_type<Linear>::type,
typename point_type<Box>::type
>
{};
template <typename Linear, typename Box>
struct default_strategy<Linear, Box, linear_tag, box_tag, false>
: strategy::distance::services::default_strategy
<
segment_tag, box_tag,
typename point_type<Linear>::type,
typename point_type<Box>::type
>
{};
// Helper metafunction for default point-segment strategy retrieval

View File

@@ -5,9 +5,10 @@
// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2014.
// Modifications copyright (c) 2014, Oracle and/or its affiliates.
// This file was modified by Oracle on 2014, 2018.
// Modifications copyright (c) 2014-2018, Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
@@ -25,6 +26,7 @@
#include <boost/geometry/algorithms/detail/distance/multipoint_to_geometry.hpp>
#include <boost/geometry/algorithms/detail/distance/linear_to_linear.hpp>
#include <boost/geometry/algorithms/detail/distance/linear_or_areal_to_areal.hpp>
#include <boost/geometry/algorithms/detail/distance/linear_to_box.hpp>
#include <boost/geometry/algorithms/detail/distance/geometry_to_segment_or_box.hpp>
#include <boost/geometry/algorithms/detail/distance/segment_to_segment.hpp>
#include <boost/geometry/algorithms/detail/distance/segment_to_box.hpp>

View File

@@ -6,10 +6,11 @@
// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
// Copyright (c) 2014 Samuel Debionne, Grenoble, France.
// This file was modified by Oracle on 2014.
// Modifications copyright (c) 2014, Oracle and/or its affiliates.
// This file was modified by Oracle on 2014, 2018.
// Modifications copyright (c) 2014-2018, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -94,9 +95,10 @@ struct distance
namespace resolve_strategy
{
template <typename Strategy>
struct distance
{
template <typename Geometry1, typename Geometry2, typename Strategy>
template <typename Geometry1, typename Geometry2>
static inline typename distance_result<Geometry1, Geometry2, Strategy>::type
apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
@@ -107,7 +109,11 @@ struct distance
Geometry1, Geometry2, Strategy
>::apply(geometry1, geometry2, strategy);
}
};
template <>
struct distance<default_strategy>
{
template <typename Geometry1, typename Geometry2>
static inline
typename distance_result<Geometry1, Geometry2, default_strategy>::type
@@ -143,8 +149,10 @@ struct distance
Geometry2 const& geometry2,
Strategy const& strategy)
{
return
resolve_strategy::distance::apply(geometry1, geometry2, strategy);
return resolve_strategy::distance
<
Strategy
>::apply(geometry1, geometry2, strategy);
}
};
@@ -320,10 +328,10 @@ struct distance
/*!
\brief \brief_calc2{distance} \brief_strategy
\brief Calculate the distance between two geometries \brief_strategy
\ingroup distance
\details
\details \details_calc{area}. \brief_strategy. \details_strategy_reasons
\details The free function distance calculates the distance between two geometries \brief_strategy. \details_strategy_reasons
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
@@ -376,9 +384,10 @@ distance(Geometry1 const& geometry1,
/*!
\brief \brief_calc2{distance}
\brief Calculate the distance between two geometries.
\ingroup distance
\details The default strategy is used, corresponding to the coordinate system of the geometries
\details The free function distance calculates the distance between two geometries. \details_default_strategy
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\param geometry1 \param_geometry

View File

@@ -18,7 +18,6 @@
#include <boost/geometry/algorithms/detail/distance/linear_to_linear.hpp>
namespace boost { namespace geometry
{
@@ -61,7 +60,6 @@ struct linear_to_areal
}
};
template <typename Areal1, typename Areal2, typename Strategy>
struct areal_to_areal
{
@@ -110,7 +108,6 @@ struct distance
>
{};
template <typename Areal, typename Linear, typename Strategy>
struct distance
<

View File

@@ -0,0 +1,123 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2018, Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_LINEAR_TO_BOX_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_LINEAR_TO_BOX_HPP
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/algorithms/intersects.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace distance
{
template <typename Linear, typename Box, typename Strategy>
struct linear_to_box
{
typedef typename strategy::distance::services::return_type
<
Strategy,
typename point_type<Linear>::type,
typename point_type<Box>::type
>::type return_type;
template <typename Iterator>
static inline return_type apply(Box const& box,
Iterator begin,
Iterator end,
Strategy const& strategy)
{
bool first = true;
return_type d_min(0);
for (Iterator it = begin; it != end; ++it, first = false)
{
typedef typename std::iterator_traits<Iterator>::value_type
Segment;
return_type d = dispatch::distance<Segment, Box, Strategy>
::apply(*it, box, strategy);
if ( first || d < d_min )
{
d_min = d;
}
}
return d_min;
}
static inline return_type apply(Linear const& linear,
Box const& box,
Strategy const& strategy)
{
if ( geometry::intersects(linear, box) )
{
return 0;
}
return apply(box,
geometry::segments_begin(linear),
geometry::segments_end(linear),
strategy);
}
static inline return_type apply(Box const& box,
Linear const& linear,
Strategy const& strategy)
{
return apply(linear, box, strategy);
}
};
}} // namespace detail::distance
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Linear, typename Box, typename Strategy>
struct distance
<
Linear, Box, Strategy,
linear_tag, box_tag,
strategy_tag_distance_segment_box, false
>
: detail::distance::linear_to_box
<
Linear, Box, Strategy
>
{};
template <typename Areal, typename Box, typename Strategy>
struct distance
<
Areal, Box, Strategy,
areal_tag, box_tag,
strategy_tag_distance_segment_box, false
>
: detail::distance::linear_to_box
<
Areal, Box, Strategy
>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_LINEAR_TO_BOX_HPP

View File

@@ -193,6 +193,7 @@ struct distance
>
{};
template <typename MultiPoint, typename Linear, typename Strategy>
struct distance
<

View File

@@ -5,10 +5,11 @@
// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2014.
// Modifications copyright (c) 2014, Oracle and/or its affiliates.
// This file was modified by Oracle on 2014, 2019.
// Modifications copyright (c) 2014-2019, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -39,13 +40,12 @@
#include <boost/geometry/strategies/tags.hpp>
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/algorithms/covered_by.hpp>
#include <boost/geometry/algorithms/within.hpp>
#include <boost/geometry/algorithms/detail/closest_feature/geometry_to_range.hpp>
#include <boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp>
#include <boost/geometry/algorithms/detail/distance/is_comparable.hpp>
#include <boost/geometry/algorithms/detail/distance/iterator_selector.hpp>
#include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp>
#include <boost/geometry/algorithms/dispatch/distance.hpp>
@@ -160,7 +160,8 @@ struct point_to_ring
Ring const& ring,
Strategy const& strategy)
{
if (geometry::within(point, ring))
// TODO: pass strategy
if (within::within_point_geometry(point, ring))
{
return return_type(0);
}
@@ -204,7 +205,8 @@ private:
{
for (InteriorRingIterator it = first; it != last; ++it)
{
if (geometry::within(point, *it))
// TODO: pass strategy
if (within::within_point_geometry(point, *it))
{
// the point is inside a polygon hole, so its distance
// to the polygon its distance to the polygon's
@@ -233,7 +235,8 @@ public:
Polygon const& polygon,
Strategy const& strategy)
{
if (!geometry::covered_by(point, exterior_ring(polygon)))
// TODO: pass strategy
if (! within::covered_by_point_geometry(point, exterior_ring(polygon)))
{
// the point is outside the exterior ring, so its distance
// to the polygon is its distance to the polygon's exterior ring
@@ -330,7 +333,8 @@ struct point_to_multigeometry<Point, MultiPolygon, Strategy, true>
MultiPolygon const& multipolygon,
Strategy const& strategy)
{
if (geometry::covered_by(point, multipolygon))
// TODO: pass strategy
if (within::covered_by_point_geometry(point, multipolygon))
{
return 0;
}
@@ -391,7 +395,7 @@ struct distance
template <typename Point, typename Polygon, typename Strategy>
struct distance
<
Point, Polygon, Strategy, point_tag, polygon_tag,
Point, Polygon, Strategy, point_tag, polygon_tag,
strategy_tag_distance_point_segment, false
> : detail::distance::point_to_polygon
<

View File

@@ -1,8 +1,10 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014, Oracle and/or its affiliates.
// Copyright (c) 2014-2019 Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
@@ -27,26 +29,26 @@
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/util/calculation_type.hpp>
#include <boost/geometry/util/condition.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/strategies/tags.hpp>
#include <boost/geometry/algorithms/detail/assign_box_corners.hpp>
#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp>
#include <boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp>
#include <boost/geometry/algorithms/detail/disjoint/segment_box.hpp>
#include <boost/geometry/algorithms/detail/distance/default_strategies.hpp>
#include <boost/geometry/algorithms/detail/distance/is_comparable.hpp>
#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
#include <boost/geometry/algorithms/dispatch/distance.hpp>
#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/policies/compare.hpp>
#include <boost/geometry/algorithms/equals.hpp>
#include <boost/geometry/algorithms/intersects.hpp>
#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/algorithms/detail/assign_box_corners.hpp>
#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp>
#include <boost/geometry/algorithms/detail/distance/default_strategies.hpp>
#include <boost/geometry/algorithms/detail/distance/is_comparable.hpp>
#include <boost/geometry/algorithms/dispatch/distance.hpp>
#include <boost/geometry/util/calculation_type.hpp>
#include <boost/geometry/util/condition.hpp>
#include <boost/geometry/util/has_nan_coordinate.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/strategies/disjoint.hpp>
#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/strategies/tags.hpp>
namespace boost { namespace geometry
@@ -58,6 +60,20 @@ namespace detail { namespace distance
{
// TODO: Take strategy
template <typename Segment, typename Box>
inline bool intersects_segment_box(Segment const& segment, Box const& box)
{
typedef typename strategy::disjoint::services::default_strategy
<
Segment, Box
>::type strategy_type;
return ! detail::disjoint::disjoint_segment_box::apply(segment, box,
strategy_type());
}
template
<
typename Segment,
@@ -73,7 +89,7 @@ private:
typedef typename strategy::distance::services::comparable_type
<
Strategy
typename Strategy::distance_ps_strategy::type
>::type comparable_strategy;
typedef detail::closest_feature::point_to_point_range
@@ -100,7 +116,7 @@ public:
Strategy const& strategy,
bool check_intersection = true)
{
if (check_intersection && geometry::intersects(segment, box))
if (check_intersection && intersects_segment_box(segment, box))
{
return 0;
}
@@ -108,8 +124,8 @@ public:
comparable_strategy cstrategy =
strategy::distance::services::get_comparable
<
Strategy
>::apply(strategy);
typename Strategy::distance_ps_strategy::type
>::apply(strategy.get_distance_ps_strategy());
// get segment points
segment_point p[2];
@@ -159,12 +175,12 @@ public:
if (imin < 4)
{
return strategy.apply(box_points[imin], p[0], p[1]);
return strategy.get_distance_ps_strategy().apply(box_points[imin], p[0], p[1]);
}
else
{
unsigned int bimin = imin - 4;
return strategy.apply(p[bimin],
return strategy.get_distance_ps_strategy().apply(p[bimin],
*bit_min[bimin].first,
*bit_min[bimin].second);
}
@@ -215,7 +231,7 @@ public:
Strategy const& strategy,
bool check_intersection = true)
{
if (check_intersection && geometry::intersects(segment, box))
if (check_intersection && intersects_segment_box(segment, box))
{
return 0;
}
@@ -280,8 +296,7 @@ template
typename ReturnType,
typename SegmentPoint,
typename BoxPoint,
typename PPStrategy,
typename PSStrategy
typename SBStrategy
>
class segment_to_box_2D
{
@@ -340,10 +355,9 @@ private:
SegmentPoint const& p1,
BoxPoint const& bottom_right,
BoxPoint const& top_right,
PPStrategy const& pp_strategy,
PSStrategy const& ps_strategy)
SBStrategy const& sb_strategy)
{
boost::ignore_unused(pp_strategy, ps_strategy);
boost::ignore_unused(sb_strategy);
// the implementation below is written for non-negative slope
// segments
@@ -355,22 +369,29 @@ private:
LessEqual less_equal;
if (less_equal(geometry::get<1>(top_right), geometry::get<1>(p0)))
typename SBStrategy::distance_ps_strategy::type ps_strategy =
sb_strategy.get_distance_ps_strategy();
if (less_equal(geometry::get<1>(bottom_right), geometry::get<1>(p0)))
{
// closest box point is the top-right corner
return cast::apply(pp_strategy.apply(p0, top_right));
}
else if (less_equal(geometry::get<1>(bottom_right),
geometry::get<1>(p0)))
{
// distance is realized between p0 and right-most
// segment of box
ReturnType diff = cast::apply(geometry::get<0>(p0))
- cast::apply(geometry::get<0>(bottom_right));
return strategy::distance::services::result_from_distance
<
PSStrategy, BoxPoint, SegmentPoint
>::apply(ps_strategy, math::abs(diff));
//if p0 is in box's band
if (less_equal(geometry::get<1>(p0), geometry::get<1>(top_right)))
{
// segment & crosses band (TODO:merge with box-box dist)
if (math::equals(geometry::get<0>(p0), geometry::get<0>(p1)))
{
SegmentPoint high = geometry::get<1>(p1) > geometry::get<1>(p0) ? p1 : p0;
if (less_equal(geometry::get<1>(high), geometry::get<1>(top_right)))
{
return cast::apply(ps_strategy.apply(high, bottom_right, top_right));
}
return cast::apply(ps_strategy.apply(top_right, p0, p1));
}
return cast::apply(ps_strategy.apply(p0, bottom_right, top_right));
}
// distance is realized between the top-right
// corner of the box and the segment
return cast::apply(ps_strategy.apply(top_right, p0, p1));
}
else
{
@@ -381,45 +402,55 @@ private:
}
};
// it is assumed here that p0 lies above the box (so the
// entire segment lies above the box)
template <typename LessEqual>
struct above_of_box
{
static inline ReturnType apply(SegmentPoint const& p0,
SegmentPoint const& p1,
BoxPoint const& top_left,
PSStrategy const& ps_strategy)
SBStrategy const& sb_strategy)
{
boost::ignore_unused(ps_strategy);
// the segment lies above the box
boost::ignore_unused(sb_strategy);
return apply(p0, p1, p0, top_left, sb_strategy);
}
static inline ReturnType apply(SegmentPoint const& p0,
SegmentPoint const& p1,
SegmentPoint const& p_max,
BoxPoint const& top_left,
SBStrategy const& sb_strategy)
{
boost::ignore_unused(sb_strategy);
typedef cast_to_result<ReturnType> cast;
LessEqual less_equal;
// p0 is above the upper segment of the box
// (and inside its band)
if (less_equal(geometry::get<0>(top_left), geometry::get<0>(p0)))
// p0 is above the upper segment of the box (and inside its band)
// then compute the vertical (i.e. meridian for spherical) distance
if (less_equal(geometry::get<0>(top_left), geometry::get<0>(p_max)))
{
ReturnType diff = cast::apply(geometry::get<1>(p0))
- cast::apply(geometry::get<1>(top_left));
ReturnType diff =
sb_strategy.get_distance_ps_strategy().vertical_or_meridian(
geometry::get_as_radian<1>(p_max),
geometry::get_as_radian<1>(top_left));
return strategy::distance::services::result_from_distance
<
PSStrategy, SegmentPoint, BoxPoint
>::apply(ps_strategy, math::abs(diff));
SBStrategy, SegmentPoint, BoxPoint
>::apply(sb_strategy, math::abs(diff));
}
// p0 is to the left of the box, but p1 is above the box
// in this case the distance is realized between the
// top-left corner of the box and the segment
return cast::apply(ps_strategy.apply(top_left, p0, p1));
return cast::apply(sb_strategy.get_distance_ps_strategy().
apply(top_left, p0, p1));
}
};
template <typename LessEqual>
struct check_right_left_of_box
{
@@ -429,8 +460,7 @@ private:
BoxPoint const& top_right,
BoxPoint const& bottom_left,
BoxPoint const& bottom_right,
PPStrategy const& pp_strategy,
PSStrategy const& ps_strategy,
SBStrategy const& sb_strategy,
ReturnType& result)
{
// p0 lies to the right of the box
@@ -440,7 +470,7 @@ private:
<
LessEqual
>::apply(p0, p1, bottom_right, top_right,
pp_strategy, ps_strategy);
sb_strategy);
return true;
}
@@ -451,7 +481,7 @@ private:
<
typename other_compare<LessEqual>::type
>::apply(p1, p0, top_left, bottom_left,
pp_strategy, ps_strategy);
sb_strategy);
return true;
}
@@ -459,7 +489,6 @@ private:
}
};
template <typename LessEqual>
struct check_above_below_of_box
{
@@ -469,26 +498,35 @@ private:
BoxPoint const& top_right,
BoxPoint const& bottom_left,
BoxPoint const& bottom_right,
PSStrategy const& ps_strategy,
SBStrategy const& sb_strategy,
ReturnType& result)
{
typedef compare_less_equal<ReturnType, false> GreaterEqual;
// the segment lies below the box
if (geometry::get<1>(p1) < geometry::get<1>(bottom_left))
{
result = above_of_box
<
typename other_compare<LessEqual>::type
>::apply(p1, p0, bottom_right, ps_strategy);
result = sb_strategy.template segment_below_of_box
<
LessEqual,
ReturnType
>(p0, p1,
top_left, top_right,
bottom_left, bottom_right);
return true;
}
// the segment lies above the box
if (geometry::get<1>(p0) > geometry::get<1>(top_right))
{
result = above_of_box
<
LessEqual
>::apply(p0, p1, top_left, ps_strategy);
result = (std::min)(above_of_box
<
LessEqual
>::apply(p0, p1, top_left, sb_strategy),
above_of_box
<
GreaterEqual
>::apply(p1, p0, top_right, sb_strategy));
return true;
}
return false;
@@ -499,47 +537,30 @@ private:
{
static inline bool apply(SegmentPoint const& p0,
SegmentPoint const& p1,
BoxPoint const& bottom_left0,
BoxPoint const& top_right0,
BoxPoint const& bottom_left1,
BoxPoint const& top_right1,
BoxPoint const& corner1,
BoxPoint const& corner2,
PSStrategy const& ps_strategy,
SBStrategy const& sb_strategy,
ReturnType& result)
{
typedef typename geometry::strategy::side::services::default_strategy
<
typename geometry::cs_tag<SegmentPoint>::type
>::type side;
typedef cast_to_result<ReturnType> cast;
ReturnType diff0 = cast::apply(geometry::get<0>(p1))
- cast::apply(geometry::get<0>(p0));
ReturnType t_min0 = cast::apply(geometry::get<0>(bottom_left0))
- cast::apply(geometry::get<0>(p0));
ReturnType t_max0 = cast::apply(geometry::get<0>(top_right0))
- cast::apply(geometry::get<0>(p0));
ReturnType diff1 = cast::apply(geometry::get<1>(p1))
- cast::apply(geometry::get<1>(p0));
ReturnType t_min1 = cast::apply(geometry::get<1>(bottom_left1))
- cast::apply(geometry::get<1>(p0));
ReturnType t_max1 = cast::apply(geometry::get<1>(top_right1))
- cast::apply(geometry::get<1>(p0));
- cast::apply(geometry::get<1>(p0));
if (diff1 < 0)
{
diff1 = -diff1;
t_min1 = -t_min1;
t_max1 = -t_max1;
}
typename SBStrategy::distance_ps_strategy::type ps_strategy =
sb_strategy.get_distance_ps_strategy();
// t_min0 > t_max1
if (t_min0 * diff1 > t_max1 * diff0)
int sign = diff1 < 0 ? -1 : 1;
if (side::apply(p0, p1, corner1) * sign < 0)
{
result = cast::apply(ps_strategy.apply(corner1, p0, p1));
return true;
}
// t_max0 < t_min1
if (t_max0 * diff1 < t_min1 * diff0)
if (side::apply(p0, p1, corner2) * sign > 0)
{
result = cast::apply(ps_strategy.apply(corner2, p0, p1));
return true;
@@ -555,8 +576,7 @@ private:
BoxPoint const& top_right,
BoxPoint const& bottom_left,
BoxPoint const& bottom_right,
PPStrategy const& pp_strategy,
PSStrategy const& ps_strategy)
SBStrategy const& sb_strategy)
{
typedef compare_less_equal<ReturnType, true> less_equal;
@@ -576,7 +596,7 @@ private:
less_equal
>::apply(p0, p1,
top_left, top_right, bottom_left, bottom_right,
pp_strategy, ps_strategy, result))
sb_strategy, result))
{
return result;
}
@@ -586,16 +606,14 @@ private:
less_equal
>::apply(p0, p1,
top_left, top_right, bottom_left, bottom_right,
ps_strategy, result))
sb_strategy, result))
{
return result;
}
if (check_generic_position::apply(p0, p1,
bottom_left, top_right,
bottom_left, top_right,
top_left, bottom_right,
ps_strategy, result))
sb_strategy, result))
{
return result;
}
@@ -612,8 +630,7 @@ private:
BoxPoint const& top_right,
BoxPoint const& bottom_left,
BoxPoint const& bottom_right,
PPStrategy const& pp_strategy,
PSStrategy const& ps_strategy)
SBStrategy const& sb_strategy)
{
typedef compare_less_equal<ReturnType, false> greater_equal;
@@ -630,7 +647,7 @@ private:
greater_equal
>::apply(p0, p1,
bottom_left, bottom_right, top_left, top_right,
pp_strategy, ps_strategy, result))
sb_strategy, result))
{
return result;
}
@@ -640,16 +657,14 @@ private:
greater_equal
>::apply(p1, p0,
top_right, top_left, bottom_right, bottom_left,
ps_strategy, result))
sb_strategy, result))
{
return result;
}
if (check_generic_position::apply(p0, p1,
bottom_left, top_right,
top_right, bottom_left,
bottom_left, top_right,
ps_strategy, result))
sb_strategy, result))
{
return result;
}
@@ -665,8 +680,7 @@ public:
BoxPoint const& top_right,
BoxPoint const& bottom_left,
BoxPoint const& bottom_right,
PPStrategy const& pp_strategy,
PSStrategy const& ps_strategy)
SBStrategy const& sb_strategy)
{
BOOST_GEOMETRY_ASSERT( geometry::less<SegmentPoint>()(p0, p1)
|| geometry::has_nan_coordinate(p0)
@@ -678,27 +692,43 @@ public:
return negative_slope_segment(p0, p1,
top_left, top_right,
bottom_left, bottom_right,
pp_strategy, ps_strategy);
sb_strategy);
}
return non_negative_slope_segment(p0, p1,
top_left, top_right,
bottom_left, bottom_right,
pp_strategy, ps_strategy);
sb_strategy);
}
template <typename LessEqual>
static inline ReturnType call_above_of_box(SegmentPoint const& p0,
SegmentPoint const& p1,
SegmentPoint const& p_max,
BoxPoint const& top_left,
SBStrategy const& sb_strategy)
{
return above_of_box<LessEqual>::apply(p0, p1, p_max, top_left, sb_strategy);
}
template <typename LessEqual>
static inline ReturnType call_above_of_box(SegmentPoint const& p0,
SegmentPoint const& p1,
BoxPoint const& top_left,
SBStrategy const& sb_strategy)
{
return above_of_box<LessEqual>::apply(p0, p1, top_left, sb_strategy);
}
};
//=========================================================================
template
<
typename Segment,
typename Box,
typename std::size_t Dimension,
typename PPStrategy,
typename PSStrategy
typename SBStrategy
>
class segment_to_box
: not_implemented<Segment, Box>
@@ -709,10 +739,9 @@ template
<
typename Segment,
typename Box,
typename PPStrategy,
typename PSStrategy
typename SBStrategy
>
class segment_to_box<Segment, Box, 2, PPStrategy, PSStrategy>
class segment_to_box<Segment, Box, 2, SBStrategy>
{
private:
typedef typename point_type<Segment>::type segment_point;
@@ -720,12 +749,7 @@ private:
typedef typename strategy::distance::services::comparable_type
<
PPStrategy
>::type pp_comparable_strategy;
typedef typename strategy::distance::services::comparable_type
<
PSStrategy
SBStrategy
>::type ps_comparable_strategy;
typedef typename strategy::distance::services::return_type
@@ -735,26 +759,26 @@ private:
public:
typedef typename strategy::distance::services::return_type
<
PSStrategy, segment_point, box_point
SBStrategy, segment_point, box_point
>::type return_type;
static inline return_type apply(Segment const& segment,
Box const& box,
PPStrategy const& pp_strategy,
PSStrategy const& ps_strategy)
SBStrategy const& sb_strategy)
{
segment_point p[2];
detail::assign_point_from_index<0>(segment, p[0]);
detail::assign_point_from_index<1>(segment, p[1]);
if (geometry::equals(p[0], p[1]))
if (detail::equals::equals_point_point(p[0], p[1],
sb_strategy.get_equals_point_point_strategy()))
{
typedef typename boost::mpl::if_
<
boost::is_same
<
ps_comparable_strategy,
PSStrategy
SBStrategy
>,
typename strategy::distance::services::comparable_type
<
@@ -781,6 +805,10 @@ public:
detail::assign_box_corners(box, bottom_left, bottom_right,
top_left, top_right);
SBStrategy::mirror(p[0], p[1],
bottom_left, bottom_right,
top_left, top_right);
if (geometry::less<segment_point>()(p[0], p[1]))
{
return segment_to_box_2D
@@ -788,12 +816,10 @@ public:
return_type,
segment_point,
box_point,
PPStrategy,
PSStrategy
SBStrategy
>::apply(p[0], p[1],
top_left, top_right, bottom_left, bottom_right,
pp_strategy,
ps_strategy);
sb_strategy);
}
else
{
@@ -802,12 +828,10 @@ public:
return_type,
segment_point,
box_point,
PPStrategy,
PSStrategy
SBStrategy
>::apply(p[1], p[0],
top_left, top_right, bottom_left, bottom_right,
pp_strategy,
ps_strategy);
sb_strategy);
}
}
};
@@ -826,7 +850,7 @@ template <typename Segment, typename Box, typename Strategy>
struct distance
<
Segment, Box, Strategy, segment_tag, box_tag,
strategy_tag_distance_point_segment, false
strategy_tag_distance_segment_box, false
>
{
typedef typename strategy::distance::services::return_type
@@ -843,40 +867,13 @@ struct distance
{
assert_dimension_equal<Segment, Box>();
typedef typename boost::mpl::if_
<
boost::is_same
<
typename strategy::distance::services::comparable_type
<
Strategy
>::type,
Strategy
>,
typename strategy::distance::services::comparable_type
<
typename detail::distance::default_strategy
<
typename point_type<Segment>::type,
typename point_type<Box>::type
>::type
>::type,
typename detail::distance::default_strategy
<
typename point_type<Segment>::type,
typename point_type<Box>::type
>::type
>::type pp_strategy_type;
return detail::distance::segment_to_box
<
Segment,
Box,
dimension<Segment>::value,
pp_strategy_type,
Strategy
>::apply(segment, box, pp_strategy_type(), strategy);
>::apply(segment, box, strategy);
}
};

View File

@@ -0,0 +1,90 @@
// Boost.Geometry
// Copyright (c) 2018 Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// 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_ENVELOPE_AREAL_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_AREAL_HPP
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/iterators/segment_iterator.hpp>
#include <boost/geometry/algorithms/detail/envelope/range.hpp>
#include <boost/geometry/algorithms/detail/envelope/linear.hpp>
#include <boost/geometry/algorithms/dispatch/envelope.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace envelope
{
struct envelope_polygon
{
template <typename Polygon, typename Box, typename Strategy>
static inline void apply(Polygon const& polygon, Box& mbr, Strategy const& strategy)
{
typename ring_return_type<Polygon const>::type ext_ring
= exterior_ring(polygon);
if (geometry::is_empty(ext_ring))
{
// if the exterior ring is empty, consider the interior rings
envelope_multi_range
<
envelope_range
>::apply(interior_rings(polygon), mbr, strategy);
}
else
{
// otherwise, consider only the exterior ring
envelope_range::apply(ext_ring, mbr, strategy);
}
}
};
}} // namespace detail::envelope
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Ring>
struct envelope<Ring, ring_tag>
: detail::envelope::envelope_range
{};
template <typename Polygon>
struct envelope<Polygon, polygon_tag>
: detail::envelope::envelope_polygon
{};
template <typename MultiPolygon>
struct envelope<MultiPolygon, multi_polygon_tag>
: detail::envelope::envelope_multi_range
<
detail::envelope::envelope_polygon
>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_AREAL_HPP

View File

@@ -4,11 +4,12 @@
// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2015, 2016.
// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates.
// This file was modified by Oracle on 2015-2018.
// Modifications copyright (c) 2015-2018, Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
@@ -17,151 +18,32 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_BOX_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_BOX_HPP
#include <cstddef>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/core/coordinate_system.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/views/detail/indexed_point_view.hpp>
#include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
#include <boost/geometry/algorithms/detail/normalize.hpp>
#include <boost/geometry/algorithms/detail/envelope/transform_units.hpp>
#include <boost/geometry/algorithms/dispatch/envelope.hpp>
// For backward compatibility
#include <boost/geometry/strategies/cartesian/envelope_box.hpp>
#include <boost/geometry/strategies/spherical/envelope_box.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace envelope
{
template
<
std::size_t Index,
std::size_t Dimension,
std::size_t DimensionCount
>
struct envelope_indexed_box
{
template <typename BoxIn, typename BoxOut>
static inline void apply(BoxIn const& box_in, BoxOut& mbr)
{
detail::indexed_point_view<BoxIn const, Index> box_in_corner(box_in);
detail::indexed_point_view<BoxOut, Index> mbr_corner(mbr);
detail::conversion::point_to_point
<
detail::indexed_point_view<BoxIn const, Index>,
detail::indexed_point_view<BoxOut, Index>,
Dimension,
DimensionCount
>::apply(box_in_corner, mbr_corner);
}
};
template
<
std::size_t Index,
std::size_t DimensionCount
>
struct envelope_indexed_box_on_spheroid
{
template <typename BoxIn, typename BoxOut>
static inline void apply(BoxIn const& box_in, BoxOut& mbr)
{
// transform() does not work with boxes of dimension higher
// than 2; to account for such boxes we transform the min/max
// points of the boxes using the indexed_point_view
detail::indexed_point_view<BoxIn const, Index> box_in_corner(box_in);
detail::indexed_point_view<BoxOut, Index> mbr_corner(mbr);
// first transform the units
transform_units(box_in_corner, mbr_corner);
// now transform the remaining coordinates
detail::conversion::point_to_point
<
detail::indexed_point_view<BoxIn const, Index>,
detail::indexed_point_view<BoxOut, Index>,
2,
DimensionCount
>::apply(box_in_corner, mbr_corner);
}
};
struct envelope_box
{
template<typename BoxIn, typename BoxOut, typename Strategy>
static inline void apply(BoxIn const& box_in,
BoxOut& mbr,
Strategy const&)
{
envelope_indexed_box
<
min_corner, 0, dimension<BoxIn>::value
>::apply(box_in, mbr);
envelope_indexed_box
<
max_corner, 0, dimension<BoxIn>::value
>::apply(box_in, mbr);
}
};
struct envelope_box_on_spheroid
{
template <typename BoxIn, typename BoxOut, typename Strategy>
static inline void apply(BoxIn const& box_in,
BoxOut& mbr,
Strategy const&)
{
BoxIn box_in_normalized = detail::return_normalized<BoxIn>(box_in);
envelope_indexed_box_on_spheroid
<
min_corner, dimension<BoxIn>::value
>::apply(box_in_normalized, mbr);
envelope_indexed_box_on_spheroid
<
max_corner, dimension<BoxIn>::value
>::apply(box_in_normalized, mbr);
}
};
}} // namespace detail::envelope
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Box, typename CS_Tag>
struct envelope<Box, box_tag, CS_Tag>
: detail::envelope::envelope_box
{};
template <typename Box>
struct envelope<Box, box_tag, spherical_equatorial_tag>
: detail::envelope::envelope_box_on_spheroid
{};
template <typename Box>
struct envelope<Box, box_tag, geographic_tag>
: detail::envelope::envelope_box_on_spheroid
{};
struct envelope<Box, box_tag>
{
template<typename BoxIn, typename BoxOut, typename Strategy>
static inline void apply(BoxIn const& box_in, BoxOut& mbr, Strategy const& )
{
Strategy::apply(box_in, mbr);
}
};
} // namespace dispatch

View File

@@ -26,6 +26,7 @@
#include <boost/geometry/algorithms/is_empty.hpp>
#include <boost/geometry/algorithms/detail/envelope/areal.hpp>
#include <boost/geometry/algorithms/detail/envelope/box.hpp>
#include <boost/geometry/algorithms/detail/envelope/linear.hpp>
#include <boost/geometry/algorithms/detail/envelope/multipoint.hpp>
@@ -35,73 +36,4 @@
#include <boost/geometry/algorithms/dispatch/envelope.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace envelope
{
struct envelope_polygon
{
template <typename Polygon, typename Box, typename Strategy>
static inline void apply(Polygon const& polygon, Box& mbr, Strategy const& strategy)
{
typename ring_return_type<Polygon const>::type ext_ring
= exterior_ring(polygon);
if (geometry::is_empty(ext_ring))
{
// if the exterior ring is empty, consider the interior rings
envelope_multi_range
<
envelope_range
>::apply(interior_rings(polygon), mbr, strategy);
}
else
{
// otherwise, consider only the exterior ring
envelope_range::apply(ext_ring, mbr, strategy);
}
}
};
}} // namespace detail::envelope
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Ring>
struct envelope<Ring, ring_tag>
: detail::envelope::envelope_range
{};
template <typename Polygon>
struct envelope<Polygon, polygon_tag>
: detail::envelope::envelope_polygon
{};
template <typename MultiPolygon>
struct envelope<MultiPolygon, multi_polygon_tag>
: detail::envelope::envelope_multi_range
<
detail::envelope::envelope_polygon
>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_IMPLEMENTATION_HPP

View File

@@ -4,8 +4,8 @@
// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2015, 2016, 2017.
// Modifications copyright (c) 2015-2017, Oracle and/or its affiliates.
// This file was modified by Oracle on 2015, 2016, 2017, 2018.
// Modifications copyright (c) 2015-2018, Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
@@ -21,19 +21,24 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_INTERFACE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_INTERFACE_HPP
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/algorithms/dispatch/envelope.hpp>
#include <boost/geometry/core/coordinate_system.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/strategies/default_strategy.hpp>
#include <boost/geometry/strategies/envelope.hpp>
#include <boost/geometry/strategies/cartesian/envelope_segment.hpp>
#include <boost/geometry/strategies/spherical/envelope_segment.hpp>
#include <boost/geometry/strategies/geographic/envelope_segment.hpp>
#include <boost/geometry/util/select_most_precise.hpp>
namespace boost { namespace geometry
{
@@ -57,13 +62,15 @@ struct envelope
Box& box,
default_strategy)
{
typedef typename point_type<Geometry>::type point_type;
typedef typename coordinate_type<point_type>::type coordinate_type;
typedef typename strategy::envelope::services::default_strategy
<
typename cs_tag<point_type>::type,
coordinate_type
typename tag<Geometry>::type,
typename cs_tag<Geometry>::type,
typename select_most_precise
<
typename coordinate_type<Geometry>::type,
typename coordinate_type<Box>::type
>::type
>::type strategy_type;
dispatch::envelope<Geometry>::apply(geometry, box, strategy_type());

View File

@@ -4,11 +4,12 @@
// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2015, 2016.
// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates.
// This file was modified by Oracle on 2015, 2016, 2018.
// Modifications copyright (c) 2015-2018, Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
@@ -17,93 +18,40 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_LINEAR_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_LINEAR_HPP
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/iterators/segment_iterator.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/detail/envelope/range.hpp>
#include <boost/geometry/algorithms/dispatch/envelope.hpp>
// For backward compatibility
#include <boost/geometry/strategies/cartesian/envelope.hpp>
#include <boost/geometry/strategies/spherical/envelope.hpp>
#include <boost/geometry/strategies/geographic/envelope.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace envelope
{
struct envelope_linestring_on_spheroid
{
template <typename Linestring, typename Box, typename Strategy>
static inline void apply(Linestring const& linestring,
Box& mbr,
Strategy const& strategy)
{
envelope_range::apply(geometry::segments_begin(linestring),
geometry::segments_end(linestring),
mbr,
strategy);
}
};
}} // namespace detail::envelope
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Linestring, typename CS_Tag>
struct envelope<Linestring, linestring_tag, CS_Tag>
template <typename Linestring>
struct envelope<Linestring, linestring_tag>
: detail::envelope::envelope_range
{};
template <typename Linestring>
struct envelope<Linestring, linestring_tag, spherical_equatorial_tag>
: detail::envelope::envelope_linestring_on_spheroid
{};
template <typename Linestring>
struct envelope<Linestring, linestring_tag, geographic_tag>
: detail::envelope::envelope_linestring_on_spheroid
{};
template <typename MultiLinestring, typename CS_Tag>
struct envelope
<
MultiLinestring, multi_linestring_tag, CS_Tag
> : detail::envelope::envelope_multi_range
template <typename MultiLinestring>
struct envelope<MultiLinestring, multi_linestring_tag>
: detail::envelope::envelope_multi_range
<
detail::envelope::envelope_range
>
{};
template <typename MultiLinestring>
struct envelope
<
MultiLinestring, multi_linestring_tag, spherical_equatorial_tag
> : detail::envelope::envelope_multi_range_on_spheroid
<
detail::envelope::envelope_linestring_on_spheroid
>
{};
template <typename MultiLinestring>
struct envelope
<
MultiLinestring, multi_linestring_tag, geographic_tag
> : detail::envelope::envelope_multi_range_on_spheroid
<
detail::envelope::envelope_linestring_on_spheroid
>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH

View File

@@ -1,9 +1,10 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2015-2016, Oracle and/or its affiliates.
// Copyright (c) 2015-2018, Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
@@ -12,363 +13,32 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_MULTIPOINT_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_MULTIPOINT_HPP
#include <cstddef>
#include <algorithm>
#include <utility>
#include <vector>
#include <boost/algorithm/minmax_element.hpp>
#include <boost/range.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/core/coordinate_system.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/range.hpp>
#include <boost/geometry/geometries/helper_geometry.hpp>
#include <boost/geometry/algorithms/detail/normalize.hpp>
#include <boost/geometry/algorithms/detail/envelope/box.hpp>
#include <boost/geometry/algorithms/detail/envelope/initialize.hpp>
#include <boost/geometry/algorithms/detail/envelope/range.hpp>
#include <boost/geometry/algorithms/detail/expand/point.hpp>
#include <boost/geometry/algorithms/dispatch/envelope.hpp>
// For backward compatibility
#include <boost/geometry/strategies/cartesian/envelope_multipoint.hpp>
#include <boost/geometry/strategies/spherical/envelope_multipoint.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace envelope
{
class envelope_multipoint_on_spheroid
{
private:
template <std::size_t Dim>
struct coordinate_less
{
template <typename Point>
inline bool operator()(Point const& point1, Point const& point2) const
{
return math::smaller(geometry::get<Dim>(point1),
geometry::get<Dim>(point2));
}
};
template <typename Constants, typename MultiPoint, typename OutputIterator>
static inline void analyze_point_coordinates(MultiPoint const& multipoint,
bool& has_south_pole,
bool& has_north_pole,
OutputIterator oit)
{
typedef typename boost::range_value<MultiPoint>::type point_type;
typedef typename boost::range_iterator
<
MultiPoint const
>::type iterator_type;
// analyze point coordinates:
// (1) normalize point coordinates
// (2) check if any point is the north or the south pole
// (3) put all non-pole points in a container
//
// notice that at this point in the algorithm, we have at
// least two points on the spheroid
has_south_pole = false;
has_north_pole = false;
for (iterator_type it = boost::begin(multipoint);
it != boost::end(multipoint);
++it)
{
point_type point = detail::return_normalized<point_type>(*it);
if (math::equals(geometry::get<1>(point),
Constants::min_latitude()))
{
has_south_pole = true;
}
else if (math::equals(geometry::get<1>(point),
Constants::max_latitude()))
{
has_north_pole = true;
}
else
{
*oit++ = point;
}
}
}
template <typename SortedRange, typename Value>
static inline Value maximum_gap(SortedRange const& sorted_range,
Value& max_gap_left,
Value& max_gap_right)
{
typedef typename boost::range_iterator
<
SortedRange const
>::type iterator_type;
iterator_type it1 = boost::begin(sorted_range), it2 = it1;
++it2;
max_gap_left = geometry::get<0>(*it1);
max_gap_right = geometry::get<0>(*it2);
Value max_gap = max_gap_right - max_gap_left;
for (++it1, ++it2; it2 != boost::end(sorted_range); ++it1, ++it2)
{
Value gap = geometry::get<0>(*it2) - geometry::get<0>(*it1);
if (math::larger(gap, max_gap))
{
max_gap_left = geometry::get<0>(*it1);
max_gap_right = geometry::get<0>(*it2);
max_gap = gap;
}
}
return max_gap;
}
template
<
typename Constants,
typename PointRange,
typename LongitudeLess,
typename CoordinateType
>
static inline void get_min_max_longitudes(PointRange& range,
LongitudeLess const& lon_less,
CoordinateType& lon_min,
CoordinateType& lon_max)
{
typedef typename boost::range_iterator
<
PointRange const
>::type iterator_type;
// compute min and max longitude values
std::pair<iterator_type, iterator_type> min_max_longitudes
= boost::minmax_element(boost::begin(range),
boost::end(range),
lon_less);
lon_min = geometry::get<0>(*min_max_longitudes.first);
lon_max = geometry::get<0>(*min_max_longitudes.second);
// if the longitude span is "large" compute the true maximum gap
if (math::larger(lon_max - lon_min, Constants::half_period()))
{
std::sort(boost::begin(range), boost::end(range), lon_less);
CoordinateType max_gap_left = 0, max_gap_right = 0;
CoordinateType max_gap
= maximum_gap(range, max_gap_left, max_gap_right);
CoordinateType complement_gap
= Constants::period() + lon_min - lon_max;
if (math::larger(max_gap, complement_gap))
{
lon_min = max_gap_right;
lon_max = max_gap_left + Constants::period();
}
}
}
template
<
typename Constants,
typename Iterator,
typename LatitudeLess,
typename CoordinateType
>
static inline void get_min_max_latitudes(Iterator const first,
Iterator const last,
LatitudeLess const& lat_less,
bool has_south_pole,
bool has_north_pole,
CoordinateType& lat_min,
CoordinateType& lat_max)
{
if (has_south_pole && has_north_pole)
{
lat_min = Constants::min_latitude();
lat_max = Constants::max_latitude();
}
else if (has_south_pole)
{
lat_min = Constants::min_latitude();
lat_max
= geometry::get<1>(*std::max_element(first, last, lat_less));
}
else if (has_north_pole)
{
lat_min
= geometry::get<1>(*std::min_element(first, last, lat_less));
lat_max = Constants::max_latitude();
}
else
{
std::pair<Iterator, Iterator> min_max_latitudes
= boost::minmax_element(first, last, lat_less);
lat_min = geometry::get<1>(*min_max_latitudes.first);
lat_max = geometry::get<1>(*min_max_latitudes.second);
}
}
public:
template <typename MultiPoint, typename Box, typename Strategy>
static inline void apply(MultiPoint const& multipoint, Box& mbr, Strategy const& strategy)
{
typedef typename point_type<MultiPoint>::type point_type;
typedef typename coordinate_type<MultiPoint>::type coordinate_type;
typedef typename boost::range_iterator
<
MultiPoint const
>::type iterator_type;
typedef math::detail::constants_on_spheroid
<
coordinate_type,
typename coordinate_system<MultiPoint>::type::units
> constants;
if (boost::empty(multipoint))
{
initialize<Box, 0, dimension<Box>::value>::apply(mbr);
return;
}
initialize<Box, 0, 2>::apply(mbr);
if (boost::size(multipoint) == 1)
{
return dispatch::envelope
<
typename boost::range_value<MultiPoint>::type
>::apply(range::front(multipoint), mbr, strategy);
}
// analyze the points and put the non-pole ones in the
// points vector
std::vector<point_type> points;
bool has_north_pole = false, has_south_pole = false;
analyze_point_coordinates<constants>(multipoint,
has_south_pole, has_north_pole,
std::back_inserter(points));
coordinate_type lon_min, lat_min, lon_max, lat_max;
if (points.size() == 1)
{
// we have one non-pole point and at least one pole point
lon_min = geometry::get<0>(range::front(points));
lon_max = geometry::get<0>(range::front(points));
lat_min = has_south_pole
? constants::min_latitude()
: constants::max_latitude();
lat_max = has_north_pole
? constants::max_latitude()
: constants::min_latitude();
}
else if (points.empty())
{
// all points are pole points
BOOST_GEOMETRY_ASSERT(has_south_pole || has_north_pole);
lon_min = coordinate_type(0);
lon_max = coordinate_type(0);
lat_min = has_south_pole
? constants::min_latitude()
: constants::max_latitude();
lat_max = (has_north_pole)
? constants::max_latitude()
: constants::min_latitude();
}
else
{
get_min_max_longitudes<constants>(points,
coordinate_less<0>(),
lon_min,
lon_max);
get_min_max_latitudes<constants>(points.begin(),
points.end(),
coordinate_less<1>(),
has_south_pole,
has_north_pole,
lat_min,
lat_max);
}
typedef typename helper_geometry
<
Box,
coordinate_type,
typename coordinate_system<MultiPoint>::type::units
>::type helper_box_type;
helper_box_type helper_mbr;
geometry::set<min_corner, 0>(helper_mbr, lon_min);
geometry::set<min_corner, 1>(helper_mbr, lat_min);
geometry::set<max_corner, 0>(helper_mbr, lon_max);
geometry::set<max_corner, 1>(helper_mbr, lat_max);
// now transform to output MBR (per index)
envelope_indexed_box_on_spheroid<min_corner, 2>::apply(helper_mbr, mbr);
envelope_indexed_box_on_spheroid<max_corner, 2>::apply(helper_mbr, mbr);
// compute envelope for higher coordinates
iterator_type it = boost::begin(multipoint);
envelope_one_point<2, dimension<Box>::value>::apply(*it, mbr, strategy);
for (++it; it != boost::end(multipoint); ++it)
{
detail::expand::point_loop
<
strategy::compare::default_strategy,
strategy::compare::default_strategy,
2, dimension<Box>::value
>::apply(mbr, *it, strategy);
}
}
};
}} // namespace detail::envelope
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename MultiPoint, typename CSTag>
struct envelope<MultiPoint, multi_point_tag, CSTag>
: detail::envelope::envelope_range
{};
template <typename MultiPoint>
struct envelope<MultiPoint, multi_point_tag, spherical_equatorial_tag>
: detail::envelope::envelope_multipoint_on_spheroid
{};
template <typename MultiPoint>
struct envelope<MultiPoint, multi_point_tag, geographic_tag>
: detail::envelope::envelope_multipoint_on_spheroid
{};
struct envelope<MultiPoint, multi_point_tag>
{
template <typename Box, typename Strategy>
static inline void apply(MultiPoint const& multipoint, Box& mbr, Strategy const& )
{
Strategy::apply(multipoint, mbr);
}
};
} // namespace dispatch

View File

@@ -4,11 +4,12 @@
// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2015, 2016.
// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates.
// This file was modified by Oracle on 2015, 2016, 2017, 2018.
// Modifications copyright (c) 2015-2018, Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
@@ -17,23 +18,14 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_POINT_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_POINT_HPP
#include <cstddef>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/core/coordinate_system.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/views/detail/indexed_point_view.hpp>
#include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
#include <boost/geometry/algorithms/detail/normalize.hpp>
#include <boost/geometry/algorithms/detail/envelope/transform_units.hpp>
#include <boost/geometry/algorithms/dispatch/envelope.hpp>
// For backward compatibility
#include <boost/geometry/strategies/cartesian/envelope_point.hpp>
#include <boost/geometry/strategies/spherical/envelope_point.hpp>
namespace boost { namespace geometry
{
@@ -43,53 +35,12 @@ namespace detail { namespace envelope
{
template <std::size_t Dimension, std::size_t DimensionCount>
struct envelope_one_point
struct envelope_point
{
template <std::size_t Index, typename Point, typename Box>
static inline void apply(Point const& point, Box& mbr)
{
detail::indexed_point_view<Box, Index> box_corner(mbr);
detail::conversion::point_to_point
<
Point,
detail::indexed_point_view<Box, Index>,
Dimension,
DimensionCount
>::apply(point, box_corner);
}
template <typename Point, typename Box, typename Strategy>
static inline void apply(Point const& point, Box& mbr, Strategy const&)
static inline void apply(Point const& point, Box& mbr, Strategy const& )
{
apply<min_corner>(point, mbr);
apply<max_corner>(point, mbr);
}
};
struct envelope_point_on_spheroid
{
template<typename Point, typename Box, typename Strategy>
static inline void apply(Point const& point, Box& mbr, Strategy const& strategy)
{
Point normalized_point = detail::return_normalized<Point>(point);
typename point_type<Box>::type box_point;
// transform units of input point to units of a box point
transform_units(normalized_point, box_point);
geometry::set<min_corner, 0>(mbr, geometry::get<0>(box_point));
geometry::set<min_corner, 1>(mbr, geometry::get<1>(box_point));
geometry::set<max_corner, 0>(mbr, geometry::get<0>(box_point));
geometry::set<max_corner, 1>(mbr, geometry::get<1>(box_point));
envelope_one_point
<
2, dimension<Point>::value
>::apply(normalized_point, mbr, strategy);
Strategy::apply(point, mbr);
}
};
@@ -102,21 +53,9 @@ namespace dispatch
{
template <typename Point, typename CS_Tag>
struct envelope<Point, point_tag, CS_Tag>
: detail::envelope::envelope_one_point<0, dimension<Point>::value>
{};
template <typename Point>
struct envelope<Point, point_tag, spherical_equatorial_tag>
: detail::envelope::envelope_point_on_spheroid
{};
template <typename Point>
struct envelope<Point, point_tag, geographic_tag>
: detail::envelope::envelope_point_on_spheroid
struct envelope<Point, point_tag>
: detail::envelope::envelope_point
{};

View File

@@ -4,11 +4,12 @@
// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2015, 2016.
// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates.
// This file was modified by Oracle on 2015, 2016, 2018.
// Modifications copyright (c) 2015-2018, Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -23,23 +24,17 @@
#include <iterator>
#include <vector>
#include <boost/range.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/util/range.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/geometry/algorithms/is_empty.hpp>
#include <boost/geometry/algorithms/detail/envelope/initialize.hpp>
#include <boost/geometry/algorithms/detail/envelope/range_of_boxes.hpp>
#include <boost/geometry/algorithms/detail/expand/box.hpp>
#include <boost/geometry/algorithms/detail/expand/point.hpp>
#include <boost/geometry/algorithms/detail/expand/segment.hpp>
#include <boost/geometry/algorithms/dispatch/envelope.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
namespace boost { namespace geometry
{
@@ -53,7 +48,7 @@ namespace detail { namespace envelope
struct envelope_range
{
template <typename Iterator, typename Box, typename Strategy>
static inline void apply(Iterator first,
static inline void apply(Iterator it,
Iterator last,
Box& mbr,
Strategy const& strategy)
@@ -63,16 +58,21 @@ struct envelope_range
// initialize MBR
initialize<Box, 0, dimension<Box>::value>::apply(mbr);
Iterator it = first;
if (it != last)
{
// initialize box with first element in range
dispatch::envelope<value_type>::apply(*it, mbr, strategy);
dispatch::envelope
<
value_type
>::apply(*it, mbr, strategy.get_element_envelope_strategy());
// consider now the remaining elements in the range (if any)
for (++it; it != last; ++it)
{
dispatch::expand<Box, value_type>::apply(mbr, *it, strategy);
dispatch::expand
<
Box, value_type
>::apply(mbr, *it, strategy.get_element_expand_strategy());
}
}
}
@@ -80,7 +80,7 @@ struct envelope_range
template <typename Range, typename Box, typename Strategy>
static inline void apply(Range const& range, Box& mbr, Strategy const& strategy)
{
return apply(boost::begin(range), boost::end(range), mbr, strategy);
return apply(Strategy::begin(range), Strategy::end(range), mbr, strategy);
}
};
@@ -94,86 +94,26 @@ struct envelope_multi_range
Box& mbr,
Strategy const& strategy)
{
typedef typename boost::range_iterator
<
MultiRange const
>::type iterator_type;
bool initialized = false;
for (iterator_type it = boost::begin(multirange);
it != boost::end(multirange);
++it)
{
if (! geometry::is_empty(*it))
{
if (initialized)
{
Box helper_mbr;
EnvelopePolicy::apply(*it, helper_mbr, strategy);
dispatch::expand<Box, Box>::apply(mbr, helper_mbr, strategy);
}
else
{
// compute the initial envelope
EnvelopePolicy::apply(*it, mbr, strategy);
initialized = true;
}
}
}
if (! initialized)
{
// if not already initialized, initialize MBR
initialize<Box, 0, dimension<Box>::value>::apply(mbr);
}
apply(boost::begin(multirange), boost::end(multirange), mbr, strategy);
}
};
// implementation for multi-range on a spheroid (longitude is periodic)
template <typename EnvelopePolicy>
struct envelope_multi_range_on_spheroid
{
template <typename MultiRange, typename Box, typename Strategy>
static inline void apply(MultiRange const& multirange,
template <typename Iter, typename Box, typename Strategy>
static inline void apply(Iter it,
Iter last,
Box& mbr,
Strategy const& strategy)
{
typedef typename boost::range_iterator
<
MultiRange const
>::type iterator_type;
// due to the periodicity of longitudes we need to compute the boxes
// of all the single geometries and keep them in a container
std::vector<Box> boxes;
for (iterator_type it = boost::begin(multirange);
it != boost::end(multirange);
++it)
typename Strategy::template multi_state<Box> state;
for (; it != last; ++it)
{
if (! geometry::is_empty(*it))
{
Box helper_box;
EnvelopePolicy::apply(*it, helper_box, strategy);
boxes.push_back(helper_box);
Box helper_mbr;
EnvelopePolicy::apply(*it, helper_mbr, strategy);
state.apply(helper_mbr);
}
}
// now we need to compute the envelope of the range of boxes
// (cannot be done in an incremental fashion as in the
// Cartesian coordinate system)
// if all single geometries are empty no boxes have been found
// and the MBR is simply initialized
if (! boxes.empty())
{
envelope_range_of_boxes::apply(boxes, mbr, strategy);
}
else
{
initialize<Box, 0, dimension<Box>::value>::apply(mbr);
}
state.result(mbr);
}
};

View File

@@ -1,9 +1,10 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2015-2016, Oracle and/or its affiliates.
// Copyright (c) 2015-2018, Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
@@ -19,17 +20,20 @@
#include <boost/range.hpp>
#include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
#include <boost/geometry/algorithms/detail/max_interval_gap.hpp>
#include <boost/geometry/algorithms/detail/expand/indexed.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/core/coordinate_system.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/normalize_spheroidal_coordinates.hpp>
#include <boost/geometry/util/range.hpp>
#include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
#include <boost/geometry/algorithms/detail/max_interval_gap.hpp>
#include <boost/geometry/algorithms/detail/expand/indexed.hpp>
#include <boost/geometry/views/detail/indexed_point_view.hpp>
namespace boost { namespace geometry
@@ -150,10 +154,8 @@ struct envelope_range_of_longitudes
template <std::size_t Dimension, std::size_t DimensionCount>
struct envelope_range_of_boxes_by_expansion
{
template <typename RangeOfBoxes, typename Box, typename Strategy>
static inline void apply(RangeOfBoxes const& range_of_boxes,
Box& mbr,
Strategy const& strategy)
template <typename RangeOfBoxes, typename Box>
static inline void apply(RangeOfBoxes const& range_of_boxes, Box& mbr)
{
typedef typename boost::range_value<RangeOfBoxes>::type box_type;
@@ -194,21 +196,17 @@ struct envelope_range_of_boxes_by_expansion
{
detail::expand::indexed_loop
<
strategy::compare::default_strategy,
strategy::compare::default_strategy,
min_corner,
Dimension,
DimensionCount
>::apply(mbr, *it, strategy);
>::apply(mbr, *it);
detail::expand::indexed_loop
<
strategy::compare::default_strategy,
strategy::compare::default_strategy,
max_corner,
Dimension,
DimensionCount
>::apply(mbr, *it, strategy);
>::apply(mbr, *it);
}
}
@@ -228,24 +226,28 @@ struct envelope_range_of_boxes
}
};
template <typename RangeOfBoxes, typename Box, typename Strategy>
static inline void apply(RangeOfBoxes const& range_of_boxes,
Box& mbr,
Strategy const& strategy)
template <typename RangeOfBoxes, typename Box>
static inline void apply(RangeOfBoxes const& range_of_boxes, Box& mbr)
{
// boxes in the range are assumed to be normalized already
typedef typename boost::range_value<RangeOfBoxes>::type box_type;
typedef typename coordinate_type<box_type>::type coordinate_type;
typedef typename coordinate_system<box_type>::type::units units_type;
typedef typename detail::cs_angular_units<box_type>::type units_type;
typedef typename boost::range_iterator
<
RangeOfBoxes const
>::type iterator_type;
static const bool is_equatorial = ! boost::is_same
<
typename cs_tag<box_type>::type,
spherical_polar_tag
>::value;
typedef math::detail::constants_on_spheroid
<
coordinate_type, units_type
coordinate_type, units_type, is_equatorial
> constants;
typedef longitude_interval<coordinate_type> interval_type;
@@ -269,6 +271,11 @@ struct envelope_range_of_boxes
it != boost::end(range_of_boxes);
++it)
{
if (is_inverse_spheroidal_coordinates(*it))
{
continue;
}
coordinate_type lat_min = geometry::get<min_corner, 1>(*it);
coordinate_type lat_max = geometry::get<max_corner, 1>(*it);
if (math::equals(lat_min, constants::max_latitude())
@@ -318,7 +325,7 @@ struct envelope_range_of_boxes
envelope_range_of_boxes_by_expansion
<
2, dimension<Box>::value
>::apply(range_of_boxes, mbr, strategy);
>::apply(range_of_boxes, mbr);
}
};

View File

@@ -4,8 +4,8 @@
// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2015-2017.
// Modifications copyright (c) 2015-2017, Oracle and/or its affiliates.
// This file was modified by Oracle on 2015-2018.
// Modifications copyright (c) 2015-2018, Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
@@ -19,34 +19,17 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_SEGMENT_HPP
#include <cstddef>
#include <utility>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/core/coordinate_system.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/srs.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/radian_access.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/geometries/helper_geometry.hpp>
#include <boost/geometry/formulas/vertex_latitude.hpp>
#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp>
#include <boost/geometry/algorithms/detail/envelope/point.hpp>
#include <boost/geometry/algorithms/detail/envelope/transform_units.hpp>
#include <boost/geometry/algorithms/detail/expand/point.hpp>
#include <boost/geometry/algorithms/dispatch/envelope.hpp>
// For backward compatibility
#include <boost/geometry/strategies/cartesian/envelope_segment.hpp>
#include <boost/geometry/strategies/spherical/envelope_segment.hpp>
#include <boost/geometry/strategies/geographic/envelope_segment.hpp>
namespace boost { namespace geometry
{
@@ -54,275 +37,6 @@ namespace boost { namespace geometry
namespace detail { namespace envelope
{
template <typename CalculationType, typename CS_Tag>
struct envelope_segment_call_vertex_latitude
{
template <typename T1, typename T2, typename Strategy>
static inline CalculationType apply(T1 const& lat1,
T2 const& alp1,
Strategy const& )
{
return geometry::formula::vertex_latitude<CalculationType, CS_Tag>
::apply(lat1, alp1);
}
};
template <typename CalculationType>
struct envelope_segment_call_vertex_latitude<CalculationType, geographic_tag>
{
template <typename T1, typename T2, typename Strategy>
static inline CalculationType apply(T1 const& lat1,
T2 const& alp1,
Strategy const& strategy)
{
return geometry::formula::vertex_latitude<CalculationType, geographic_tag>
::apply(lat1, alp1, strategy.model());
}
};
template <typename CS_Tag>
class envelope_segment_impl
{
private:
// degrees or radians
template <typename CalculationType>
static inline void swap(CalculationType& lon1,
CalculationType& lat1,
CalculationType& lon2,
CalculationType& lat2)
{
std::swap(lon1, lon2);
std::swap(lat1, lat2);
}
// radians
template <typename CalculationType>
static inline bool contains_pi_half(CalculationType const& a1,
CalculationType const& a2)
{
// azimuths a1 and a2 are assumed to be in radians
BOOST_GEOMETRY_ASSERT(! math::equals(a1, a2));
static CalculationType const pi_half = math::half_pi<CalculationType>();
return (a1 < a2)
? (a1 < pi_half && pi_half < a2)
: (a1 > pi_half && pi_half > a2);
}
// radians or degrees
template <typename Units, typename CoordinateType>
static inline bool crosses_antimeridian(CoordinateType const& lon1,
CoordinateType const& lon2)
{
typedef math::detail::constants_on_spheroid
<
CoordinateType, Units
> constants;
return math::abs(lon1 - lon2) > constants::half_period(); // > pi
}
// degrees or radians
template <typename Units, typename CalculationType, typename Strategy>
static inline void compute_box_corners(CalculationType& lon1,
CalculationType& lat1,
CalculationType& lon2,
CalculationType& lat2,
Strategy const& strategy)
{
// coordinates are assumed to be in radians
BOOST_GEOMETRY_ASSERT(lon1 <= lon2);
CalculationType lon1_rad = math::as_radian<Units>(lon1);
CalculationType lat1_rad = math::as_radian<Units>(lat1);
CalculationType lon2_rad = math::as_radian<Units>(lon2);
CalculationType lat2_rad = math::as_radian<Units>(lat2);
CalculationType a1, a2;
strategy.apply(lon1_rad, lat1_rad, lon2_rad, lat2_rad, a1, a2);
if (lat1 > lat2)
{
std::swap(lat1, lat2);
std::swap(lat1_rad, lat2_rad);
std::swap(a1, a2);
}
if (math::equals(a1, a2))
{
// the segment must lie on the equator or is very short
return;
}
if (contains_pi_half(a1, a2))
{
CalculationType p_max = envelope_segment_call_vertex_latitude
<CalculationType, CS_Tag>::apply(lat1_rad, a1, strategy);
CalculationType const mid_lat = lat1 + lat2;
if (mid_lat < 0)
{
// update using min latitude
CalculationType const lat_min_rad = -p_max;
CalculationType const lat_min
= math::from_radian<Units>(lat_min_rad);
if (lat1 > lat_min)
{
lat1 = lat_min;
}
}
else if (mid_lat > 0)
{
// update using max latitude
CalculationType const lat_max_rad = p_max;
CalculationType const lat_max
= math::from_radian<Units>(lat_max_rad);
if (lat2 < lat_max)
{
lat2 = lat_max;
}
}
}
}
template <typename Units, typename CalculationType, typename Strategy>
static inline void apply(CalculationType& lon1,
CalculationType& lat1,
CalculationType& lon2,
CalculationType& lat2,
Strategy const& strategy)
{
typedef math::detail::constants_on_spheroid
<
CalculationType, Units
> constants;
bool is_pole1 = math::equals(math::abs(lat1), constants::max_latitude());
bool is_pole2 = math::equals(math::abs(lat2), constants::max_latitude());
if (is_pole1 && is_pole2)
{
// both points are poles; nothing more to do:
// longitudes are already normalized to 0
// but just in case
lon1 = 0;
lon2 = 0;
}
else if (is_pole1 && !is_pole2)
{
// first point is a pole, second point is not:
// make the longitude of the first point the same as that
// of the second point
lon1 = lon2;
}
else if (!is_pole1 && is_pole2)
{
// second point is a pole, first point is not:
// make the longitude of the second point the same as that
// of the first point
lon2 = lon1;
}
if (lon1 == lon2)
{
// segment lies on a meridian
if (lat1 > lat2)
{
std::swap(lat1, lat2);
}
return;
}
BOOST_GEOMETRY_ASSERT(!is_pole1 && !is_pole2);
if (lon1 > lon2)
{
swap(lon1, lat1, lon2, lat2);
}
if (crosses_antimeridian<Units>(lon1, lon2))
{
lon1 += constants::period();
swap(lon1, lat1, lon2, lat2);
}
compute_box_corners<Units>(lon1, lat1, lon2, lat2, strategy);
}
public:
template <
typename Units,
typename CalculationType,
typename Box,
typename Strategy
>
static inline void apply(CalculationType lon1,
CalculationType lat1,
CalculationType lon2,
CalculationType lat2,
Box& mbr,
Strategy const& strategy)
{
typedef typename coordinate_type<Box>::type box_coordinate_type;
typedef typename helper_geometry
<
Box, box_coordinate_type, Units
>::type helper_box_type;
helper_box_type radian_mbr;
apply<Units>(lon1, lat1, lon2, lat2, strategy);
geometry::set
<
min_corner, 0
>(radian_mbr, boost::numeric_cast<box_coordinate_type>(lon1));
geometry::set
<
min_corner, 1
>(radian_mbr, boost::numeric_cast<box_coordinate_type>(lat1));
geometry::set
<
max_corner, 0
>(radian_mbr, boost::numeric_cast<box_coordinate_type>(lon2));
geometry::set
<
max_corner, 1
>(radian_mbr, boost::numeric_cast<box_coordinate_type>(lat2));
transform_units(radian_mbr, mbr);
}
};
template <std::size_t Dimension, std::size_t DimensionCount>
struct envelope_one_segment
{
template<typename Point, typename Box, typename Strategy>
static inline void apply(Point const& p1,
Point const& p2,
Box& mbr,
Strategy const& strategy)
{
envelope_one_point<Dimension, DimensionCount>::apply(p1, mbr, strategy);
detail::expand::point_loop
<
strategy::compare::default_strategy,
strategy::compare::default_strategy,
Dimension,
DimensionCount
>::apply(mbr, p2, strategy);
}
};
template <std::size_t DimensionCount>
struct envelope_segment
{
@@ -332,21 +46,17 @@ struct envelope_segment
Box& mbr,
Strategy const& strategy)
{
// first compute the envelope range for the first two coordinates
strategy.apply(p1, p2, mbr);
// now compute the envelope range for coordinates of
// dimension 2 and higher
envelope_one_segment<2, DimensionCount>::apply(p1, p2, mbr, strategy);
}
template <typename Segment, typename Box>
static inline void apply(Segment const& segment, Box& mbr)
template <typename Segment, typename Box, typename Strategy>
static inline void apply(Segment const& segment, Box& mbr,
Strategy const& strategy)
{
typename point_type<Segment>::type p[2];
detail::assign_point_from_index<0>(segment, p[0]);
detail::assign_point_from_index<1>(segment, p[1]);
apply(p[0], p[1], mbr);
apply(p[0], p[1], mbr, strategy);
}
};

View File

@@ -0,0 +1,401 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// Copyright (c) 2014-2015 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2014, 2015, 2016, 2017, 2018.
// Modifications copyright (c) 2014-2018 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// 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_EQUALS_IMPLEMENTATION_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_IMPLEMENTATION_HPP
#include <cstddef>
#include <vector>
#include <boost/range.hpp>
#include <boost/type_traits/is_base_of.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
// For trivial checks
#include <boost/geometry/algorithms/area.hpp>
#include <boost/geometry/algorithms/length.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/select_coordinate_type.hpp>
#include <boost/geometry/util/select_most_precise.hpp>
#include <boost/geometry/algorithms/detail/equals/collect_vectors.hpp>
#include <boost/geometry/algorithms/detail/equals/interface.hpp>
#include <boost/geometry/algorithms/detail/relate/relate_impl.hpp>
#include <boost/geometry/algorithms/relate.hpp>
#include <boost/geometry/views/detail/indexed_point_view.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace equals
{
template
<
std::size_t Dimension,
std::size_t DimensionCount
>
struct point_point
{
template <typename Point1, typename Point2, typename Strategy>
static inline bool apply(Point1 const& point1, Point2 const& point2, Strategy const& )
{
return Strategy::apply(point1, point2);
}
};
template
<
std::size_t Dimension,
std::size_t DimensionCount
>
struct box_box
{
template <typename Box1, typename Box2, typename Strategy>
static inline bool apply(Box1 const& box1, Box2 const& box2, Strategy const& strategy)
{
if (!geometry::math::equals(get<min_corner, Dimension>(box1), get<min_corner, Dimension>(box2))
|| !geometry::math::equals(get<max_corner, Dimension>(box1), get<max_corner, Dimension>(box2)))
{
return false;
}
return box_box<Dimension + 1, DimensionCount>::apply(box1, box2, strategy);
}
};
template <std::size_t DimensionCount>
struct box_box<DimensionCount, DimensionCount>
{
template <typename Box1, typename Box2, typename Strategy>
static inline bool apply(Box1 const& , Box2 const& , Strategy const& )
{
return true;
}
};
struct segment_segment
{
template <typename Segment1, typename Segment2, typename Strategy>
static inline bool apply(Segment1 const& segment1, Segment2 const& segment2,
Strategy const& strategy)
{
typename Strategy::point_in_point_strategy_type const&
pt_pt_strategy = strategy.get_point_in_point_strategy();
return equals::equals_point_point(
indexed_point_view<Segment1 const, 0>(segment1),
indexed_point_view<Segment2 const, 0>(segment2),
pt_pt_strategy)
? equals::equals_point_point(
indexed_point_view<Segment1 const, 1>(segment1),
indexed_point_view<Segment2 const, 1>(segment2),
pt_pt_strategy)
: ( equals::equals_point_point(
indexed_point_view<Segment1 const, 0>(segment1),
indexed_point_view<Segment2 const, 1>(segment2),
pt_pt_strategy)
&& equals::equals_point_point(
indexed_point_view<Segment1 const, 1>(segment1),
indexed_point_view<Segment2 const, 0>(segment2),
pt_pt_strategy)
);
}
};
struct area_check
{
template <typename Geometry1, typename Geometry2, typename Strategy>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
return geometry::math::equals(
geometry::area(geometry1,
strategy.template get_area_strategy<Geometry1>()),
geometry::area(geometry2,
strategy.template get_area_strategy<Geometry2>()));
}
};
struct length_check
{
template <typename Geometry1, typename Geometry2, typename Strategy>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
return geometry::math::equals(
geometry::length(geometry1,
strategy.template get_distance_strategy<Geometry1>()),
geometry::length(geometry2,
strategy.template get_distance_strategy<Geometry2>()));
}
};
template <typename Geometry1, typename Geometry2, typename IntersectionStrategy>
struct collected_vector
{
typedef typename geometry::select_most_precise
<
typename select_coordinate_type
<
Geometry1, Geometry2
>::type,
double
>::type calculation_type;
typedef geometry::collected_vector
<
calculation_type,
Geometry1,
typename IntersectionStrategy::side_strategy_type
> type;
};
template <typename TrivialCheck>
struct equals_by_collection
{
template <typename Geometry1, typename Geometry2, typename Strategy>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
if (! TrivialCheck::apply(geometry1, geometry2, strategy))
{
return false;
}
typedef typename collected_vector
<
Geometry1, Geometry2, Strategy
>::type collected_vector_type;
std::vector<collected_vector_type> c1, c2;
geometry::collect_vectors(c1, geometry1);
geometry::collect_vectors(c2, geometry2);
if (boost::size(c1) != boost::size(c2))
{
return false;
}
std::sort(c1.begin(), c1.end());
std::sort(c2.begin(), c2.end());
// Just check if these vectors are equal.
return std::equal(c1.begin(), c1.end(), c2.begin());
}
};
template<typename Geometry1, typename Geometry2>
struct equals_by_relate
: detail::relate::relate_impl
<
detail::de9im::static_mask_equals_type,
Geometry1,
Geometry2
>
{};
// If collect_vectors which is a SideStrategy-dispatched optimization
// is implemented in a way consistent with the Intersection/Side Strategy
// then collect_vectors is used, otherwise relate is used.
// NOTE: the result could be conceptually different for invalid
// geometries in different coordinate systems because collect_vectors
// and relate treat invalid geometries differently.
template<typename TrivialCheck>
struct equals_by_collection_or_relate
{
template <typename Geometry1, typename Geometry2, typename Strategy>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
typedef typename boost::is_base_of
<
nyi::not_implemented_tag,
typename collected_vector
<
Geometry1, Geometry2, Strategy
>::type
>::type enable_relate_type;
return apply(geometry1, geometry2, strategy, enable_relate_type());
}
private:
template <typename Geometry1, typename Geometry2, typename Strategy>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy,
boost::false_type /*enable_relate*/)
{
return equals_by_collection<TrivialCheck>::apply(geometry1, geometry2, strategy);
}
template <typename Geometry1, typename Geometry2, typename Strategy>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy,
boost::true_type /*enable_relate*/)
{
return equals_by_relate<Geometry1, Geometry2>::apply(geometry1, geometry2, strategy);
}
};
}} // namespace detail::equals
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename P1, typename P2, std::size_t DimensionCount, bool Reverse>
struct equals<P1, P2, point_tag, point_tag, DimensionCount, Reverse>
: detail::equals::point_point<0, DimensionCount>
{};
template <typename MultiPoint1, typename MultiPoint2, std::size_t DimensionCount, bool Reverse>
struct equals<MultiPoint1, MultiPoint2, multi_point_tag, multi_point_tag, DimensionCount, Reverse>
: detail::equals::equals_by_relate<MultiPoint1, MultiPoint2>
{};
template <typename MultiPoint, typename Point, std::size_t DimensionCount, bool Reverse>
struct equals<Point, MultiPoint, point_tag, multi_point_tag, DimensionCount, Reverse>
: detail::equals::equals_by_relate<Point, MultiPoint>
{};
template <typename Box1, typename Box2, std::size_t DimensionCount, bool Reverse>
struct equals<Box1, Box2, box_tag, box_tag, DimensionCount, Reverse>
: detail::equals::box_box<0, DimensionCount>
{};
template <typename Ring1, typename Ring2, bool Reverse>
struct equals<Ring1, Ring2, ring_tag, ring_tag, 2, Reverse>
: detail::equals::equals_by_collection_or_relate<detail::equals::area_check>
{};
template <typename Polygon1, typename Polygon2, bool Reverse>
struct equals<Polygon1, Polygon2, polygon_tag, polygon_tag, 2, Reverse>
: detail::equals::equals_by_collection_or_relate<detail::equals::area_check>
{};
template <typename Polygon, typename Ring, bool Reverse>
struct equals<Polygon, Ring, polygon_tag, ring_tag, 2, Reverse>
: detail::equals::equals_by_collection_or_relate<detail::equals::area_check>
{};
template <typename Ring, typename Box, bool Reverse>
struct equals<Ring, Box, ring_tag, box_tag, 2, Reverse>
: detail::equals::equals_by_collection<detail::equals::area_check>
{};
template <typename Polygon, typename Box, bool Reverse>
struct equals<Polygon, Box, polygon_tag, box_tag, 2, Reverse>
: detail::equals::equals_by_collection<detail::equals::area_check>
{};
template <typename Segment1, typename Segment2, std::size_t DimensionCount, bool Reverse>
struct equals<Segment1, Segment2, segment_tag, segment_tag, DimensionCount, Reverse>
: detail::equals::segment_segment
{};
template <typename LineString1, typename LineString2, bool Reverse>
struct equals<LineString1, LineString2, linestring_tag, linestring_tag, 2, Reverse>
: detail::equals::equals_by_relate<LineString1, LineString2>
{};
template <typename LineString, typename MultiLineString, bool Reverse>
struct equals<LineString, MultiLineString, linestring_tag, multi_linestring_tag, 2, Reverse>
: detail::equals::equals_by_relate<LineString, MultiLineString>
{};
template <typename MultiLineString1, typename MultiLineString2, bool Reverse>
struct equals<MultiLineString1, MultiLineString2, multi_linestring_tag, multi_linestring_tag, 2, Reverse>
: detail::equals::equals_by_relate<MultiLineString1, MultiLineString2>
{};
template <typename MultiPolygon1, typename MultiPolygon2, bool Reverse>
struct equals
<
MultiPolygon1, MultiPolygon2,
multi_polygon_tag, multi_polygon_tag,
2,
Reverse
>
: detail::equals::equals_by_collection_or_relate<detail::equals::area_check>
{};
template <typename Polygon, typename MultiPolygon, bool Reverse>
struct equals
<
Polygon, MultiPolygon,
polygon_tag, multi_polygon_tag,
2,
Reverse
>
: detail::equals::equals_by_collection_or_relate<detail::equals::area_check>
{};
template <typename MultiPolygon, typename Ring, bool Reverse>
struct equals
<
MultiPolygon, Ring,
multi_polygon_tag, ring_tag,
2,
Reverse
>
: detail::equals::equals_by_collection_or_relate<detail::equals::area_check>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_IMPLEMENTATION_HPP

View File

@@ -0,0 +1,317 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// Copyright (c) 2014-2015 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2014, 2015, 2016, 2017.
// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// 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_EQUALS_INTERFACE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_INTERFACE_HPP
#include <cstddef>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/core/reverse_dispatch.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/strategies/default_strategy.hpp>
#include <boost/geometry/strategies/relate.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template
<
typename Geometry1,
typename Geometry2,
typename Tag1 = typename tag<Geometry1>::type,
typename Tag2 = typename tag<Geometry2>::type,
std::size_t DimensionCount = dimension<Geometry1>::type::value,
bool Reverse = reverse_dispatch<Geometry1, Geometry2>::type::value
>
struct equals: not_implemented<Tag1, Tag2>
{};
// If reversal is needed, perform it
template
<
typename Geometry1, typename Geometry2,
typename Tag1, typename Tag2,
std::size_t DimensionCount
>
struct equals<Geometry1, Geometry2, Tag1, Tag2, DimensionCount, true>
: equals<Geometry2, Geometry1, Tag2, Tag1, DimensionCount, false>
{
template <typename Strategy>
static inline bool apply(Geometry1 const& g1, Geometry2 const& g2, Strategy const& strategy)
{
return equals
<
Geometry2, Geometry1,
Tag2, Tag1,
DimensionCount,
false
>::apply(g2, g1, strategy);
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
namespace resolve_strategy
{
struct equals
{
template <typename Geometry1, typename Geometry2, typename Strategy>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
return dispatch::equals
<
Geometry1, Geometry2
>::apply(geometry1, geometry2, strategy);
}
template <typename Geometry1, typename Geometry2>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
default_strategy)
{
typedef typename strategy::relate::services::default_strategy
<
Geometry1,
Geometry2
>::type strategy_type;
return dispatch::equals
<
Geometry1, Geometry2
>::apply(geometry1, geometry2, strategy_type());
}
};
} // namespace resolve_strategy
namespace resolve_variant {
template <typename Geometry1, typename Geometry2>
struct equals
{
template <typename Strategy>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
concepts::check_concepts_and_equal_dimensions
<
Geometry1 const,
Geometry2 const
>();
return resolve_strategy::equals
::apply(geometry1, geometry2, strategy);
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
struct equals<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
{
template <typename Strategy>
struct visitor: static_visitor<bool>
{
Geometry2 const& m_geometry2;
Strategy const& m_strategy;
visitor(Geometry2 const& geometry2, Strategy const& strategy)
: m_geometry2(geometry2)
, m_strategy(strategy)
{}
template <typename Geometry1>
inline bool operator()(Geometry1 const& geometry1) const
{
return equals<Geometry1, Geometry2>
::apply(geometry1, m_geometry2, m_strategy);
}
};
template <typename Strategy>
static inline bool apply(
boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy
)
{
return boost::apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1);
}
};
template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct equals<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
{
template <typename Strategy>
struct visitor: static_visitor<bool>
{
Geometry1 const& m_geometry1;
Strategy const& m_strategy;
visitor(Geometry1 const& geometry1, Strategy const& strategy)
: m_geometry1(geometry1)
, m_strategy(strategy)
{}
template <typename Geometry2>
inline bool operator()(Geometry2 const& geometry2) const
{
return equals<Geometry1, Geometry2>
::apply(m_geometry1, geometry2, m_strategy);
}
};
template <typename Strategy>
static inline bool apply(
Geometry1 const& geometry1,
boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2,
Strategy const& strategy
)
{
return boost::apply_visitor(visitor<Strategy>(geometry1, strategy), geometry2);
}
};
template <
BOOST_VARIANT_ENUM_PARAMS(typename T1),
BOOST_VARIANT_ENUM_PARAMS(typename T2)
>
struct equals<
boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>,
boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>
>
{
template <typename Strategy>
struct visitor: static_visitor<bool>
{
Strategy const& m_strategy;
visitor(Strategy const& strategy)
: m_strategy(strategy)
{}
template <typename Geometry1, typename Geometry2>
inline bool operator()(Geometry1 const& geometry1,
Geometry2 const& geometry2) const
{
return equals<Geometry1, Geometry2>
::apply(geometry1, geometry2, m_strategy);
}
};
template <typename Strategy>
static inline bool apply(
boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1,
boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2,
Strategy const& strategy
)
{
return boost::apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2);
}
};
} // namespace resolve_variant
/*!
\brief \brief_check{are spatially equal}
\details \details_check12{equals, is spatially equal}. Spatially equal means
that the same point set is included. A box can therefore be spatially equal
to a ring or a polygon, or a linestring can be spatially equal to a
multi-linestring or a segment. This only works theoretically, not all
combinations are implemented yet.
\ingroup equals
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\tparam Strategy \tparam_strategy{Equals}
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\param strategy \param_strategy{equals}
\return \return_check2{are spatially equal}
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/equals.qbk]}
*/
template <typename Geometry1, typename Geometry2, typename Strategy>
inline bool equals(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
return resolve_variant::equals
<
Geometry1, Geometry2
>::apply(geometry1, geometry2, strategy);
}
/*!
\brief \brief_check{are spatially equal}
\details \details_check12{equals, is spatially equal}. Spatially equal means
that the same point set is included. A box can therefore be spatially equal
to a ring or a polygon, or a linestring can be spatially equal to a
multi-linestring or a segment. This only works theoretically, not all
combinations are implemented yet.
\ingroup equals
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\return \return_check2{are spatially equal}
\qbk{[include reference/algorithms/equals.qbk]}
*/
template <typename Geometry1, typename Geometry2>
inline bool equals(Geometry1 const& geometry1, Geometry2 const& geometry2)
{
return resolve_variant::equals<Geometry1, Geometry2>
::apply(geometry1, geometry2, default_strategy());
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_INTERFACE_HPP

View File

@@ -5,8 +5,8 @@
// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland
// This file was modified by Oracle on 2013-2014.
// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates.
// This file was modified by Oracle on 2013-2018.
// Modifications copyright (c) 2013-2018, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
@@ -21,13 +21,10 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_POINT_POINT_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_POINT_POINT_HPP
#include <boost/geometry/algorithms/detail/disjoint/point_point.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace equals
{
@@ -36,17 +33,16 @@ namespace detail { namespace equals
\brief Internal utility function to detect of points are disjoint
\note To avoid circular references
*/
template <typename Point1, typename Point2>
inline bool equals_point_point(Point1 const& point1, Point2 const& point2)
template <typename Point1, typename Point2, typename Strategy>
inline bool equals_point_point(Point1 const& point1, Point2 const& point2,
Strategy const& )
{
return ! detail::disjoint::disjoint_point_point(point1, point2);
return Strategy::apply(point1, point2);
}
}} // namespace detail::equals
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_POINT_POINT_HPP

View File

@@ -5,11 +5,12 @@
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// Copyright (c) 2014-2015 Samuel Debionne, Grenoble, France.
// This file was modified by Oracle on 2015, 2016.
// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates.
// This file was modified by Oracle on 2015, 2016, 2017, 2018.
// Modifications copyright (c) 2015-2018, Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
@@ -18,52 +19,19 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_BOX_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_BOX_HPP
#include <cstddef>
#include <algorithm>
#include <boost/mpl/assert.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/detail/envelope/box.hpp>
#include <boost/geometry/algorithms/detail/envelope/range_of_boxes.hpp>
#include <boost/geometry/algorithms/detail/expand/indexed.hpp>
#include <boost/geometry/algorithms/dispatch/expand.hpp>
#include <boost/geometry/core/tags.hpp>
// For backward compatibility
#include <boost/geometry/strategies/cartesian/expand_box.hpp>
#include <boost/geometry/strategies/spherical/expand_box.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace expand
{
struct box_on_spheroid
{
template <typename BoxOut, typename BoxIn, typename Strategy>
static inline void apply(BoxOut& box_out,
BoxIn const& box_in,
Strategy const& strategy)
{
// normalize both boxes and convert box-in to be of type of box-out
BoxOut mbrs[2];
detail::envelope::envelope_box_on_spheroid::apply(box_in, mbrs[0], strategy);
detail::envelope::envelope_box_on_spheroid::apply(box_out, mbrs[1], strategy);
// compute the envelope of the two boxes
detail::envelope::envelope_range_of_boxes::apply(mbrs, box_out, strategy);
}
};
}} // namespace detail::expand
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
@@ -72,53 +40,23 @@ namespace dispatch
// Box + box -> new box containing two input boxes
template
<
typename BoxOut, typename BoxIn,
typename StrategyLess, typename StrategyGreater,
typename CSTagOut, typename CSTag
typename BoxOut, typename BoxIn
>
struct expand
<
BoxOut, BoxIn,
StrategyLess, StrategyGreater,
box_tag, box_tag,
CSTagOut, CSTag
> : detail::expand::expand_indexed
<
0, dimension<BoxIn>::value, StrategyLess, StrategyGreater
>
box_tag, box_tag
>
{
BOOST_MPL_ASSERT_MSG((boost::is_same<CSTagOut, CSTag>::value),
COORDINATE_SYSTEMS_MUST_BE_THE_SAME,
(types<CSTagOut, CSTag>()));
template <typename Strategy>
static inline void apply(BoxOut& box_out,
BoxIn const& box_in,
Strategy const& )
{
Strategy::apply(box_out, box_in);
}
};
template
<
typename BoxOut, typename BoxIn,
typename StrategyLess, typename StrategyGreater
>
struct expand
<
BoxOut, BoxIn,
StrategyLess, StrategyGreater,
box_tag, box_tag,
spherical_equatorial_tag, spherical_equatorial_tag
> : detail::expand::box_on_spheroid
{};
template
<
typename BoxOut, typename BoxIn,
typename StrategyLess, typename StrategyGreater
>
struct expand
<
BoxOut, BoxIn,
StrategyLess, StrategyGreater,
box_tag, box_tag,
geographic_tag, geographic_tag
> : detail::expand::box_on_spheroid
{};
} // namespace dispatch

View File

@@ -5,11 +5,12 @@
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// Copyright (c) 2014-2015 Samuel Debionne, Grenoble, France.
// This file was modified by Oracle on 2015, 2016.
// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates.
// This file was modified by Oracle on 2015, 2016, 2017, 2018.
// Modifications copyright (c) 2015-2018, Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -22,15 +23,13 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_INDEXED_HPP
#include <cstddef>
#include <functional>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/util/select_coordinate_type.hpp>
#include <boost/geometry/strategies/compare.hpp>
#include <boost/geometry/policies/compare.hpp>
#include <boost/geometry/algorithms/dispatch/expand.hpp>
@@ -44,36 +43,25 @@ namespace detail { namespace expand
template
<
typename StrategyLess, typename StrategyGreater,
std::size_t Index,
std::size_t Dimension, std::size_t DimensionCount
>
struct indexed_loop
{
template <typename Box, typename Geometry, typename Strategy>
static inline void apply(Box& box, Geometry const& source, Strategy const& strategy)
template <typename Box, typename Geometry>
static inline void apply(Box& box, Geometry const& source)
{
typedef typename strategy::compare::detail::select_strategy
<
StrategyLess, 1, Box, Dimension
>::type less_type;
typedef typename strategy::compare::detail::select_strategy
<
StrategyGreater, -1, Box, Dimension
>::type greater_type;
typedef typename select_coordinate_type
<
Box,
Geometry
>::type coordinate_type;
less_type less;
greater_type greater;
coordinate_type const coord = get<Index, Dimension>(source);
std::less<coordinate_type> less;
std::greater<coordinate_type> greater;
if (less(coord, get<min_corner, Dimension>(box)))
{
set<min_corner, Dimension>(box, coord);
@@ -86,54 +74,40 @@ struct indexed_loop
indexed_loop
<
StrategyLess, StrategyGreater,
Index, Dimension + 1, DimensionCount
>::apply(box, source, strategy);
>::apply(box, source);
}
};
template
<
typename StrategyLess, typename StrategyGreater,
std::size_t Index, std::size_t DimensionCount
>
template <std::size_t Index, std::size_t DimensionCount>
struct indexed_loop
<
StrategyLess, StrategyGreater,
Index, DimensionCount, DimensionCount
>
{
template <typename Box, typename Geometry, typename Strategy>
static inline void apply(Box&, Geometry const&, Strategy const&) {}
template <typename Box, typename Geometry>
static inline void apply(Box&, Geometry const&) {}
};
// Changes a box such that the other box is also contained by the box
template
<
std::size_t Dimension, std::size_t DimensionCount,
typename StrategyLess, typename StrategyGreater
>
template <std::size_t Dimension, std::size_t DimensionCount>
struct expand_indexed
{
template <typename Box, typename Geometry, typename Strategy>
static inline void apply(Box& box,
Geometry const& geometry,
Strategy const& strategy)
template <typename Box, typename Geometry>
static inline void apply(Box& box, Geometry const& geometry)
{
indexed_loop
<
StrategyLess, StrategyGreater,
0, Dimension, DimensionCount
>::apply(box, geometry, strategy);
>::apply(box, geometry);
indexed_loop
<
StrategyLess, StrategyGreater,
1, Dimension, DimensionCount
>::apply(box, geometry, strategy);
>::apply(box, geometry);
}
};

View File

@@ -5,11 +5,12 @@
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// Copyright (c) 2014-2015 Samuel Debionne, Grenoble, France.
// This file was modified by Oracle on 2015, 2016.
// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates.
// This file was modified by Oracle on 2015, 2016, 2018.
// Modifications copyright (c) 2015-2018, Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -25,16 +26,17 @@
#include <boost/variant/static_visitor.hpp>
#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/core/coordinate_system.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/algorithms/dispatch/expand.hpp>
#include <boost/geometry/strategies/default_strategy.hpp>
#include <boost/geometry/strategies/expand.hpp>
#include <boost/geometry/strategies/envelope.hpp>
#include <boost/geometry/strategies/cartesian/envelope_segment.hpp>
#include <boost/geometry/strategies/spherical/envelope_segment.hpp>
#include <boost/geometry/strategies/geographic/envelope_segment.hpp>
namespace boost { namespace geometry
{
@@ -58,14 +60,11 @@ struct expand
Geometry const& geometry,
default_strategy)
{
typedef typename point_type<Geometry>::type point_type;
typedef typename coordinate_type<point_type>::type coordinate_type;
typedef typename strategy::envelope::services::default_strategy
<
typename cs_tag<point_type>::type,
coordinate_type
>::type strategy_type;
typedef typename strategy::expand::services::default_strategy
<
typename tag<Geometry>::type,
typename cs_tag<Geometry>::type
>::type strategy_type;
dispatch::expand<Box, Geometry>::apply(box, geometry, strategy_type());
}

View File

@@ -5,11 +5,12 @@
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// Copyright (c) 2014-2015 Samuel Debionne, Grenoble, France.
// This file was modified by Oracle on 2015, 2016.
// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates.
// This file was modified by Oracle on 2015-2018.
// Modifications copyright (c) 2015-2018, Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -21,222 +22,19 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_POINT_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_POINT_HPP
#include <cstddef>
#include <algorithm>
#include <boost/mpl/assert.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/core/coordinate_system.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/select_coordinate_type.hpp>
#include <boost/geometry/strategies/compare.hpp>
#include <boost/geometry/policies/compare.hpp>
#include <boost/geometry/algorithms/detail/normalize.hpp>
#include <boost/geometry/algorithms/detail/envelope/transform_units.hpp>
#include <boost/geometry/algorithms/dispatch/expand.hpp>
#include <boost/geometry/core/tags.hpp>
// For backward compatibility
#include <boost/geometry/strategies/cartesian/expand_point.hpp>
#include <boost/geometry/strategies/spherical/expand_point.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace expand
{
template
<
typename StrategyLess, typename StrategyGreater,
std::size_t Dimension, std::size_t DimensionCount
>
struct point_loop
{
template <typename Box, typename Point, typename Strategy>
static inline void apply(Box& box, Point const& source, Strategy const& strategy)
{
typedef typename strategy::compare::detail::select_strategy
<
StrategyLess, 1, Point, Dimension
>::type less_type;
typedef typename strategy::compare::detail::select_strategy
<
StrategyGreater, -1, Point, Dimension
>::type greater_type;
typedef typename select_coordinate_type
<
Point, Box
>::type coordinate_type;
less_type less;
greater_type greater;
coordinate_type const coord = get<Dimension>(source);
if (less(coord, get<min_corner, Dimension>(box)))
{
set<min_corner, Dimension>(box, coord);
}
if (greater(coord, get<max_corner, Dimension>(box)))
{
set<max_corner, Dimension>(box, coord);
}
point_loop
<
StrategyLess, StrategyGreater, Dimension + 1, DimensionCount
>::apply(box, source, strategy);
}
};
template
<
typename StrategyLess,
typename StrategyGreater,
std::size_t DimensionCount
>
struct point_loop
<
StrategyLess, StrategyGreater, DimensionCount, DimensionCount
>
{
template <typename Box, typename Point, typename Strategy>
static inline void apply(Box&, Point const&, Strategy const&) {}
};
// implementation for the spherical equatorial and geographic coordinate systems
template
<
typename StrategyLess,
typename StrategyGreater,
std::size_t DimensionCount
>
struct point_loop_on_spheroid
{
template <typename Box, typename Point, typename Strategy>
static inline void apply(Box& box,
Point const& point,
Strategy const& strategy)
{
typedef typename point_type<Box>::type box_point_type;
typedef typename coordinate_type<Box>::type box_coordinate_type;
typedef math::detail::constants_on_spheroid
<
box_coordinate_type,
typename coordinate_system<Box>::type::units
> constants;
// normalize input point and input box
Point p_normalized = detail::return_normalized<Point>(point);
detail::normalize(box, box);
// transform input point to be of the same type as the box point
box_point_type box_point;
detail::envelope::transform_units(p_normalized, box_point);
box_coordinate_type p_lon = geometry::get<0>(box_point);
box_coordinate_type p_lat = geometry::get<1>(box_point);
typename coordinate_type<Box>::type
b_lon_min = geometry::get<min_corner, 0>(box),
b_lat_min = geometry::get<min_corner, 1>(box),
b_lon_max = geometry::get<max_corner, 0>(box),
b_lat_max = geometry::get<max_corner, 1>(box);
if (math::equals(math::abs(p_lat), constants::max_latitude()))
{
// the point of expansion is the either the north or the
// south pole; the only important coordinate here is the
// pole's latitude, as the longitude can be anything;
// we, thus, take into account the point's latitude only and return
geometry::set<min_corner, 1>(box, (std::min)(p_lat, b_lat_min));
geometry::set<max_corner, 1>(box, (std::max)(p_lat, b_lat_max));
return;
}
if (math::equals(b_lat_min, b_lat_max)
&& math::equals(math::abs(b_lat_min), constants::max_latitude()))
{
// the box degenerates to either the north or the south pole;
// the only important coordinate here is the pole's latitude,
// as the longitude can be anything;
// we thus take into account the box's latitude only and return
geometry::set<min_corner, 0>(box, p_lon);
geometry::set<min_corner, 1>(box, (std::min)(p_lat, b_lat_min));
geometry::set<max_corner, 0>(box, p_lon);
geometry::set<max_corner, 1>(box, (std::max)(p_lat, b_lat_max));
return;
}
// update latitudes
b_lat_min = (std::min)(b_lat_min, p_lat);
b_lat_max = (std::max)(b_lat_max, p_lat);
// update longitudes
if (math::smaller(p_lon, b_lon_min))
{
box_coordinate_type p_lon_shifted = p_lon + constants::period();
if (math::larger(p_lon_shifted, b_lon_max))
{
// here we could check using: ! math::larger(.., ..)
if (math::smaller(b_lon_min - p_lon, p_lon_shifted - b_lon_max))
{
b_lon_min = p_lon;
}
else
{
b_lon_max = p_lon_shifted;
}
}
}
else if (math::larger(p_lon, b_lon_max))
{
// in this case, and since p_lon is normalized in the range
// (-180, 180], we must have that b_lon_max <= 180
if (b_lon_min < 0
&& math::larger(p_lon - b_lon_max,
constants::period() - p_lon + b_lon_min))
{
b_lon_min = p_lon;
b_lon_max += constants::period();
}
else
{
b_lon_max = p_lon;
}
}
geometry::set<min_corner, 0>(box, b_lon_min);
geometry::set<min_corner, 1>(box, b_lat_min);
geometry::set<max_corner, 0>(box, b_lon_max);
geometry::set<max_corner, 1>(box, b_lat_max);
point_loop
<
StrategyLess, StrategyGreater, 2, DimensionCount
>::apply(box, point, strategy);
}
};
}} // namespace detail::expand
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
@@ -245,59 +43,23 @@ namespace dispatch
// Box + point -> new box containing also point
template
<
typename BoxOut, typename Point,
typename StrategyLess, typename StrategyGreater,
typename CSTagOut, typename CSTag
typename BoxOut, typename Point
>
struct expand
<
BoxOut, Point,
StrategyLess, StrategyGreater,
box_tag, point_tag,
CSTagOut, CSTag
> : detail::expand::point_loop
<
StrategyLess, StrategyGreater, 0, dimension<Point>::value
>
box_tag, point_tag
>
{
BOOST_MPL_ASSERT_MSG((boost::is_same<CSTagOut, CSTag>::value),
COORDINATE_SYSTEMS_MUST_BE_THE_SAME,
(types<CSTagOut, CSTag>()));
template <typename Strategy>
static inline void apply(BoxOut& box,
Point const& point,
Strategy const& )
{
Strategy::apply(box, point);
}
};
template
<
typename BoxOut, typename Point,
typename StrategyLess, typename StrategyGreater
>
struct expand
<
BoxOut, Point,
StrategyLess, StrategyGreater,
box_tag, point_tag,
spherical_equatorial_tag, spherical_equatorial_tag
> : detail::expand::point_loop_on_spheroid
<
StrategyLess, StrategyGreater, dimension<Point>::value
>
{};
template
<
typename BoxOut, typename Point,
typename StrategyLess, typename StrategyGreater
>
struct expand
<
BoxOut, Point,
StrategyLess, StrategyGreater,
box_tag, point_tag,
geographic_tag, geographic_tag
> : detail::expand::point_loop_on_spheroid
<
StrategyLess, StrategyGreater, dimension<Point>::value
>
{};
} // namespace dispatch

View File

@@ -5,11 +5,12 @@
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// Copyright (c) 2014-2015 Samuel Debionne, Grenoble, France.
// This file was modified by Oracle on 2015, 2016.
// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates.
// This file was modified by Oracle on 2015, 2016, 2017, 2018.
// Modifications copyright (c) 2015-2018, Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
@@ -18,111 +19,46 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_SEGMENT_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_SEGMENT_HPP
#include <boost/mpl/assert.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/detail/envelope/box.hpp>
#include <boost/geometry/algorithms/detail/envelope/range_of_boxes.hpp>
#include <boost/geometry/algorithms/detail/envelope/segment.hpp>
#include <boost/geometry/algorithms/detail/expand/indexed.hpp>
#include <boost/core/ignore_unused.hpp>
#include <boost/geometry/algorithms/dispatch/expand.hpp>
#include <boost/geometry/core/tags.hpp>
// For backward compatibility
#include <boost/geometry/strategies/cartesian/expand_segment.hpp>
#include <boost/geometry/strategies/geographic/expand_segment.hpp>
#include <boost/geometry/strategies/spherical/expand_segment.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace expand
{
struct segment
{
template <typename Box, typename Segment, typename Strategy>
static inline void apply(Box& box,
Segment const& segment,
Strategy const& strategy)
{
Box mbrs[2];
// compute the envelope of the segment
typename point_type<Segment>::type p[2];
detail::assign_point_from_index<0>(segment, p[0]);
detail::assign_point_from_index<1>(segment, p[1]);
detail::envelope::envelope_segment
<
dimension<Segment>::value
>::apply(p[0], p[1], mbrs[0], strategy);
// normalize the box
detail::envelope::envelope_box_on_spheroid::apply(box, mbrs[1], strategy);
// compute the envelope of the two boxes
detail::envelope::envelope_range_of_boxes::apply(mbrs, box, strategy);
}
};
}} // namespace detail::expand
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template
<
typename Box, typename Segment,
typename StrategyLess, typename StrategyGreater,
typename CSTagOut, typename CSTag
typename Box, typename Segment
>
struct expand
<
Box, Segment,
StrategyLess, StrategyGreater,
box_tag, segment_tag,
CSTagOut, CSTag
> : detail::expand::expand_indexed
<
0, dimension<Segment>::value, StrategyLess, StrategyGreater
>
box_tag, segment_tag
>
{
BOOST_MPL_ASSERT_MSG((boost::is_same<CSTagOut, CSTag>::value),
COORDINATE_SYSTEMS_MUST_BE_THE_SAME,
(types<CSTagOut, CSTag>()));
template <typename Strategy>
static inline void apply(Box& box,
Segment const& segment,
Strategy const& strategy)
{
boost::ignore_unused(strategy);
strategy.apply(box, segment);
}
};
template
<
typename Box, typename Segment,
typename StrategyLess, typename StrategyGreater
>
struct expand
<
Box, Segment,
StrategyLess, StrategyGreater,
box_tag, segment_tag,
spherical_equatorial_tag, spherical_equatorial_tag
> : detail::expand::segment
{};
template
<
typename Box, typename Segment,
typename StrategyLess, typename StrategyGreater
>
struct expand
<
Box, Segment,
StrategyLess, StrategyGreater,
box_tag, segment_tag,
geographic_tag, geographic_tag
> : detail::expand::segment
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH

View File

@@ -3,7 +3,12 @@
// Copyright (c) 2007-2013 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2013 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2013 Mateusz Loskot, London, UK.
// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
// Copyright (c) 2013-2017 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2017, 2018.
// Modifications copyright (c) 2017-2018 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
@@ -20,6 +25,7 @@
#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/point_order.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/ring_type.hpp>
#include <boost/geometry/core/tags.hpp>
@@ -117,12 +123,6 @@ struct extreme_points_on_ring
typedef typename boost::range_iterator<Ring const>::type range_iterator;
typedef typename geometry::point_type<Ring>::type point_type;
typedef typename geometry::strategy::side::services::default_strategy
<
typename geometry::cs_tag<point_type>::type
>::type side_strategy;
template <typename CirclingIterator, typename Points>
static inline bool extend(CirclingIterator& it,
std::size_t n,
@@ -214,10 +214,11 @@ struct extreme_points_on_ring
return true;
}
template <typename Extremes, typename Intruders, typename CirclingIterator>
template <typename Extremes, typename Intruders, typename CirclingIterator, typename SideStrategy>
static inline void get_intruders(Ring const& ring, CirclingIterator left, CirclingIterator right,
Extremes const& extremes,
Intruders& intruders)
Intruders& intruders,
SideStrategy const& strategy)
{
if (boost::size(extremes) < 3)
{
@@ -238,8 +239,8 @@ struct extreme_points_on_ring
if (coordinate > min_value && other_coordinate > other_min && other_coordinate < other_max)
{
int const factor = geometry::point_order<Ring>::value == geometry::clockwise ? 1 : -1;
int const first_side = side_strategy::apply(*right, extremes.front(), *(extremes.begin() + 1)) * factor;
int const last_side = side_strategy::apply(*right, *(extremes.rbegin() + 1), extremes.back()) * factor;
int const first_side = strategy.apply(*right, extremes.front(), *(extremes.begin() + 1)) * factor;
int const last_side = strategy.apply(*right, *(extremes.rbegin() + 1), extremes.back()) * factor;
// If not lying left from any of the extemes side
if (first_side != 1 && last_side != 1)
@@ -263,10 +264,11 @@ struct extreme_points_on_ring
}
}
template <typename Extremes, typename Intruders>
template <typename Extremes, typename Intruders, typename SideStrategy>
static inline void get_intruders(Ring const& ring,
Extremes const& extremes,
Intruders& intruders)
Intruders& intruders,
SideStrategy const& strategy)
{
std::size_t const n = boost::size(ring);
if (n >= 3)
@@ -275,12 +277,12 @@ struct extreme_points_on_ring
geometry::ever_circling_range_iterator<Ring const> right(ring);
++right;
get_intruders(ring, left, right, extremes, intruders);
get_intruders(ring, left, right, extremes, intruders, strategy);
}
}
template <typename Iterator>
static inline bool right_turn(Ring const& ring, Iterator it)
template <typename Iterator, typename SideStrategy>
static inline bool right_turn(Ring const& ring, Iterator it, SideStrategy const& strategy)
{
typename std::iterator_traits<Iterator>::difference_type const index
= std::distance(boost::begin(ring), it);
@@ -295,8 +297,8 @@ struct extreme_points_on_ring
}
int const factor = geometry::point_order<Ring>::value == geometry::clockwise ? 1 : -1;
int const first_side = side_strategy::apply(*(right - 1), *right, *left) * factor;
int const last_side = side_strategy::apply(*left, *(left + 1), *right) * factor;
int const first_side = strategy.apply(*(right - 1), *right, *left) * factor;
int const last_side = strategy.apply(*left, *(left + 1), *right) * factor;
//std::cout << "Candidate at " << geometry::wkt(*it) << " first=" << first_side << " last=" << last_side << std::endl;
@@ -306,8 +308,11 @@ struct extreme_points_on_ring
// Gets the extreme segments (top point plus neighbouring points), plus intruders, if any, on the same ring
template <typename Extremes, typename Intruders>
static inline bool apply(Ring const& ring, Extremes& extremes, Intruders& intruders)
template <typename Extremes, typename Intruders, typename SideStrategy>
static inline bool apply(Ring const& ring,
Extremes& extremes,
Intruders& intruders,
SideStrategy const& strategy)
{
std::size_t const n = boost::size(ring);
if (n < 3)
@@ -321,7 +326,7 @@ struct extreme_points_on_ring
compare<Dimension> smaller;
for (range_iterator it = max_it + 1; it != boost::end(ring); ++it)
{
if (smaller(*max_it, *it) && right_turn(ring, it))
if (smaller(*max_it, *it) && right_turn(ring, it, strategy))
{
max_it = it;
}
@@ -365,7 +370,7 @@ struct extreme_points_on_ring
std::copy(points.begin(), points.end(), std::back_inserter(extremes));
get_intruders(ring, left, right, extremes, intruders);
get_intruders(ring, left, right, extremes, intruders, strategy);
return true;
}
@@ -403,8 +408,9 @@ struct extreme_points<Ring, Dimension, ring_tag>
template<typename Polygon, std::size_t Dimension>
struct extreme_points<Polygon, Dimension, polygon_tag>
{
template <typename Extremes, typename Intruders>
static inline bool apply(Polygon const& polygon, Extremes& extremes, Intruders& intruders)
template <typename Extremes, typename Intruders, typename SideStrategy>
static inline bool apply(Polygon const& polygon, Extremes& extremes, Intruders& intruders,
SideStrategy const& strategy)
{
typedef typename geometry::ring_type<Polygon>::type ring_type;
typedef detail::extreme_points::extreme_points_on_ring
@@ -412,7 +418,8 @@ struct extreme_points<Polygon, Dimension, polygon_tag>
ring_type, Dimension
> ring_implementation;
if (! ring_implementation::apply(geometry::exterior_ring(polygon), extremes, intruders))
if (! ring_implementation::apply(geometry::exterior_ring(polygon),
extremes, intruders, strategy))
{
return false;
}
@@ -423,7 +430,7 @@ struct extreme_points<Polygon, Dimension, polygon_tag>
for (typename detail::interior_iterator<Polygon const>::type
it = boost::begin(rings); it != boost::end(rings); ++it)
{
ring_implementation::get_intruders(*it, extremes, intruders);
ring_implementation::get_intruders(*it, extremes, intruders, strategy);
}
return true;
@@ -433,8 +440,9 @@ struct extreme_points<Polygon, Dimension, polygon_tag>
template<typename Box>
struct extreme_points<Box, 1, box_tag>
{
template <typename Extremes, typename Intruders>
static inline bool apply(Box const& box, Extremes& extremes, Intruders& )
template <typename Extremes, typename Intruders, typename SideStrategy>
static inline bool apply(Box const& box, Extremes& extremes, Intruders& ,
SideStrategy const& )
{
extremes.resize(4);
geometry::detail::assign_box_corners_oriented<false>(box, extremes);
@@ -446,8 +454,9 @@ struct extreme_points<Box, 1, box_tag>
template<typename Box>
struct extreme_points<Box, 0, box_tag>
{
template <typename Extremes, typename Intruders>
static inline bool apply(Box const& box, Extremes& extremes, Intruders& )
template <typename Extremes, typename Intruders, typename SideStrategy>
static inline bool apply(Box const& box, Extremes& extremes, Intruders& ,
SideStrategy const& )
{
extremes.resize(4);
geometry::detail::assign_box_corners_oriented<false>(box, extremes);
@@ -460,8 +469,9 @@ struct extreme_points<Box, 0, box_tag>
template<typename MultiPolygon, std::size_t Dimension>
struct extreme_points<MultiPolygon, Dimension, multi_polygon_tag>
{
template <typename Extremes, typename Intruders>
static inline bool apply(MultiPolygon const& multi, Extremes& extremes, Intruders& intruders)
template <typename Extremes, typename Intruders, typename SideStrategy>
static inline bool apply(MultiPolygon const& multi, Extremes& extremes,
Intruders& intruders, SideStrategy const& strategy)
{
// Get one for the very first polygon, that is (for the moment) enough.
// It is not guaranteed the "extreme" then, but for the current purpose
@@ -473,7 +483,7 @@ struct extreme_points<MultiPolygon, Dimension, multi_polygon_tag>
typename boost::range_value<MultiPolygon const>::type,
Dimension,
polygon_tag
>::apply(*boost::begin(multi), extremes, intruders);
>::apply(*boost::begin(multi), extremes, intruders, strategy);
}
return false;
@@ -489,8 +499,18 @@ struct extreme_points<MultiPolygon, Dimension, multi_polygon_tag>
for Edge=0 in dimension 0, the right side)
\note We could specify a strategy (less/greater) to get bottom/left side too. However, until now we don't need that.
*/
template <std::size_t Edge, typename Geometry, typename Extremes, typename Intruders>
inline bool extreme_points(Geometry const& geometry, Extremes& extremes, Intruders& intruders)
template
<
std::size_t Edge,
typename Geometry,
typename Extremes,
typename Intruders,
typename SideStrategy
>
inline bool extreme_points(Geometry const& geometry,
Extremes& extremes,
Intruders& intruders,
SideStrategy const& strategy)
{
concepts::check<Geometry const>();
@@ -509,10 +529,32 @@ inline bool extreme_points(Geometry const& geometry, Extremes& extremes, Intrude
const
>();
return dispatch::extreme_points<Geometry, Edge>::apply(geometry, extremes, intruders);
return dispatch::extreme_points
<
Geometry,
Edge
>::apply(geometry, extremes, intruders, strategy);
}
template
<
std::size_t Edge,
typename Geometry,
typename Extremes,
typename Intruders
>
inline bool extreme_points(Geometry const& geometry,
Extremes& extremes,
Intruders& intruders)
{
typedef typename strategy::side::services::default_strategy
<
typename cs_tag<Geometry>::type
>::type strategy_type;
return geometry::extreme_points<Edge>(geometry,extremes, intruders, strategy_type());
}
}} // namespace boost::geometry

View File

@@ -2,6 +2,11 @@
// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2017, 2018.
// Modifications copyright (c) 2017-2018, 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)
@@ -9,11 +14,14 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_GET_LEFT_TURNS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_GET_LEFT_TURNS_HPP
#include <set>
#include <vector>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/arithmetic/arithmetic.hpp>
#include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
#include <boost/geometry/arithmetic/arithmetic.hpp>
#include <boost/geometry/iterators/closing_iterator.hpp>
#include <boost/geometry/iterators/ever_circling_iterator.hpp>
#include <boost/geometry/strategies/side.hpp>
@@ -60,17 +68,14 @@ inline int squared_length(Vector const& vector)
}
template <typename Point>
template <typename Point, typename SideStrategy>
struct angle_less
{
typedef Point vector_type;
typedef typename strategy::side::services::default_strategy
<
typename cs_tag<Point>::type
>::type side_strategy_type;
angle_less(Point const& origin)
angle_less(Point const& origin, SideStrategy const& strategy)
: m_origin(origin)
, m_strategy(strategy)
{}
template <typename Angle>
@@ -89,8 +94,7 @@ struct angle_less
return quadrant_p < quadrant_q;
}
// Same quadrant, check if p is located left of q
int const side = side_strategy_type::apply(m_origin, q.point,
p.point);
int const side = m_strategy.apply(m_origin, q.point, p.point);
if (side != 0)
{
return side == 1;
@@ -114,19 +118,17 @@ struct angle_less
private:
Point m_origin;
SideStrategy m_strategy;
};
template <typename Point>
template <typename Point, typename SideStrategy>
struct angle_equal_to
{
typedef Point vector_type;
typedef typename strategy::side::services::default_strategy
<
typename cs_tag<Point>::type
>::type side_strategy_type;
inline angle_equal_to(Point const& origin)
inline angle_equal_to(Point const& origin, SideStrategy const& strategy)
: m_origin(origin)
, m_strategy(strategy)
{}
template <typename Angle>
@@ -143,13 +145,13 @@ struct angle_equal_to
return false;
}
// Same quadrant, check if p/q are collinear
int const side = side_strategy_type::apply(m_origin, q.point,
p.point);
int const side = m_strategy.apply(m_origin, q.point, p.point);
return side == 0;
}
private:
Point m_origin;
SideStrategy m_strategy;
};
template <typename AngleCollection, typename Turns>
@@ -193,13 +195,14 @@ inline void get_left_turns(AngleCollection const& sorted_angles,
//! Returns the number of clusters
template <typename Point, typename AngleCollection>
inline std::size_t assign_cluster_indices(AngleCollection& sorted, Point const& origin)
template <typename Point, typename AngleCollection, typename SideStrategy>
inline std::size_t assign_cluster_indices(AngleCollection& sorted, Point const& origin,
SideStrategy const& strategy)
{
// Assign same cluster_index for all turns in same direction
BOOST_GEOMETRY_ASSERT(boost::size(sorted) >= 4u);
angle_equal_to<Point> comparator(origin);
angle_equal_to<Point, SideStrategy> comparator(origin, strategy);
typename boost::range_iterator<AngleCollection>::type it = sorted.begin();
std::size_t cluster_index = 0;

View File

@@ -5,6 +5,11 @@
// Copyright (c) 2014 Mateusz Loskot, London, UK.
// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2018.
// Modifications copyright (c) 2018, 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)
@@ -12,10 +17,10 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_GET_MAX_SIZE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_GET_MAX_SIZE_HPP
#include <cstddef>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/util/math.hpp>
namespace boost { namespace geometry

View File

@@ -81,7 +81,11 @@ inline bool has_self_intersections(Geometry const& geometry,
std::deque<turn_info> turns;
detail::disjoint::disjoint_interrupt_policy policy;
geometry::self_turns<detail::overlay::assign_null_policy>(geometry, strategy, robust_policy, turns, policy);
detail::self_get_turn_points::self_turns
<
false,
detail::overlay::assign_null_policy
>(geometry, strategy, robust_policy, turns, policy, 0, false);
#ifdef BOOST_GEOMETRY_DEBUG_HAS_SELF_INTERSECTIONS
bool first = true;

View File

@@ -237,7 +237,7 @@ struct intersection_insert
OverlayType,
Reverse1, Reverse2, ReverseOut,
multi_linestring_tag, multi_linestring_tag, point_tag,
false, false, false
linear_tag, linear_tag, pointlike_tag
> : detail::intersection::intersection_multi_linestring_multi_linestring_point
<
GeometryOut
@@ -259,7 +259,7 @@ struct intersection_insert
OverlayType,
Reverse1, Reverse2, ReverseOut,
linestring_tag, multi_linestring_tag, point_tag,
false, false, false
linear_tag, linear_tag, pointlike_tag
> : detail::intersection::intersection_linestring_multi_linestring_point
<
GeometryOut
@@ -281,7 +281,7 @@ struct intersection_insert
OverlayType,
Reverse1, Reverse2, ReverseOut,
multi_linestring_tag, box_tag, linestring_tag,
false, true, false
linear_tag, areal_tag, linear_tag
> : detail::intersection::clip_multi_linestring
<
GeometryOut
@@ -303,7 +303,7 @@ struct intersection_insert
OverlayType,
ReverseLinestring, ReverseMultiPolygon, ReverseOut,
linestring_tag, multi_polygon_tag, linestring_tag,
false, true, false
linear_tag, areal_tag, linear_tag
> : detail::intersection::intersection_of_linestring_with_areal
<
ReverseMultiPolygon,
@@ -329,7 +329,7 @@ struct intersection_insert
OverlayType,
ReversePolygon, ReverseMultiLinestring, ReverseOut,
polygon_tag, multi_linestring_tag, linestring_tag,
true, false, false
areal_tag, linear_tag, linear_tag
> : detail::intersection::intersection_of_areal_with_multi_linestring
<
ReversePolygon,
@@ -353,7 +353,7 @@ struct intersection_insert
OverlayType,
ReverseMultiLinestring, ReverseRing, ReverseOut,
multi_linestring_tag, ring_tag, linestring_tag,
false, true, false
linear_tag, areal_tag, linear_tag
> : detail::intersection::intersection_of_multi_linestring_with_areal
<
ReverseRing,
@@ -376,7 +376,7 @@ struct intersection_insert
OverlayType,
ReverseMultiLinestring, ReverseRing, ReverseOut,
multi_linestring_tag, polygon_tag, linestring_tag,
false, true, false
linear_tag, areal_tag, linear_tag
> : detail::intersection::intersection_of_multi_linestring_with_areal
<
ReverseRing,
@@ -401,7 +401,7 @@ struct intersection_insert
OverlayType,
ReverseMultiLinestring, ReverseMultiPolygon, ReverseOut,
multi_linestring_tag, multi_polygon_tag, linestring_tag,
false, true, false
linear_tag, areal_tag, linear_tag
> : detail::intersection::intersection_of_multi_linestring_with_areal
<
ReverseMultiPolygon,

View File

@@ -0,0 +1,89 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2013-2017.
// Modifications copyright (c) 2013-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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_INTERSECTS_IMPLEMENTATION_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTS_IMPLEMENTATION_HPP
#include <deque>
#include <boost/geometry/algorithms/detail/intersects/interface.hpp>
#include <boost/geometry/algorithms/detail/disjoint/implementation.hpp>
#include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp>
#include <boost/geometry/policies/disjoint_interrupt_policy.hpp>
#include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
#include <boost/geometry/strategies/relate.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace intersects
{
template <typename Geometry>
struct self_intersects
{
static bool apply(Geometry const& geometry)
{
concepts::check<Geometry const>();
typedef typename geometry::point_type<Geometry>::type point_type;
typedef typename strategy::relate::services::default_strategy
<
Geometry, Geometry
>::type strategy_type;
typedef detail::no_rescale_policy rescale_policy_type;
typedef detail::overlay::turn_info
<
point_type,
typename segment_ratio_type<point_type, rescale_policy_type>::type
> turn_info;
std::deque<turn_info> turns;
typedef detail::overlay::get_turn_info
<
detail::overlay::assign_null_policy
> turn_policy;
strategy_type strategy;
rescale_policy_type robust_policy;
detail::disjoint::disjoint_interrupt_policy policy;
// TODO: skip_adjacent should be set to false
detail::self_get_turn_points::get_turns
<
false, turn_policy
>::apply(geometry, strategy, robust_policy, turns, policy, 0, true);
return policy.has_intersections;
}
};
}} // namespace detail::intersects
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTS_IMPLEMENTATION_HPP

View File

@@ -0,0 +1,115 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2013-2017.
// Modifications copyright (c) 2013-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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_INTERSECTS_INTERFACE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTS_INTERFACE_HPP
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/algorithms/detail/disjoint/interface.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace intersects
{
// Forward declaration
template <typename Geometry>
struct self_intersects;
}} // namespace detail::intersects
#endif // DOXYGEN_NO_DETAIL
/*!
\brief \brief_check{has at least one intersection (crossing or self-tangency)}
\note This function can be called for one geometry (self-intersection) and
also for two geometries (intersection)
\ingroup intersects
\tparam Geometry \tparam_geometry
\param geometry \param_geometry
\return \return_check{is self-intersecting}
\qbk{distinguish,one geometry}
\qbk{[def __one_parameter__]}
\qbk{[include reference/algorithms/intersects.qbk]}
*/
template <typename Geometry>
inline bool intersects(Geometry const& geometry)
{
return detail::intersects::self_intersects<Geometry>::apply(geometry);
}
/*!
\brief \brief_check2{have at least one intersection}
\ingroup intersects
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\tparam Strategy \tparam_strategy{Intersects}
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\param strategy \param_strategy{intersects}
\return \return_check2{intersect each other}
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/intersects.qbk]}
*/
template <typename Geometry1, typename Geometry2, typename Strategy>
inline bool intersects(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
concepts::check<Geometry1 const>();
concepts::check<Geometry2 const>();
return ! geometry::disjoint(geometry1, geometry2, strategy);
}
/*!
\brief \brief_check2{have at least one intersection}
\ingroup intersects
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\return \return_check2{intersect each other}
\qbk{distinguish,two geometries}
\qbk{[include reference/algorithms/intersects.qbk]}
*/
template <typename Geometry1, typename Geometry2>
inline bool intersects(Geometry1 const& geometry1, Geometry2 const& geometry2)
{
concepts::check<Geometry1 const>();
concepts::check<Geometry2 const>();
return ! geometry::disjoint(geometry1, geometry2);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTS_INTERFACE_HPP

View File

@@ -217,14 +217,15 @@ inline bool has_self_intersections(Linear const& linear, Strategy const& strateg
is_acceptable_turn<Linear>
> interrupt_policy(predicate);
// TODO: skip_adjacent should be set to false
detail::self_get_turn_points::get_turns
<
turn_policy
false, turn_policy
>::apply(linear,
strategy,
detail::no_rescale_policy(),
turns,
interrupt_policy);
interrupt_policy, 0, true);
detail::is_valid::debug_print_turns(turns.begin(), turns.end());
debug_print_boundary_points(linear);
@@ -236,7 +237,9 @@ inline bool has_self_intersections(Linear const& linear, Strategy const& strateg
template <typename Linestring, bool CheckSelfIntersections = true>
struct is_simple_linestring
{
static inline bool apply(Linestring const& linestring)
template <typename Strategy>
static inline bool apply(Linestring const& linestring,
Strategy const& strategy)
{
simplicity_failure_policy policy;
return ! boost::empty(linestring)
@@ -247,7 +250,7 @@ struct is_simple_linestring
&& ! detail::is_valid::has_spikes
<
Linestring, closed
>::apply(linestring, policy);
>::apply(linestring, policy, strategy.get_side_strategy());
}
};
@@ -258,7 +261,10 @@ struct is_simple_linestring<Linestring, true>
static inline bool apply(Linestring const& linestring,
Strategy const& strategy)
{
return is_simple_linestring<Linestring, false>::apply(linestring)
return is_simple_linestring
<
Linestring, false
>::apply(linestring, strategy)
&& ! has_self_intersections(linestring, strategy);
}
};
@@ -267,23 +273,44 @@ struct is_simple_linestring<Linestring, true>
template <typename MultiLinestring>
struct is_simple_multilinestring
{
private:
template <typename Strategy>
struct per_linestring
{
per_linestring(Strategy const& strategy)
: m_strategy(strategy)
{}
template <typename Linestring>
inline bool apply(Linestring const& linestring) const
{
return detail::is_simple::is_simple_linestring
<
Linestring,
false // do not compute self-intersections
>::apply(linestring, m_strategy);
}
Strategy const& m_strategy;
};
public:
template <typename Strategy>
static inline bool apply(MultiLinestring const& multilinestring,
Strategy const& strategy)
{
typedef per_linestring<Strategy> per_ls;
// check each of the linestrings for simplicity
// but do not compute self-intersections yet; these will be
// computed for the entire multilinestring
if ( ! detail::check_iterator_range
<
is_simple_linestring
<
typename boost::range_value<MultiLinestring>::type,
false // do not compute self-intersections
>,
per_ls, // do not compute self-intersections
true // allow empty multilinestring
>::apply(boost::begin(multilinestring),
boost::end(multilinestring))
boost::end(multilinestring),
per_ls(strategy))
)
{
return false;

View File

@@ -1,8 +1,9 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014, Oracle and/or its affiliates.
// Copyright (c) 2014, 2018, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
@@ -19,6 +20,7 @@
#include <boost/core/addressof.hpp>
#include <boost/geometry/algorithms/detail/signed_size_type.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/policies/compare.hpp>
@@ -221,9 +223,11 @@ public:
return false;
}
#ifdef BOOST_GEOMETRY_TEST_DEBUG
template <typename OStream, typename TP>
friend inline
void debug_print_complement_graph(OStream&, complement_graph<TP> const&);
#endif // BOOST_GEOMETRY_TEST_DEBUG
private:
std::size_t m_num_rings, m_num_turns;

View File

@@ -1,8 +1,9 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014, Oracle and/or its affiliates.
// Copyright (c) 2014, 2018, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
@@ -14,6 +15,8 @@
#include <iostream>
#endif
#include <boost/geometry/algorithms/detail/is_valid/complement_graph.hpp>
namespace boost { namespace geometry
{

View File

@@ -1,8 +1,9 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014, Oracle and/or its affiliates.
// Copyright (c) 2014, 2018, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
@@ -12,11 +13,10 @@
#ifdef GEOMETRY_TEST_DEBUG
#include <iostream>
#endif
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
#endif
namespace boost { namespace geometry
{

View File

@@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014-2015, Oracle and/or its affiliates.
// Copyright (c) 2014-2018, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -15,15 +15,17 @@
#include <boost/type_traits/is_floating_point.hpp>
#include <boost/geometry/algorithms/detail/check_iterator_range.hpp>
#include <boost/geometry/algorithms/validity_failure_type.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/util/has_non_finite_coordinate.hpp>
#include <boost/geometry/iterators/point_iterator.hpp>
#include <boost/geometry/views/detail/indexed_point_view.hpp>
#include <boost/geometry/algorithms/detail/check_iterator_range.hpp>
#include <boost/geometry/views/detail/indexed_point_view.hpp>
#include <boost/geometry/util/has_non_finite_coordinate.hpp>
namespace boost { namespace geometry
{

View File

@@ -1,8 +1,9 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014-2015, Oracle and/or its affiliates.
// Copyright (c) 2014-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
@@ -91,8 +92,9 @@ struct has_spikes
return std::find_if(second, last, not_equal(*first));
}
template <typename VisitPolicy>
static inline bool apply(Range const& range, VisitPolicy& visitor)
template <typename VisitPolicy, typename SideStrategy>
static inline bool apply(Range const& range, VisitPolicy& visitor,
SideStrategy const& strategy)
{
boost::ignore_unused(visitor);
@@ -124,9 +126,11 @@ struct has_spikes
while (next != boost::end(view))
{
if ( geometry::detail::point_is_spike_or_equal(*prev,
*next,
*cur) )
// Verify spike. TODO: this is a reverse order from expected
// in is_spike_or_equal, but this order calls the side
// strategy in the way to correctly detect the spikes,
// also in geographic cases going over the pole
if (detail::is_spike_or_equal(*next, *cur, *prev, strategy))
{
return
! visitor.template apply<failure_spikes>(is_linear, *cur);
@@ -146,7 +150,7 @@ struct has_spikes
boost::rend(view));
iterator next = find_different_from_first(cur, boost::end(view));
if (detail::point_is_spike_or_equal(*prev, *next, *cur))
if (detail::is_spike_or_equal(*next, *cur, *prev, strategy))
{
return
! visitor.template apply<failure_spikes>(is_linear, *cur);

View File

@@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014-2017, Oracle and/or its affiliates.
// Copyright (c) 2014-2018, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -16,6 +16,12 @@
#include <boost/core/ignore_unused.hpp>
#include <boost/range.hpp>
#include <boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp>
#include <boost/geometry/algorithms/validity_failure_type.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/core/point_type.hpp>
@@ -23,12 +29,6 @@
#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
#include <boost/geometry/policies/robustness/get_rescale_policy.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp>
#include <boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp>
namespace boost { namespace geometry
{
@@ -86,7 +86,7 @@ public:
IsAcceptableTurn
> interrupt_policy;
geometry::self_turns<turn_policy>(geometry,
detail::self_get_turn_points::self_turns<false, turn_policy>(geometry,
strategy,
robust_policy,
turns,

View File

@@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Boost.Geometry
// Copyright (c) 2014-2017, Oracle and/or its affiliates.
// Copyright (c) 2014-2018, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -18,9 +18,9 @@
#include <boost/variant/static_visitor.hpp>
#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/algorithms/dispatch/is_valid.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/policies/is_valid/default_policy.hpp>
#include <boost/geometry/policies/is_valid/failing_reason_policy.hpp>
#include <boost/geometry/policies/is_valid/failure_type_policy.hpp>

View File

@@ -138,10 +138,17 @@ public:
}
operation_type const op = acceptable_operation<MultiPolygon>::value;
if ( base::check_turn(turn, method_touch_interior, op)
|| base::check_turn(turn, method_touch, op))
{
return true;
}
return base::check_turn(turn, method_touch_interior, op)
|| base::check_turn(turn, method_touch, op)
;
// Turn is acceptable only in case of a touch(interior) and both lines
// (polygons) do not cross
return (turn.method == method_touch
|| turn.method == method_touch_interior)
&& turn.touch_only;
}
};

View File

@@ -43,9 +43,10 @@ namespace detail { namespace is_valid
template <typename Linestring>
struct is_valid_linestring
{
template <typename VisitPolicy>
template <typename VisitPolicy, typename Strategy>
static inline bool apply(Linestring const& linestring,
VisitPolicy& visitor)
VisitPolicy& visitor,
Strategy const& strategy)
{
if (has_invalid_coordinate<Linestring>::apply(linestring, visitor))
{
@@ -75,15 +76,12 @@ struct is_valid_linestring
{
return visitor.template apply<no_failure>();
}
return ! has_spikes<Linestring, closed>::apply(linestring, visitor);
}
template <typename VisitPolicy, typename Strategy>
static inline bool apply(Linestring const& linestring,
VisitPolicy& visitor,
Strategy const&)
{
return apply(linestring, visitor);
return ! has_spikes
<
Linestring, closed
>::apply(linestring, visitor,
strategy.get_side_strategy());
}
};
@@ -132,10 +130,13 @@ class is_valid
>
{
private:
template <typename VisitPolicy>
template <typename VisitPolicy, typename Strategy>
struct per_linestring
{
per_linestring(VisitPolicy& policy) : m_policy(policy) {}
per_linestring(VisitPolicy& policy, Strategy const& strategy)
: m_policy(policy)
, m_strategy(strategy)
{}
template <typename Linestring>
inline bool apply(Linestring const& linestring) const
@@ -143,17 +144,18 @@ private:
return detail::is_valid::is_valid_linestring
<
Linestring
>::apply(linestring, m_policy);
>::apply(linestring, m_policy, m_strategy);
}
VisitPolicy& m_policy;
Strategy const& m_strategy;
};
public:
template <typename VisitPolicy, typename Strategy>
static inline bool apply(MultiLinestring const& multilinestring,
VisitPolicy& visitor,
Strategy const&)
Strategy const& strategy)
{
if (BOOST_GEOMETRY_CONDITION(
AllowEmptyMultiGeometries && boost::empty(multilinestring)))
@@ -161,13 +163,15 @@ public:
return visitor.template apply<no_failure>();
}
typedef per_linestring<VisitPolicy, Strategy> per_ls;
return detail::check_iterator_range
<
per_linestring<VisitPolicy>,
per_ls,
false // do not check for empty multilinestring (done above)
>::apply(boost::begin(multilinestring),
boost::end(multilinestring),
per_linestring<VisitPolicy>(visitor));
per_ls(visitor, strategy));
}
};

View File

@@ -76,45 +76,59 @@ private:
<
typename PolygonIterator,
typename TurnIterator,
typename VisitPolicy
typename VisitPolicy,
typename Strategy
>
static inline
bool are_polygon_interiors_disjoint(PolygonIterator polygons_first,
PolygonIterator polygons_beyond,
TurnIterator turns_first,
TurnIterator turns_beyond,
VisitPolicy& visitor)
VisitPolicy& visitor,
Strategy const& strategy)
{
boost::ignore_unused(visitor);
// collect all polygons that have turns
// collect all polygons that have crossing turns
std::set<signed_size_type> multi_indices;
for (TurnIterator tit = turns_first; tit != turns_beyond; ++tit)
{
multi_indices.insert(tit->operations[0].seg_id.multi_index);
multi_indices.insert(tit->operations[1].seg_id.multi_index);
if (! tit->touch_only)
{
multi_indices.insert(tit->operations[0].seg_id.multi_index);
multi_indices.insert(tit->operations[1].seg_id.multi_index);
}
}
typedef geometry::model::box<typename point_type<MultiPolygon>::type> box_type;
typedef typename base::template partition_item<PolygonIterator, box_type> item_type;
// put polygon iterators without turns in a vector
std::vector<PolygonIterator> polygon_iterators;
std::vector<item_type> polygon_iterators;
signed_size_type multi_index = 0;
for (PolygonIterator it = polygons_first; it != polygons_beyond;
++it, ++multi_index)
{
if (multi_indices.find(multi_index) == multi_indices.end())
{
polygon_iterators.push_back(it);
polygon_iterators.push_back(item_type(it));
}
}
typename base::item_visitor_type item_visitor;
// prepare strategies
typedef typename Strategy::envelope_strategy_type envelope_strategy_type;
envelope_strategy_type const envelope_strategy
= strategy.get_envelope_strategy();
// call partition to check if polygons are disjoint from each other
typename base::template item_visitor_type<Strategy> item_visitor(strategy);
geometry::partition
<
geometry::model::box<typename point_type<MultiPolygon>::type>
>::apply(polygon_iterators, item_visitor,
typename base::expand_box(),
typename base::overlaps_box());
typename base::template expand_box<envelope_strategy_type>(envelope_strategy),
typename base::template overlaps_box<envelope_strategy_type>(envelope_strategy));
if (item_visitor.items_overlap)
{
@@ -155,13 +169,15 @@ private:
<
typename PolygonIterator,
typename TurnIterator,
typename VisitPolicy
typename VisitPolicy,
typename Strategy
>
static inline bool apply(PolygonIterator polygons_first,
PolygonIterator polygons_beyond,
TurnIterator turns_first,
TurnIterator turns_beyond,
VisitPolicy& visitor)
VisitPolicy& visitor,
Strategy const& strategy)
{
signed_size_type multi_index = 0;
for (PolygonIterator it = polygons_first; it != polygons_beyond;
@@ -185,7 +201,8 @@ private:
if (! Predicate::apply(*it,
filtered_turns_first,
filtered_turns_beyond,
visitor))
visitor,
strategy))
{
return false;
}
@@ -200,19 +217,21 @@ private:
<
typename PolygonIterator,
typename TurnIterator,
typename VisitPolicy
typename VisitPolicy,
typename Strategy
>
static inline bool have_holes_inside(PolygonIterator polygons_first,
PolygonIterator polygons_beyond,
TurnIterator turns_first,
TurnIterator turns_beyond,
VisitPolicy& visitor)
VisitPolicy& visitor,
Strategy const& strategy)
{
return has_property_per_polygon
<
typename base::has_holes_inside
>::apply(polygons_first, polygons_beyond,
turns_first, turns_beyond, visitor);
turns_first, turns_beyond, visitor, strategy);
}
@@ -221,19 +240,21 @@ private:
<
typename PolygonIterator,
typename TurnIterator,
typename VisitPolicy
typename VisitPolicy,
typename Strategy
>
static inline bool have_connected_interior(PolygonIterator polygons_first,
PolygonIterator polygons_beyond,
TurnIterator turns_first,
TurnIterator turns_beyond,
VisitPolicy& visitor)
VisitPolicy& visitor,
Strategy const& strategy)
{
return has_property_per_polygon
<
typename base::has_connected_interior
>::apply(polygons_first, polygons_beyond,
turns_first, turns_beyond, visitor);
turns_first, turns_beyond, visitor, strategy);
}
@@ -307,7 +328,8 @@ public:
boost::end(multipolygon),
turns.begin(),
turns.end(),
visitor))
visitor,
strategy))
{
return false;
}
@@ -320,7 +342,8 @@ public:
boost::end(multipolygon),
turns.begin(),
turns.end(),
visitor))
visitor,
strategy))
{
return false;
}
@@ -332,7 +355,8 @@ public:
boost::end(multipolygon),
turns.begin(),
turns.end(),
visitor);
visitor,
strategy);
}
};

View File

@@ -1,6 +1,8 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014-2017, Oracle and/or its affiliates.
// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
// Copyright (c) 2014-2018, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -43,6 +45,7 @@
#include <boost/geometry/algorithms/expand.hpp>
#include <boost/geometry/algorithms/num_interior_rings.hpp>
#include <boost/geometry/algorithms/validity_failure_type.hpp>
#include <boost/geometry/algorithms/detail/point_on_border.hpp>
#include <boost/geometry/algorithms/within.hpp>
#include <boost/geometry/algorithms/detail/check_iterator_range.hpp>
@@ -142,43 +145,96 @@ protected:
};
// Iterator value_type is a Ring or Polygon
template <typename Iterator, typename Box>
struct partition_item
{
explicit partition_item(Iterator it)
: m_it(it)
, m_is_initialized(false)
{}
Iterator get() const
{
return m_it;
}
template <typename EnvelopeStrategy>
Box const& get_envelope(EnvelopeStrategy const& strategy) const
{
if (! m_is_initialized)
{
m_box = geometry::return_envelope<Box>(*m_it, strategy);
m_is_initialized = true;
}
return m_box;
}
private:
Iterator m_it;
mutable Box m_box;
mutable bool m_is_initialized;
};
// structs for partition -- start
template <typename EnvelopeStrategy>
struct expand_box
{
explicit expand_box(EnvelopeStrategy const& strategy) : m_strategy(strategy) {}
template <typename Box, typename Iterator>
static inline void apply(Box& total, Iterator const& it)
inline void apply(Box& total, partition_item<Iterator, Box> const& item) const
{
geometry::expand(total, geometry::return_envelope<Box>(*it));
geometry::expand(total, item.get_envelope(m_strategy));
}
EnvelopeStrategy const& m_strategy;
};
template <typename EnvelopeStrategy>
struct overlaps_box
{
explicit overlaps_box(EnvelopeStrategy const& strategy) : m_strategy(strategy) {}
template <typename Box, typename Iterator>
static inline bool apply(Box const& box, Iterator const& it)
inline bool apply(Box const& box, partition_item<Iterator, Box> const& item) const
{
return ! geometry::disjoint(*it, box);
return ! geometry::disjoint(item.get_envelope(m_strategy), box);
}
EnvelopeStrategy const& m_strategy;
};
template <typename WithinStrategy>
struct item_visitor_type
{
bool items_overlap;
WithinStrategy const& m_strategy;
item_visitor_type() : items_overlap(false) {}
explicit item_visitor_type(WithinStrategy const& strategy)
: items_overlap(false)
, m_strategy(strategy)
{}
template <typename Item1, typename Item2>
inline void apply(Item1 const& item1, Item2 const& item2)
template <typename Iterator, typename Box>
inline bool apply(partition_item<Iterator, Box> const& item1,
partition_item<Iterator, Box> const& item2)
{
if (! items_overlap
&& (geometry::within(*points_begin(*item1), *item2)
|| geometry::within(*points_begin(*item2), *item1))
)
typedef boost::mpl::vector
<
geometry::de9im::static_mask<'T'>,
geometry::de9im::static_mask<'*', 'T'>,
geometry::de9im::static_mask<'*', '*', '*', 'T'>
> relate_mask_t;
if ( ! items_overlap
&& geometry::relate(*item1.get(), *item2.get(), relate_mask_t(), m_strategy) )
{
items_overlap = true;
return false; // interrupt
}
return true;
}
};
// structs for partition -- end
@@ -189,14 +245,16 @@ protected:
typename RingIterator,
typename ExteriorRing,
typename TurnIterator,
typename VisitPolicy
typename VisitPolicy,
typename Strategy
>
static inline bool are_holes_inside(RingIterator rings_first,
RingIterator rings_beyond,
ExteriorRing const& exterior_ring,
TurnIterator turns_first,
TurnIterator turns_beyond,
VisitPolicy& visitor)
VisitPolicy& visitor,
Strategy const& strategy)
{
boost::ignore_unused(visitor);
@@ -217,6 +275,14 @@ protected:
}
}
// prepare strategy
typedef typename std::iterator_traits<RingIterator>::value_type inter_ring_type;
typename Strategy::template point_in_geometry_strategy
<
inter_ring_type, ExteriorRing
>::type const in_exterior_strategy
= strategy.template get_point_in_geometry_strategy<inter_ring_type, ExteriorRing>();
signed_size_type ring_index = 0;
for (RingIterator it = rings_first; it != rings_beyond;
++it, ++ring_index)
@@ -224,7 +290,7 @@ protected:
// do not examine interior rings that have turns with the
// exterior ring
if (ring_indices.find(ring_index) == ring_indices.end()
&& ! geometry::covered_by(range::front(*it), exterior_ring))
&& ! geometry::covered_by(range::front(*it), exterior_ring, in_exterior_strategy))
{
return visitor.template apply<failure_interior_rings_outside>();
}
@@ -237,26 +303,36 @@ protected:
ring_indices.insert(tit->operations[1].seg_id.ring_index);
}
typedef geometry::model::box<typename point_type<Polygon>::type> box_type;
typedef partition_item<RingIterator, box_type> item_type;
// put iterators for interior rings without turns in a vector
std::vector<RingIterator> ring_iterators;
std::vector<item_type> ring_iterators;
ring_index = 0;
for (RingIterator it = rings_first; it != rings_beyond;
++it, ++ring_index)
{
if (ring_indices.find(ring_index) == ring_indices.end())
{
ring_iterators.push_back(it);
ring_iterators.push_back(item_type(it));
}
}
// call partition to check is interior rings are disjoint from
// prepare strategies
typedef typename Strategy::envelope_strategy_type envelope_strategy_type;
envelope_strategy_type const envelope_strategy
= strategy.get_envelope_strategy();
// call partition to check if interior rings are disjoint from
// each other
item_visitor_type item_visitor;
item_visitor_type<Strategy> item_visitor(strategy);
geometry::partition
<
geometry::model::box<typename point_type<Polygon>::type>
>::apply(ring_iterators, item_visitor, expand_box(), overlaps_box());
box_type
>::apply(ring_iterators, item_visitor,
expand_box<envelope_strategy_type>(envelope_strategy),
overlaps_box<envelope_strategy_type>(envelope_strategy));
if (item_visitor.items_overlap)
{
@@ -273,35 +349,40 @@ protected:
typename InteriorRings,
typename ExteriorRing,
typename TurnIterator,
typename VisitPolicy
typename VisitPolicy,
typename Strategy
>
static inline bool are_holes_inside(InteriorRings const& interior_rings,
ExteriorRing const& exterior_ring,
TurnIterator first,
TurnIterator beyond,
VisitPolicy& visitor)
VisitPolicy& visitor,
Strategy const& strategy)
{
return are_holes_inside(boost::begin(interior_rings),
boost::end(interior_rings),
exterior_ring,
first,
beyond,
visitor);
visitor,
strategy);
}
struct has_holes_inside
{
template <typename TurnIterator, typename VisitPolicy>
template <typename TurnIterator, typename VisitPolicy, typename Strategy>
static inline bool apply(Polygon const& polygon,
TurnIterator first,
TurnIterator beyond,
VisitPolicy& visitor)
VisitPolicy& visitor,
Strategy const& strategy)
{
return are_holes_inside(geometry::interior_rings(polygon),
geometry::exterior_ring(polygon),
first,
beyond,
visitor);
visitor,
strategy);
}
};
@@ -310,11 +391,12 @@ protected:
struct has_connected_interior
{
template <typename TurnIterator, typename VisitPolicy>
template <typename TurnIterator, typename VisitPolicy, typename Strategy>
static inline bool apply(Polygon const& polygon,
TurnIterator first,
TurnIterator beyond,
VisitPolicy& visitor)
VisitPolicy& visitor,
Strategy const& )
{
boost::ignore_unused(visitor);
@@ -388,7 +470,8 @@ public:
if (! has_holes_inside::apply(polygon,
turns.begin(), turns.end(),
visitor))
visitor,
strategy))
{
return false;
}
@@ -399,7 +482,8 @@ public:
return has_connected_interior::apply(polygon,
turns.begin(),
turns.end(),
visitor);
visitor,
strategy);
}
};

View File

@@ -1,6 +1,8 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014-2017, Oracle and/or its affiliates.
// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
// Copyright (c) 2014-2018, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -18,6 +20,7 @@
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/point_order.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/util/order_as_direction.hpp>
#include <boost/geometry/util/range.hpp>
@@ -34,6 +37,7 @@
#include <boost/geometry/algorithms/detail/is_valid/has_invalid_coordinate.hpp>
#include <boost/geometry/algorithms/detail/is_valid/has_spikes.hpp>
#include <boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp>
#include <boost/geometry/algorithms/dispatch/is_valid.hpp>
#include <boost/geometry/strategies/area.hpp>
@@ -107,15 +111,16 @@ struct is_properly_oriented
{
boost::ignore_unused(visitor);
typedef typename point_type<Ring>::type point_type;
typedef detail::area::ring_area
<
order_as_direction<geometry::point_order<Ring>::value>::value,
geometry::closure<Ring>::value
> ring_area_type;
typedef typename default_area_result<Ring>::type area_result_type;
typedef typename Strategy::template area_strategy
<
Ring
>::type::template result_type<Ring>::type area_result_type;
typename ring_area_predicate
<
@@ -126,7 +131,7 @@ struct is_properly_oriented
area_result_type const zero = 0;
area_result_type const area
= ring_area_type::apply(ring,
strategy.template get_area_strategy<point_type>());
strategy.template get_area_strategy<Ring>());
if (predicate(area, zero))
{
return visitor.template apply<no_failure>();
@@ -195,7 +200,7 @@ struct is_valid_ring
return
is_topologically_closed<Ring, closure>::apply(ring, visitor)
&& ! has_duplicates<Ring, closure>::apply(ring, visitor)
&& ! has_spikes<Ring, closure>::apply(ring, visitor)
&& ! has_spikes<Ring, closure>::apply(ring, visitor, strategy.get_side_strategy())
&& (! CheckSelfIntersections
|| has_valid_self_turns<Ring>::apply(ring, visitor, strategy))
&& is_properly_oriented<Ring, IsInteriorRing>::apply(ring, visitor, strategy);

View File

@@ -4,6 +4,10 @@
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2017.
// Modifications copyright (c) 2017 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -40,6 +44,18 @@ struct multi_modify
Policy::apply(*it);
}
}
template <typename Strategy>
static inline void apply(MultiGeometry& multi, Strategy const& strategy)
{
typedef typename boost::range_iterator<MultiGeometry>::type iterator_type;
for (iterator_type it = boost::begin(multi);
it != boost::end(multi);
++it)
{
Policy::apply(*it, strategy);
}
}
};

View File

@@ -1,8 +1,9 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2015, Oracle and/or its affiliates.
// Copyright (c) 2015-2018, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
@@ -10,278 +11,31 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_NORMALIZE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_NORMALIZE_HPP
#include <cstddef>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_system.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/util/normalize_spheroidal_coordinates.hpp>
#include <boost/geometry/util/normalize_spheroidal_box_coordinates.hpp>
#include <boost/geometry/views/detail/indexed_point_view.hpp>
// For backward compatibility
#include <boost/geometry/strategies/normalize.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace normalization
{
struct do_nothing
{
template <typename GeometryIn, typename GeometryOut>
static inline void apply(GeometryIn const&, GeometryOut&)
{
}
};
template <std::size_t Dimension, std::size_t DimensionCount>
struct assign_loop
{
template <typename CoordinateType, typename PointIn, typename PointOut>
static inline void apply(CoordinateType const& longitude,
CoordinateType const& latitude,
PointIn const& point_in,
PointOut& point_out)
{
geometry::set<Dimension>(point_out, boost::numeric_cast
<
typename coordinate_type<PointOut>::type
>(geometry::get<Dimension>(point_in)));
assign_loop
<
Dimension + 1, DimensionCount
>::apply(longitude, latitude, point_in, point_out);
}
};
template <std::size_t DimensionCount>
struct assign_loop<DimensionCount, DimensionCount>
{
template <typename CoordinateType, typename PointIn, typename PointOut>
static inline void apply(CoordinateType const&,
CoordinateType const&,
PointIn const&,
PointOut&)
{
}
};
template <std::size_t DimensionCount>
struct assign_loop<0, DimensionCount>
{
template <typename CoordinateType, typename PointIn, typename PointOut>
static inline void apply(CoordinateType const& longitude,
CoordinateType const& latitude,
PointIn const& point_in,
PointOut& point_out)
{
geometry::set<0>(point_out, boost::numeric_cast
<
typename coordinate_type<PointOut>::type
>(longitude));
assign_loop
<
1, DimensionCount
>::apply(longitude, latitude, point_in, point_out);
}
};
template <std::size_t DimensionCount>
struct assign_loop<1, DimensionCount>
{
template <typename CoordinateType, typename PointIn, typename PointOut>
static inline void apply(CoordinateType const& longitude,
CoordinateType const& latitude,
PointIn const& point_in,
PointOut& point_out)
{
geometry::set<1>(point_out, boost::numeric_cast
<
typename coordinate_type<PointOut>::type
>(latitude));
assign_loop
<
2, DimensionCount
>::apply(longitude, latitude, point_in, point_out);
}
};
template <typename PointIn, typename PointOut>
struct normalize_point
{
static inline void apply(PointIn const& point_in, PointOut& point_out)
{
typedef typename coordinate_type<PointIn>::type in_coordinate_type;
in_coordinate_type longitude = geometry::get<0>(point_in);
in_coordinate_type latitude = geometry::get<1>(point_in);
math::normalize_spheroidal_coordinates
<
typename coordinate_system<PointIn>::type::units,
in_coordinate_type
>(longitude, latitude);
assign_loop
<
0, dimension<PointIn>::value
>::apply(longitude, latitude, point_in, point_out);
}
};
template <typename BoxIn, typename BoxOut>
class normalize_box
{
template <typename UnitsIn, typename UnitsOut, typename CoordinateInType>
static inline void apply_to_coordinates(CoordinateInType& lon_min,
CoordinateInType& lat_min,
CoordinateInType& lon_max,
CoordinateInType& lat_max,
BoxIn const& box_in,
BoxOut& box_out)
{
detail::indexed_point_view<BoxOut, min_corner> p_min_out(box_out);
assign_loop
<
0, dimension<BoxIn>::value
>::apply(lon_min,
lat_min,
detail::indexed_point_view
<
BoxIn const, min_corner
>(box_in),
p_min_out);
detail::indexed_point_view<BoxOut, max_corner> p_max_out(box_out);
assign_loop
<
0, dimension<BoxIn>::value
>::apply(lon_max,
lat_max,
detail::indexed_point_view
<
BoxIn const, max_corner
>(box_in),
p_max_out);
}
public:
static inline void apply(BoxIn const& box_in, BoxOut& box_out)
{
typedef typename coordinate_type<BoxIn>::type in_coordinate_type;
in_coordinate_type lon_min = geometry::get<min_corner, 0>(box_in);
in_coordinate_type lat_min = geometry::get<min_corner, 1>(box_in);
in_coordinate_type lon_max = geometry::get<max_corner, 0>(box_in);
in_coordinate_type lat_max = geometry::get<max_corner, 1>(box_in);
math::normalize_spheroidal_box_coordinates
<
typename coordinate_system<BoxIn>::type::units,
in_coordinate_type
>(lon_min, lat_min, lon_max, lat_max);
apply_to_coordinates
<
typename coordinate_system<BoxIn>::type::units,
typename coordinate_system<BoxOut>::type::units
>(lon_min, lat_min, lon_max, lat_max, box_in, box_out);
}
};
}} // namespace detail::normalization
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template
<
typename GeometryIn,
typename GeometryOut,
typename TagIn = typename tag<GeometryIn>::type,
typename TagOut = typename tag<GeometryOut>::type,
typename CSTagIn = typename cs_tag<GeometryIn>::type,
typename CSTagOut = typename cs_tag<GeometryOut>::type
>
struct normalize : detail::normalization::do_nothing
{};
template <typename PointIn, typename PointOut>
struct normalize
<
PointIn, PointOut, point_tag, point_tag,
spherical_equatorial_tag, spherical_equatorial_tag
> : detail::normalization::normalize_point<PointIn, PointOut>
{};
template <typename PointIn, typename PointOut>
struct normalize
<
PointIn, PointOut, point_tag, point_tag, geographic_tag, geographic_tag
> : detail::normalization::normalize_point<PointIn, PointOut>
{};
template <typename BoxIn, typename BoxOut>
struct normalize
<
BoxIn, BoxOut, box_tag, box_tag,
spherical_equatorial_tag, spherical_equatorial_tag
> : detail::normalization::normalize_box<BoxIn, BoxOut>
{};
template <typename BoxIn, typename BoxOut>
struct normalize
<
BoxIn, BoxOut, box_tag, box_tag, geographic_tag, geographic_tag
> : detail::normalization::normalize_box<BoxIn, BoxOut>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
template <typename GeometryIn, typename GeometryOut>
inline void normalize(GeometryIn const& geometry_in, GeometryOut& geometry_out)
template <typename GeometryIn, typename GeometryOut, typename Strategy>
inline void normalize(GeometryIn const& geometry_in, GeometryOut& geometry_out, Strategy const& )
{
dispatch::normalize
<
GeometryIn, GeometryOut
>::apply(geometry_in, geometry_out);
Strategy::apply(geometry_in, geometry_out);
}
template <typename GeometryOut, typename GeometryIn>
inline GeometryOut return_normalized(GeometryIn const& geometry_in)
template <typename GeometryOut, typename GeometryIn, typename Strategy>
inline GeometryOut return_normalized(GeometryIn const& geometry_in, Strategy const& strategy)
{
GeometryOut geometry_out;
detail::normalize(geometry_in, geometry_out);
detail::normalize(geometry_in, geometry_out, strategy);
return geometry_out;
}

View File

@@ -2,6 +2,11 @@
// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2017.
// Modifications copyright (c) 2017, 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)
@@ -99,12 +104,18 @@ public :
}
}
template <typename RobustPoint, typename Turns>
inline void get_left_turns(RobustPoint const& origin, Turns& turns)
template <typename RobustPoint, typename Turns, typename SideStrategy>
inline void get_left_turns(RobustPoint const& origin, Turns& turns,
SideStrategy const& strategy)
{
typedef detail::left_turns::angle_less
<
typename AngleInfo::point_type,
SideStrategy
> angle_less;
// Sort on angle
std::sort(m_angles.begin(), m_angles.end(),
detail::left_turns::angle_less<typename AngleInfo::point_type>(origin));
std::sort(m_angles.begin(), m_angles.end(), angle_less(origin, strategy));
// Group same-angled elements
std::size_t cluster_size = detail::left_turns::assign_cluster_indices(m_angles, origin);

View File

@@ -0,0 +1,156 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2014, 2015, 2017.
// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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_OVERLAPS_IMPLEMENTATION_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAPS_IMPLEMENTATION_HPP
#include <cstddef>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/algorithms/relate.hpp>
#include <boost/geometry/algorithms/detail/overlaps/interface.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace overlaps
{
template
<
std::size_t Dimension,
std::size_t DimensionCount
>
struct box_box_loop
{
template <typename Box1, typename Box2>
static inline void apply(Box1 const& b1, Box2 const& b2,
bool& overlaps, bool& one_in_two, bool& two_in_one)
{
assert_dimension_equal<Box1, Box2>();
typedef typename coordinate_type<Box1>::type coordinate_type1;
typedef typename coordinate_type<Box2>::type coordinate_type2;
coordinate_type1 const& min1 = get<min_corner, Dimension>(b1);
coordinate_type1 const& max1 = get<max_corner, Dimension>(b1);
coordinate_type2 const& min2 = get<min_corner, Dimension>(b2);
coordinate_type2 const& max2 = get<max_corner, Dimension>(b2);
// We might use the (not yet accepted) Boost.Interval
// submission in the future
// If:
// B1: |-------|
// B2: |------|
// in any dimension -> no overlap
if (max1 <= min2 || min1 >= max2)
{
overlaps = false;
return;
}
// If:
// B1: |--------------------|
// B2: |-------------|
// in all dimensions -> within, then no overlap
// B1: |--------------------|
// B2: |-------------|
// this is "within-touch" -> then no overlap. So use < and >
if (min1 < min2 || max1 > max2)
{
one_in_two = false;
}
// Same other way round
if (min2 < min1 || max2 > max1)
{
two_in_one = false;
}
box_box_loop
<
Dimension + 1,
DimensionCount
>::apply(b1, b2, overlaps, one_in_two, two_in_one);
}
};
template
<
std::size_t DimensionCount
>
struct box_box_loop<DimensionCount, DimensionCount>
{
template <typename Box1, typename Box2>
static inline void apply(Box1 const& , Box2 const&, bool&, bool&, bool&)
{
}
};
struct box_box
{
template <typename Box1, typename Box2, typename Strategy>
static inline bool apply(Box1 const& b1, Box2 const& b2, Strategy const& /*strategy*/)
{
bool overlaps = true;
bool within1 = true;
bool within2 = true;
box_box_loop
<
0,
dimension<Box1>::type::value
>::apply(b1, b2, overlaps, within1, within2);
/*
\see http://docs.codehaus.org/display/GEOTDOC/02+Geometry+Relationships#02GeometryRelationships-Overlaps
where is stated that "inside" is not an "overlap",
this is true and is implemented as such.
*/
return overlaps && ! within1 && ! within2;
}
};
}} // namespace detail::overlaps
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Box1, typename Box2>
struct overlaps<Box1, Box2, box_tag, box_tag>
: detail::overlaps::box_box
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAPS_IMPLEMENTATION_HPP

View File

@@ -0,0 +1,124 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2014, 2015, 2017.
// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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_OVERLAPS_INTERFACE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAPS_INTERFACE_HPP
#include <cstddef>
#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/algorithms/detail/relate/relate_impl.hpp>
#include <boost/geometry/strategies/relate.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template
<
typename Geometry1,
typename Geometry2,
typename Tag1 = typename tag<Geometry1>::type,
typename Tag2 = typename tag<Geometry2>::type
>
struct overlaps
: detail::relate::relate_impl
<
detail::de9im::static_mask_overlaps_type,
Geometry1,
Geometry2
>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
/*!
\brief \brief_check2{overlap}
\ingroup overlaps
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\tparam Strategy \tparam_strategy{Overlaps}
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\param strategy \param_strategy{overlaps}
\return \return_check2{overlap}
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/overlaps.qbk]}
*/
template <typename Geometry1, typename Geometry2, typename Strategy>
inline bool overlaps(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
concepts::check<Geometry1 const>();
concepts::check<Geometry2 const>();
return dispatch::overlaps
<
Geometry1,
Geometry2
>::apply(geometry1, geometry2, strategy);
}
/*!
\brief \brief_check2{overlap}
\ingroup overlaps
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\return \return_check2{overlap}
\qbk{[include reference/algorithms/overlaps.qbk]}
*/
template <typename Geometry1, typename Geometry2>
inline bool overlaps(Geometry1 const& geometry1, Geometry2 const& geometry2)
{
concepts::check<Geometry1 const>();
concepts::check<Geometry2 const>();
typedef typename strategy::relate::services::default_strategy
<
Geometry1,
Geometry2
>::type strategy_type;
return dispatch::overlaps
<
Geometry1,
Geometry2
>::apply(geometry1, geometry2, strategy_type());
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAPS_INTERFACE_HPP

View File

@@ -1,6 +1,12 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2017.
// Modifications copyright (c) 2017, 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
@@ -10,8 +16,10 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ADD_RINGS_HPP
#include <boost/range.hpp>
#include <boost/throw_exception.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/exception.hpp>
#include <boost/geometry/algorithms/area.hpp>
#include <boost/geometry/algorithms/detail/overlay/convert_ring.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_ring.hpp>
@@ -62,6 +70,13 @@ inline void convert_and_add(GeometryOut& result,
}
}
enum add_rings_error_handling
{
add_rings_ignore_unordered,
add_rings_add_unordered,
add_rings_throw_if_reversed
};
template
<
typename GeometryOut,
@@ -69,16 +84,21 @@ template
typename Geometry1,
typename Geometry2,
typename RingCollection,
typename OutputIterator
typename OutputIterator,
typename AreaStrategy
>
inline OutputIterator add_rings(SelectionMap const& map,
Geometry1 const& geometry1, Geometry2 const& geometry2,
RingCollection const& collection,
OutputIterator out)
OutputIterator out,
AreaStrategy const& area_strategy,
add_rings_error_handling error_handling = add_rings_ignore_unordered)
{
typedef typename SelectionMap::const_iterator iterator;
typedef typename SelectionMap::mapped_type property_type;
typedef typename property_type::area_type area_type;
typedef typename AreaStrategy::template result_type
<
GeometryOut
>::type area_type;
area_type const zero = 0;
std::size_t const min_num_points = core_detail::closure::minimum_ring_size
@@ -122,10 +142,22 @@ inline OutputIterator add_rings(SelectionMap const& map,
// Only add rings if they satisfy minimal requirements.
// This cannot be done earlier (during traversal), not
// everything is figured out yet (sum of positive/negative rings)
if (geometry::num_points(result) >= min_num_points
&& math::larger(geometry::area(result), zero))
if (geometry::num_points(result) >= min_num_points)
{
*out++ = result;
area_type const area = geometry::area(result, area_strategy);
// Ignore if area is 0
if (! math::equals(area, zero))
{
if (error_handling == add_rings_add_unordered
|| area > zero)
{
*out++ = result;
}
else if (error_handling == add_rings_throw_if_reversed)
{
BOOST_THROW_EXCEPTION(invalid_output_exception());
}
}
}
}
}
@@ -139,15 +171,17 @@ template
typename SelectionMap,
typename Geometry,
typename RingCollection,
typename OutputIterator
typename OutputIterator,
typename AreaStrategy
>
inline OutputIterator add_rings(SelectionMap const& map,
Geometry const& geometry,
RingCollection const& collection,
OutputIterator out)
OutputIterator out,
AreaStrategy const& area_strategy)
{
Geometry empty;
return add_rings<GeometryOut>(map, geometry, empty, collection, out);
return add_rings<GeometryOut>(map, geometry, empty, collection, out, area_strategy);
}

View File

@@ -1,100 +0,0 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2016 Barend Gehrels, 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_OVERLAY_AGGREGATE_OPERATIONS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_AGGREGATE_OPERATIONS_HPP
#include <set>
#include <boost/geometry/algorithms/detail/overlay/sort_by_side.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace overlay { namespace sort_by_side
{
struct ring_with_direction
{
ring_identifier ring_id;
direction_type direction;
bool only_turn_on_ring;
inline bool operator<(ring_with_direction const& other) const
{
return this->ring_id != other.ring_id
? this->ring_id < other.ring_id
: this->direction < other.direction;
}
ring_with_direction()
: direction(dir_unknown)
, only_turn_on_ring(false)
{}
};
struct rank_with_rings
{
std::size_t rank;
std::set<ring_with_direction> rings;
rank_with_rings()
: rank(0)
{
}
inline bool all_to() const
{
for (std::set<ring_with_direction>::const_iterator it = rings.begin();
it != rings.end(); ++it)
{
if (it->direction == sort_by_side::dir_from)
{
return false;
}
}
return true;
}
};
template <typename Sbs>
inline void aggregate_operations(Sbs const& sbs, std::vector<rank_with_rings>& aggregation)
{
aggregation.clear();
for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++)
{
typename Sbs::rp const& ranked_point = sbs.m_ranked_points[i];
if (aggregation.empty() || aggregation.back().rank != ranked_point.rank)
{
rank_with_rings current;
current.rank = ranked_point.rank;
aggregation.push_back(current);
}
ring_with_direction rwd;
segment_identifier const& sid = ranked_point.seg_id;
rwd.ring_id = ring_identifier(sid.source_index, sid.multi_index, sid.ring_index);
rwd.direction = ranked_point.direction;
rwd.only_turn_on_ring = ranked_point.only_turn_on_ring;
aggregation.back().rings.insert(rwd);
}
}
}}} // namespace detail::overlay::sort_by_side
#endif //DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_AGGREGATE_OPERATIONS_HPP

View File

@@ -2,6 +2,11 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2018.
// Modifications copyright (c) 2018 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)
@@ -10,11 +15,10 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_APPEND_NO_DUPLICATES_HPP
#include <boost/range.hpp>
#include <boost/geometry/algorithms/append.hpp>
#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
#include <boost/geometry/util/range.hpp>
namespace boost { namespace geometry
@@ -26,11 +30,24 @@ namespace detail { namespace overlay
{
template <typename Range, typename Point>
inline void append_no_duplicates(Range& range, Point const& point, bool force = false)
inline void append_with_duplicates(Range& range, Point const& point)
{
if (boost::size(range) == 0
|| force
|| ! geometry::detail::equals::equals_point_point(*(boost::end(range)-1), point))
#ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION
std::cout << " add: ("
<< geometry::get<0>(point) << ", " << geometry::get<1>(point) << ")"
<< std::endl;
#endif
geometry::append(range, point);
}
template <typename Range, typename Point, typename EqPPStrategy>
inline void append_no_duplicates(Range& range, Point const& point,
EqPPStrategy const& strategy)
{
if ( boost::empty(range)
|| ! geometry::detail::equals::equals_point_point(geometry::range::back(range),
point,
strategy) )
{
#ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION
std::cout << " add: ("

View File

@@ -2,8 +2,8 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2014.
// Modifications copyright (c) 2014 Oracle and/or its affiliates.
// This file was modified by Oracle on 2014, 2017, 2018.
// Modifications copyright (c) 2014-2018 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -15,11 +15,14 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_APPEND_NO_DUPS_OR_SPIKES_HPP
#include <boost/range.hpp>
#include <boost/static_assert.hpp>
#include <boost/geometry/algorithms/append.hpp>
#include <boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp>
#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/util/condition.hpp>
#include <boost/geometry/util/range.hpp>
@@ -33,12 +36,13 @@ namespace detail { namespace overlay
{
// TODO: move this / rename this
template <typename Point1, typename Point2, typename RobustPolicy>
template <typename Point1, typename Point2, typename EqualsStrategy, typename RobustPolicy>
inline bool points_equal_or_close(Point1 const& point1,
Point2 const& point2,
EqualsStrategy const& strategy,
RobustPolicy const& robust_policy)
{
if (detail::equals::equals_point_point(point1, point2))
if (detail::equals::equals_point_point(point1, point2, strategy))
{
return true;
}
@@ -59,12 +63,20 @@ inline bool points_equal_or_close(Point1 const& point1,
geometry::recalculate(point1_rob, point1, robust_policy);
geometry::recalculate(point2_rob, point2, robust_policy);
return detail::equals::equals_point_point(point1_rob, point2_rob);
// Only if this is the case the same strategy can be used.
BOOST_STATIC_ASSERT((boost::is_same
<
typename geometry::cs_tag<Point1>::type,
typename geometry::cs_tag<robust_point_type>::type
>::value));
return detail::equals::equals_point_point(point1_rob, point2_rob, strategy);
}
template <typename Range, typename Point, typename RobustPolicy>
template <typename Range, typename Point, typename SideStrategy, typename RobustPolicy>
inline void append_no_dups_or_spikes(Range& range, Point const& point,
SideStrategy const& strategy,
RobustPolicy const& robust_policy)
{
#ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION
@@ -75,8 +87,10 @@ inline void append_no_dups_or_spikes(Range& range, Point const& point,
// The code below this condition checks all spikes/dups
// for geometries >= 3 points.
// So we have to check the first potential duplicate differently
if (boost::size(range) == 1
&& points_equal_or_close(*(boost::begin(range)), point, robust_policy))
if ( boost::size(range) == 1
&& points_equal_or_close(*(boost::begin(range)), point,
strategy.get_equals_point_point_strategy(),
robust_policy) )
{
return;
}
@@ -92,6 +106,7 @@ inline void append_no_dups_or_spikes(Range& range, Point const& point,
&& point_is_spike_or_equal(point,
*(boost::end(range) - 3),
*(boost::end(range) - 2),
strategy,
robust_policy))
{
// Use the Concept/traits, so resize and append again
@@ -100,8 +115,48 @@ inline void append_no_dups_or_spikes(Range& range, Point const& point,
}
}
template <typename Range, typename RobustPolicy>
template <typename Range, typename Point, typename SideStrategy, typename RobustPolicy>
inline void append_no_collinear(Range& range, Point const& point,
SideStrategy const& strategy,
RobustPolicy const& robust_policy)
{
// Stricter version, not allowing any point in a linear row
// (spike, continuation or same point)
// The code below this condition checks all spikes/dups
// for geometries >= 3 points.
// So we have to check the first potential duplicate differently
if ( boost::size(range) == 1
&& points_equal_or_close(*(boost::begin(range)), point,
strategy.get_equals_point_point_strategy(),
robust_policy) )
{
return;
}
traits::push_back<Range>::apply(range, point);
// If a point is equal, or forming a spike, remove the pen-ultimate point
// because this one caused the spike.
// If so, the now-new-pen-ultimate point can again cause a spike
// (possibly at a corner). So keep doing this.
// Besides spikes it will also avoid adding duplicates.
while(boost::size(range) >= 3
&& point_is_collinear(point,
*(boost::end(range) - 3),
*(boost::end(range) - 2),
strategy,
robust_policy))
{
// Use the Concept/traits, so resize and append again
traits::resize<Range>::apply(range, boost::size(range) - 2);
traits::push_back<Range>::apply(range, point);
}
}
template <typename Range, typename SideStrategy, typename RobustPolicy>
inline void clean_closing_dups_and_spikes(Range& range,
SideStrategy const& strategy,
RobustPolicy const& robust_policy)
{
std::size_t const minsize
@@ -134,8 +189,8 @@ inline void clean_closing_dups_and_spikes(Range& range,
}
// Check if closing point is a spike (this is so if the second point is
// considered as a spike w.r.t. the last segment)
if (point_is_spike_or_equal(*second, *ultimate, *first, robust_policy))
// considered as collinear w.r.t. the last segment)
if (point_is_collinear(*second, *ultimate, *first, strategy, robust_policy))
{
range::erase(range, first);
if (BOOST_GEOMETRY_CONDITION(closed))

View File

@@ -1,9 +1,10 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2017.
// Modifications copyright (c) 2017 Oracle and/or its affiliates.
// This file was modified by Oracle on 2017, 2018.
// Modifications copyright (c) 2017-2018 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,
@@ -15,12 +16,12 @@
#include <boost/range.hpp>
#include <boost/geometry/algorithms/area.hpp>
#include <boost/geometry/algorithms/envelope.hpp>
#include <boost/geometry/algorithms/expand.hpp>
#include <boost/geometry/algorithms/detail/partition.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_ring.hpp>
#include <boost/geometry/algorithms/within.hpp>
#include <boost/geometry/algorithms/detail/overlay/range_in_geometry.hpp>
#include <boost/geometry/algorithms/covered_by.hpp>
#include <boost/geometry/geometries/box.hpp>
@@ -37,50 +38,88 @@ namespace detail { namespace overlay
template
<
typename Item,
typename InnerGeometry,
typename Geometry1, typename Geometry2,
typename RingCollection
typename RingCollection,
typename Strategy
>
static inline bool within_selected_input(Item const& item2, ring_identifier const& ring_id,
static inline bool within_selected_input(Item const& item2,
InnerGeometry const& inner_geometry,
ring_identifier const& outer_id,
Geometry1 const& geometry1, Geometry2 const& geometry2,
RingCollection const& collection)
RingCollection const& collection,
Strategy const& strategy)
{
typedef typename geometry::tag<Geometry1>::type tag1;
typedef typename geometry::tag<Geometry2>::type tag2;
switch (ring_id.source_index)
// NOTE: range_in_geometry first checks the item2.point and then
// if this point is on boundary it checks points of inner_geometry
// ring until a point inside/outside other geometry ring is found
switch (outer_id.source_index)
{
// covered_by
case 0 :
return range_in_geometry(item2.point, inner_geometry,
get_ring<tag1>::apply(outer_id, geometry1), strategy) >= 0;
case 1 :
return range_in_geometry(item2.point, inner_geometry,
get_ring<tag2>::apply(outer_id, geometry2), strategy) >= 0;
case 2 :
return range_in_geometry(item2.point, inner_geometry,
get_ring<void>::apply(outer_id, collection), strategy) >= 0;
}
return false;
}
template
<
typename Item,
typename Geometry1, typename Geometry2,
typename RingCollection,
typename Strategy
>
static inline bool within_selected_input(Item const& item2,
ring_identifier const& inner_id, ring_identifier const& outer_id,
Geometry1 const& geometry1, Geometry2 const& geometry2,
RingCollection const& collection,
Strategy const& strategy)
{
typedef typename geometry::tag<Geometry1>::type tag1;
typedef typename geometry::tag<Geometry2>::type tag2;
switch (inner_id.source_index)
{
case 0 :
return geometry::within(item2.point,
get_ring<tag1>::apply(ring_id, geometry1));
break;
return within_selected_input(item2,
get_ring<tag1>::apply(inner_id, geometry1),
outer_id, geometry1, geometry2, collection, strategy);
case 1 :
return geometry::within(item2.point,
get_ring<tag2>::apply(ring_id, geometry2));
break;
return within_selected_input(item2,
get_ring<tag2>::apply(inner_id, geometry2),
outer_id, geometry1, geometry2, collection, strategy);
case 2 :
return geometry::within(item2.point,
get_ring<void>::apply(ring_id, collection));
break;
return within_selected_input(item2,
get_ring<void>::apply(inner_id, collection),
outer_id, geometry1, geometry2, collection, strategy);
}
return false;
}
template <typename Point>
template <typename Point, typename AreaType>
struct ring_info_helper
{
typedef typename geometry::default_area_result<Point>::type area_type;
ring_identifier id;
area_type real_area;
area_type abs_area;
AreaType real_area;
AreaType abs_area;
model::box<Point> envelope;
inline ring_info_helper()
: real_area(0), abs_area(0)
{}
inline ring_info_helper(ring_identifier i, area_type a)
inline ring_info_helper(ring_identifier i, AreaType const& a)
: id(i), real_area(a), abs_area(geometry::math::abs(a))
{}
};
@@ -95,16 +134,25 @@ struct ring_info_helper_get_box
}
};
template <typename DisjointBoxBoxStrategy>
struct ring_info_helper_ovelaps_box
{
template <typename Box, typename InputItem>
static inline bool apply(Box const& box, InputItem const& item)
{
return ! geometry::detail::disjoint::disjoint_box_box(box, item.envelope);
return ! geometry::detail::disjoint::disjoint_box_box(
box, item.envelope, DisjointBoxBoxStrategy());
}
};
template <typename Geometry1, typename Geometry2, typename Collection, typename RingMap>
template
<
typename Geometry1,
typename Geometry2,
typename Collection,
typename RingMap,
typename Strategy
>
struct assign_visitor
{
typedef typename RingMap::mapped_type ring_info_type;
@@ -113,26 +161,27 @@ struct assign_visitor
Geometry2 const& m_geometry2;
Collection const& m_collection;
RingMap& m_ring_map;
Strategy const& m_strategy;
bool m_check_for_orientation;
inline assign_visitor(Geometry1 const& g1, Geometry2 const& g2, Collection const& c,
RingMap& map, bool check)
RingMap& map, Strategy const& strategy, bool check)
: m_geometry1(g1)
, m_geometry2(g2)
, m_collection(c)
, m_ring_map(map)
, m_strategy(strategy)
, m_check_for_orientation(check)
{}
template <typename Item>
inline void apply(Item const& outer, Item const& inner, bool first = true)
inline bool apply(Item const& outer, Item const& inner, bool first = true)
{
if (first && outer.abs_area < inner.abs_area)
{
// Apply with reversed arguments
apply(inner, outer, false);
return;
return true;
}
if (m_check_for_orientation
@@ -141,8 +190,10 @@ struct assign_visitor
{
ring_info_type& inner_in_map = m_ring_map[inner.id];
if (geometry::within(inner_in_map.point, outer.envelope)
&& within_selected_input(inner_in_map, outer.id, m_geometry1, m_geometry2, m_collection)
if (geometry::covered_by(inner_in_map.point, outer.envelope)
&& within_selected_input(inner_in_map, inner.id, outer.id,
m_geometry1, m_geometry2, m_collection,
m_strategy)
)
{
// Assign a parent if there was no earlier parent, or the newly
@@ -155,35 +206,46 @@ struct assign_visitor
}
}
}
return true;
}
};
template
<
overlay_type OverlayType,
typename Geometry1, typename Geometry2,
typename RingCollection,
typename RingMap
typename RingMap,
typename Strategy
>
inline void assign_parents(Geometry1 const& geometry1,
Geometry2 const& geometry2,
RingCollection const& collection,
RingMap& ring_map,
bool check_for_orientation = false)
Strategy const& strategy)
{
static bool const is_difference = OverlayType == overlay_difference;
static bool const is_buffer = OverlayType == overlay_buffer;
static bool const is_dissolve = OverlayType == overlay_dissolve;
static bool const check_for_orientation = is_buffer || is_dissolve;
typedef typename geometry::tag<Geometry1>::type tag1;
typedef typename geometry::tag<Geometry2>::type tag2;
typedef typename RingMap::mapped_type ring_info_type;
typedef typename ring_info_type::point_type point_type;
typedef model::box<point_type> box_type;
typedef typename Strategy::template area_strategy
<
point_type
>::type::template result_type<point_type>::type area_result_type;
typedef typename RingMap::iterator map_iterator_type;
{
typedef ring_info_helper<point_type> helper;
typedef ring_info_helper<point_type, area_result_type> helper;
typedef std::vector<helper> vector_type;
typedef typename boost::range_iterator<vector_type const>::type vector_iterator_type;
@@ -204,17 +266,21 @@ inline void assign_parents(Geometry1 const& geometry1,
{
case 0 :
geometry::envelope(get_ring<tag1>::apply(it->first, geometry1),
item.envelope);
item.envelope, strategy.get_envelope_strategy());
break;
case 1 :
geometry::envelope(get_ring<tag2>::apply(it->first, geometry2),
item.envelope);
item.envelope, strategy.get_envelope_strategy());
break;
case 2 :
geometry::envelope(get_ring<void>::apply(it->first, collection),
item.envelope);
item.envelope, strategy.get_envelope_strategy());
break;
}
// Expand envelope slightly
expand_by_epsilon(item.envelope);
if (item.real_area > 0)
{
count_positive++;
@@ -231,12 +297,14 @@ inline void assign_parents(Geometry1 const& geometry1,
return;
}
if (count_positive == 1)
if (count_positive == 1 && ! is_difference && ! is_dissolve)
{
// Optimization for one outer ring
// -> assign this as parent to all others (all interior rings)
// In unions, this is probably the most occuring case and gives
// a dramatic improvement (factor 5 for star_comb testcase)
// In difference or other cases where interior rings might be
// located outside the outer ring, this cannot be done
ring_identifier id_of_positive = vector[index_positive].id;
ring_info_type& outer = ring_map[id_of_positive];
index = 0;
@@ -257,14 +325,20 @@ inline void assign_parents(Geometry1 const& geometry1,
assign_visitor
<
Geometry1, Geometry2,
RingCollection, RingMap
> visitor(geometry1, geometry2, collection, ring_map, check_for_orientation);
RingCollection, RingMap,
Strategy
> visitor(geometry1, geometry2, collection, ring_map, strategy, check_for_orientation);
typedef ring_info_helper_ovelaps_box
<
typename Strategy::disjoint_box_box_strategy_type
> overlaps_box_type;
geometry::partition
<
box_type
>::apply(vector, visitor, ring_info_helper_get_box(),
ring_info_helper_ovelaps_box());
overlaps_box_type());
}
if (check_for_orientation)
@@ -272,28 +346,38 @@ inline void assign_parents(Geometry1 const& geometry1,
for (map_iterator_type it = boost::begin(ring_map);
it != boost::end(ring_map); ++it)
{
if (geometry::math::equals(it->second.get_area(), 0))
ring_info_type& info = it->second;
if (geometry::math::equals(info.get_area(), 0))
{
it->second.discarded = true;
info.discarded = true;
}
else if (it->second.parent.source_index >= 0
&& math::larger(it->second.get_area(), 0))
else if (info.parent.source_index >= 0)
{
const ring_info_type& parent = ring_map[it->second.parent];
const ring_info_type& parent = ring_map[info.parent];
bool const pos = math::larger(info.get_area(), 0);
bool const parent_pos = math::larger(parent.area, 0);
if (math::larger(parent.area, 0))
bool const double_neg = is_dissolve && ! pos && ! parent_pos;
if ((pos && parent_pos) || double_neg)
{
// Discard positive inner ring with positive parent
it->second.discarded = true;
// Also, for some cases (dissolve), negative inner ring
// with negative parent should be discarded
info.discarded = true;
}
if (pos || info.discarded)
{
// Remove parent ID from any positive or discarded inner rings
info.parent.source_index = -1;
}
// Remove parent ID from any positive inner ring
it->second.parent.source_index = -1;
}
else if (it->second.parent.source_index < 0
&& math::smaller(it->second.get_area(), 0))
else if (info.parent.source_index < 0
&& math::smaller(info.get_area(), 0))
{
// Reverse negative ring without parent
it->second.reversed = true;
info.reversed = true;
}
}
}
@@ -310,23 +394,25 @@ inline void assign_parents(Geometry1 const& geometry1,
}
// Version for one geometry (called by buffer)
// Version for one geometry (called by buffer/dissolve)
template
<
overlay_type OverlayType,
typename Geometry,
typename RingCollection,
typename RingMap
typename RingMap,
typename Strategy
>
inline void assign_parents(Geometry const& geometry,
RingCollection const& collection,
RingMap& ring_map,
bool check_for_orientation)
Strategy const& strategy)
{
// Call it with an empty geometry as second geometry (source_id == 1)
// (ring_map should be empty for source_id==1)
Geometry empty;
assign_parents(geometry, empty, collection, ring_map, check_for_orientation);
assign_parents<OverlayType>(geometry, empty,
collection, ring_map, strategy);
}

View File

@@ -2,6 +2,11 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2018.
// Modifications copyright (c) 2018 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)
@@ -9,11 +14,18 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CHECK_ENRICH_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CHECK_ENRICH_HPP
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
#include <iostream>
#endif // BOOST_GEOMETRY_DEBUG_ENRICH
#include <cstddef>
#include <vector>
#include <boost/range.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/value_type.hpp>
#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
@@ -42,7 +54,7 @@ struct meta_turn
template <typename MetaTurn>
inline void display(MetaTurn const& meta_turn, std::string const& reason = "")
inline void display(MetaTurn const& meta_turn, const char* reason = "")
{
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
std::cout << meta_turn.index

View File

@@ -2,10 +2,11 @@
// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2015.
// Modifications copyright (c) 2015 Oracle and/or its affiliates.
// This file was modified by Oracle on 2015, 2018.
// Modifications copyright (c) 2015-2018 Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// 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
@@ -24,6 +25,8 @@
#include <boost/geometry/util/select_coordinate_type.hpp>
#include <boost/geometry/geometries/segment.hpp>
#include <boost/geometry/strategies/cartesian/point_in_point.hpp>
namespace boost { namespace geometry
{
@@ -83,6 +86,15 @@ private:
public:
// TODO: Temporary, this strategy should be moved, it is cartesian-only
typedef strategy::within::cartesian_point_point equals_point_point_strategy_type;
static inline equals_point_point_strategy_type get_equals_point_point_strategy()
{
return equals_point_point_strategy_type();
}
inline bool clip_segment(Box const& b, segment_type& s, bool& sp1_clipped, bool& sp2_clipped) const
{
typedef typename select_coordinate_type<Box, Point>::type coordinate_type;
@@ -224,9 +236,10 @@ OutputIterator clip_range_with_box(Box const& b, Range const& range,
// b. Add p1 only if it is the first point, then add p2
if (boost::empty(line_out))
{
detail::overlay::append_no_duplicates(line_out, p1, true);
detail::overlay::append_with_duplicates(line_out, p1);
}
detail::overlay::append_no_duplicates(line_out, p2);
detail::overlay::append_no_duplicates(line_out, p2,
strategy.get_equals_point_point_strategy());
// c. If c2 is clipped, finish the line
if (c2)

View File

@@ -26,14 +26,11 @@ struct cluster_info
{
std::set<signed_size_type> turn_indices;
bool switch_source; // For clusters with a touch, conform turn_info uu
//! Number of open spaces (e.g. 2 for touch)
std::size_t open_count;
inline cluster_info()
: switch_source(false)
, open_count(0)
: open_count(0)
{}
};

View File

@@ -2,6 +2,11 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2018.
// Modifications copyright (c) 2018, 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)
@@ -9,18 +14,16 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CONVERT_RING_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CONVERT_RING_HPP
#include <boost/mpl/assert.hpp>
#include <boost/range.hpp>
#include <boost/range/algorithm/reverse.hpp>
#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
#include <boost/geometry/algorithms/num_points.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
#include <boost/geometry/algorithms/convert.hpp>
namespace boost { namespace geometry
{

View File

@@ -20,6 +20,7 @@
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/algorithms/detail/signed_size_type.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/util/range.hpp>
#include <boost/geometry/iterators/ever_circling_iterator.hpp>

View File

@@ -2,8 +2,8 @@
// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2014.
// Modifications copyright (c) 2014 Oracle and/or its affiliates.
// This file was modified by Oracle on 2014, 2017, 2018.
// Modifications copyright (c) 2014-2018 Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -23,22 +23,27 @@
#include <boost/range.hpp>
#include <boost/type_traits/integral_constant.hpp>
#include <boost/geometry/algorithms/detail/assign_box_corners.hpp>
#include <boost/geometry/algorithms/detail/signed_size_type.hpp>
#include <boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp>
#include <boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp>
#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/ring_type.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/iterators/ever_circling_iterator.hpp>
#include <boost/geometry/views/closeable_view.hpp>
#include <boost/geometry/views/reversible_view.hpp>
#include <boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp>
#include <boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/iterators/ever_circling_iterator.hpp>
#include <boost/geometry/util/range.hpp>
#include <boost/geometry/views/closeable_view.hpp>
#include <boost/geometry/views/reversible_view.hpp>
namespace boost { namespace geometry
{
@@ -56,12 +61,14 @@ struct copy_segments_ring
<
typename Ring,
typename SegmentIdentifier,
typename SideStrategy,
typename RobustPolicy,
typename RangeOut
>
static inline void apply(Ring const& ring,
SegmentIdentifier const& seg_id,
signed_size_type to_index,
SideStrategy const& strategy,
RobustPolicy const& robust_policy,
RangeOut& current_output)
{
@@ -108,7 +115,7 @@ struct copy_segments_ring
for (signed_size_type i = 0; i < count; ++i, ++it)
{
detail::overlay::append_no_dups_or_spikes(current_output, *it, robust_policy);
detail::overlay::append_no_dups_or_spikes(current_output, *it, strategy, robust_policy);
}
}
};
@@ -118,24 +125,27 @@ class copy_segments_linestring
{
private:
// remove spikes
template <typename RangeOut, typename Point, typename RobustPolicy>
template <typename RangeOut, typename Point, typename SideStrategy, typename RobustPolicy>
static inline void append_to_output(RangeOut& current_output,
Point const& point,
SideStrategy const& strategy,
RobustPolicy const& robust_policy,
boost::true_type const&)
{
detail::overlay::append_no_dups_or_spikes(current_output, point,
strategy,
robust_policy);
}
// keep spikes
template <typename RangeOut, typename Point, typename RobustPolicy>
template <typename RangeOut, typename Point, typename SideStrategy, typename RobustPolicy>
static inline void append_to_output(RangeOut& current_output,
Point const& point,
SideStrategy const& strategy,
RobustPolicy const&,
boost::false_type const&)
{
detail::overlay::append_no_duplicates(current_output, point);
detail::overlay::append_no_duplicates(current_output, point, strategy.get_equals_point_point_strategy());
}
public:
@@ -143,12 +153,14 @@ public:
<
typename LineString,
typename SegmentIdentifier,
typename SideStrategy,
typename RobustPolicy,
typename RangeOut
>
static inline void apply(LineString const& ls,
SegmentIdentifier const& seg_id,
signed_size_type to_index,
SideStrategy const& strategy,
RobustPolicy const& robust_policy,
RangeOut& current_output)
{
@@ -169,7 +181,7 @@ public:
for (signed_size_type i = 0; i < count; ++i, ++it)
{
append_to_output(current_output, *it, robust_policy,
append_to_output(current_output, *it, strategy, robust_policy,
boost::integral_constant<bool, RemoveSpikes>());
}
}
@@ -182,12 +194,14 @@ struct copy_segments_polygon
<
typename Polygon,
typename SegmentIdentifier,
typename SideStrategy,
typename RobustPolicy,
typename RangeOut
>
static inline void apply(Polygon const& polygon,
SegmentIdentifier const& seg_id,
signed_size_type to_index,
SideStrategy const& strategy,
RobustPolicy const& robust_policy,
RangeOut& current_output)
{
@@ -198,6 +212,7 @@ struct copy_segments_polygon
? geometry::exterior_ring(polygon)
: range::at(geometry::interior_rings(polygon), seg_id.ring_index),
seg_id, to_index,
strategy,
robust_policy,
current_output
);
@@ -212,12 +227,14 @@ struct copy_segments_box
<
typename Box,
typename SegmentIdentifier,
typename SideStrategy,
typename RobustPolicy,
typename RangeOut
>
static inline void apply(Box const& box,
SegmentIdentifier const& seg_id,
signed_size_type to_index,
SideStrategy const& strategy,
RobustPolicy const& robust_policy,
RangeOut& current_output)
{
@@ -238,7 +255,7 @@ struct copy_segments_box
for (signed_size_type i = 0; i < count; i++, index++)
{
detail::overlay::append_no_dups_or_spikes(current_output,
bp[index % 5], robust_policy);
bp[index % 5], strategy, robust_policy);
}
}
@@ -252,12 +269,14 @@ struct copy_segments_multi
<
typename MultiGeometry,
typename SegmentIdentifier,
typename SideStrategy,
typename RobustPolicy,
typename RangeOut
>
static inline void apply(MultiGeometry const& multi_geometry,
SegmentIdentifier const& seg_id,
signed_size_type to_index,
SideStrategy const& strategy,
RobustPolicy const& robust_policy,
RangeOut& current_output)
{
@@ -271,6 +290,7 @@ struct copy_segments_multi
// Call the single-version
Policy::apply(range::at(multi_geometry, seg_id.multi_index),
seg_id, to_index,
strategy,
robust_policy,
current_output);
}
@@ -340,12 +360,14 @@ template
bool Reverse,
typename Geometry,
typename SegmentIdentifier,
typename SideStrategy,
typename RobustPolicy,
typename RangeOut
>
inline void copy_segments(Geometry const& geometry,
SegmentIdentifier const& seg_id,
signed_size_type to_index,
SideStrategy const& strategy,
RobustPolicy const& robust_policy,
RangeOut& range_out)
{
@@ -355,7 +377,7 @@ inline void copy_segments(Geometry const& geometry,
<
typename tag<Geometry>::type,
Reverse
>::apply(geometry, seg_id, to_index, robust_policy, range_out);
>::apply(geometry, seg_id, to_index, strategy, robust_policy, range_out);
}

View File

@@ -1,6 +1,12 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2017.
// Modifications copyright (c) 2017 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
@@ -19,20 +25,21 @@
# include <iostream>
# include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
# include <boost/geometry/io/wkt/wkt.hpp>
# define BOOST_GEOMETRY_DEBUG_IDENTIFIER
# if ! defined(BOOST_GEOMETRY_DEBUG_IDENTIFIER)
# define BOOST_GEOMETRY_DEBUG_IDENTIFIER
#endif
#endif
#include <boost/range.hpp>
#include <boost/geometry/iterators/ever_circling_iterator.hpp>
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
#include <boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp>
#include <boost/geometry/algorithms/detail/overlay/handle_colocations.hpp>
#include <boost/geometry/algorithms/detail/overlay/handle_self_turns.hpp>
#include <boost/geometry/algorithms/detail/overlay/is_self_turn.hpp>
#include <boost/geometry/algorithms/detail/overlay/less_by_segment_ratio.hpp>
#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
#include <boost/geometry/algorithms/detail/overlay/sort_by_side.hpp>
#include <boost/geometry/policies/robustness/robust_type.hpp>
#include <boost/geometry/strategies/side.hpp>
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
# include <boost/geometry/algorithms/detail/overlay/check_enrich.hpp>
#endif
@@ -45,6 +52,21 @@ namespace boost { namespace geometry
namespace detail { namespace overlay
{
template <typename Turns>
struct discarded_turn
{
discarded_turn(Turns const& turns)
: m_turns(turns)
{}
template <typename IndexedTurn>
inline bool operator()(IndexedTurn const& indexed) const
{
return m_turns[indexed.turn_index].discarded;
}
Turns const& m_turns;
};
// Sorts IP-s of this ring on segment-identifier, and if on same segment,
// on distance.
@@ -58,15 +80,14 @@ template
typename Turns,
typename Geometry1, typename Geometry2,
typename RobustPolicy,
typename Strategy
typename SideStrategy
>
inline void enrich_sort(Operations& operations,
Turns const& turns,
operation_type for_operation,
Geometry1 const& geometry1,
Geometry2 const& geometry2,
RobustPolicy const& robust_policy,
Strategy const& /*strategy*/)
SideStrategy const& strategy)
{
std::sort(boost::begin(operations),
boost::end(operations),
@@ -76,13 +97,15 @@ inline void enrich_sort(Operations& operations,
typename boost::range_value<Operations>::type,
Geometry1, Geometry2,
RobustPolicy,
SideStrategy,
Reverse1, Reverse2
>(turns, for_operation, geometry1, geometry2, robust_policy));
>(turns, geometry1, geometry2, robust_policy, strategy));
}
template <typename Operations, typename Turns>
inline void enrich_assign(Operations& operations, Turns& turns)
inline void enrich_assign(Operations& operations, Turns& turns,
bool check_turns)
{
typedef typename boost::range_value<Turns>::type turn_type;
typedef typename turn_type::turn_operation_type op_type;
@@ -103,15 +126,18 @@ inline void enrich_assign(Operations& operations, Turns& turns)
turn_type& turn = turns[it->turn_index];
op_type& op = turn.operations[it->operation_index];
// Normal behaviour: next should point at next turn:
if (it->turn_index == next->turn_index)
if (check_turns && it->turn_index == next->turn_index)
{
// Normal behaviour: next points at next turn, increase next.
// For dissolve this should not be done, turn_index is often
// the same for two consecutive operations
++next;
}
// Cluster behaviour: next should point after cluster, unless
// their seg_ids are not the same
while (turn.cluster_id != -1
// (For dissolve, this is still to be examined - TODO)
while (turn.is_clustered()
&& it->turn_index != next->turn_index
&& turn.cluster_id == turns[next->turn_index].cluster_id
&& op.seg_id == turns[next->turn_index].operations[next->operation_index].seg_id)
@@ -135,6 +161,11 @@ inline void enrich_assign(Operations& operations, Turns& turns)
// (this is one not circular therefore fraction is considered)
op.enriched.next_ip_index = static_cast<signed_size_type>(next->turn_index);
}
if (! check_turns)
{
++next;
}
}
}
@@ -145,7 +176,7 @@ inline void enrich_assign(Operations& operations, Turns& turns)
it != boost::end(operations);
++it)
{
op_type& op = turns[it->turn_index]
op_type const& op = turns[it->turn_index]
.operations[it->operation_index];
std::cout << it->turn_index
@@ -169,11 +200,85 @@ inline void enrich_assign(Operations& operations, Turns& turns)
}
template <typename Operations, typename Turns>
inline void enrich_adapt(Operations& operations, Turns& turns)
{
typedef typename boost::range_value<Turns>::type turn_type;
typedef typename turn_type::turn_operation_type op_type;
typedef typename boost::range_value<Operations>::type indexed_turn_type;
if (operations.size() < 3)
{
// If it is empty, or contains one or two turns, it makes no sense
return;
}
// Operations is a vector of indexed_turn_operation<>
// Last index:
std::size_t const x = operations.size() - 1;
bool next_phase = false;
for (std::size_t i = 0; i < operations.size(); i++)
{
indexed_turn_type const& indexed = operations[i];
turn_type& turn = turns[indexed.turn_index];
op_type& op = turn.operations[indexed.operation_index];
// Previous/next index
std::size_t const p = i > 0 ? i - 1 : x;
std::size_t const n = i < x ? i + 1 : 0;
turn_type const& next_turn = turns[operations[n].turn_index];
op_type const& next_op = next_turn.operations[operations[n].operation_index];
if (op.seg_id.segment_index == next_op.seg_id.segment_index)
{
turn_type const& prev_turn = turns[operations[p].turn_index];
op_type const& prev_op = prev_turn.operations[operations[p].operation_index];
if (op.seg_id.segment_index == prev_op.seg_id.segment_index)
{
op.enriched.startable = false;
next_phase = true;
}
}
}
if (! next_phase)
{
return;
}
// Discard turns which are both non-startable
next_phase = false;
for (typename boost::range_iterator<Turns>::type
it = boost::begin(turns);
it != boost::end(turns);
++it)
{
turn_type& turn = *it;
if (! turn.operations[0].enriched.startable
&& ! turn.operations[1].enriched.startable)
{
turn.discarded = true;
next_phase = true;
}
}
if (! next_phase)
{
return;
}
// Remove discarded turns from operations to avoid having them as next turn
discarded_turn<Turns> const predicate(turns);
operations.erase(std::remove_if(boost::begin(operations),
boost::end(operations), predicate), boost::end(operations));
}
template <typename Turns, typename MappedVector>
inline void create_map(Turns const& turns,
detail::overlay::operation_type for_operation,
MappedVector& mapped_vector)
inline void create_map(Turns const& turns, MappedVector& mapped_vector)
{
typedef typename boost::range_value<Turns>::type turn_type;
typedef typename turn_type::container_type container_type;
@@ -195,15 +300,6 @@ inline void create_map(Turns const& turns,
continue;
}
if (for_operation == operation_intersection
&& turn.cluster_id == -1
&& turn.both(operation_union))
{
// Only include uu turns if part of cluster (to block potential paths),
// otherwise they can block possibly viable paths
continue;
}
std::size_t op_index = 0;
for (typename boost::range_iterator<container_type const>::type
op_it = boost::begin(turn.operations);
@@ -225,6 +321,52 @@ inline void create_map(Turns const& turns,
}
}
template <typename Point1, typename Point2>
inline typename geometry::coordinate_type<Point1>::type
distance_measure(Point1 const& a, Point2 const& b)
{
// TODO: use comparable distance for point-point instead - but that
// causes currently cycling include problems
typedef typename geometry::coordinate_type<Point1>::type ctype;
ctype const dx = get<0>(a) - get<0>(b);
ctype const dy = get<1>(a) - get<1>(b);
return dx * dx + dy * dy;
}
template <typename Turns>
inline void calculate_remaining_distance(Turns& turns)
{
typedef typename boost::range_value<Turns>::type turn_type;
typedef typename turn_type::turn_operation_type op_type;
for (typename boost::range_iterator<Turns>::type
it = boost::begin(turns);
it != boost::end(turns);
++it)
{
turn_type& turn = *it;
op_type& op0 = turn.operations[0];
op_type& op1 = turn.operations[1];
if (op0.remaining_distance != 0
|| op1.remaining_distance != 0)
{
continue;
}
signed_size_type const to_index0 = op0.enriched.get_next_turn_index();
signed_size_type const to_index1 = op1.enriched.get_next_turn_index();
if (to_index0 >= 0
&& to_index1 >= 0
&& to_index0 != to_index1)
{
op0.remaining_distance = distance_measure(turn.point, turns[to_index0].point);
op1.remaining_distance = distance_measure(turn.point, turns[to_index1].point);
}
}
}
}} // namespace detail::overlay
#endif //DOXYGEN_NO_DETAIL
@@ -239,7 +381,7 @@ inline void create_map(Turns const& turns,
\tparam Clusters type of cluster container
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\tparam Strategy side strategy type
\tparam SideStrategy side strategy type
\param turns container containing intersection points
\param clusters container containing clusters
\param geometry1 \param_geometry
@@ -255,16 +397,22 @@ template
typename Clusters,
typename Geometry1, typename Geometry2,
typename RobustPolicy,
typename Strategy
typename SideStrategy
>
inline void enrich_intersection_points(Turns& turns,
Clusters& clusters,
Geometry1 const& geometry1, Geometry2 const& geometry2,
RobustPolicy const& robust_policy,
Strategy const& strategy)
SideStrategy const& strategy)
{
static const detail::overlay::operation_type for_operation
static const detail::overlay::operation_type target_operation
= detail::overlay::operation_from_overlay<OverlayType>::value;
static const detail::overlay::operation_type opposite_operation
= target_operation == detail::overlay::operation_union
? detail::overlay::operation_intersection
: detail::overlay::operation_union;
static const bool is_dissolve = OverlayType == overlay_dissolve;
typedef typename boost::range_value<Turns>::type turn_type;
typedef typename turn_type::turn_operation_type op_type;
typedef detail::overlay::indexed_turn_operation
@@ -278,27 +426,67 @@ inline void enrich_intersection_points(Turns& turns,
std::vector<indexed_turn_operation>
> mapped_vector_type;
bool has_cc = false;
bool const has_colocations
= detail::overlay::handle_colocations<Reverse1, Reverse2>(turns,
= detail::overlay::handle_colocations<Reverse1, Reverse2, OverlayType>(turns,
clusters, geometry1, geometry2);
// Discard none turns, if any
// Discard turns not part of target overlay
for (typename boost::range_iterator<Turns>::type
it = boost::begin(turns);
it != boost::end(turns);
++it)
{
if (it->both(detail::overlay::operation_none))
turn_type& turn = *it;
if (turn.both(detail::overlay::operation_none)
|| turn.both(opposite_operation)
|| turn.both(detail::overlay::operation_blocked)
|| (detail::overlay::is_self_turn<OverlayType>(turn)
&& ! turn.is_clustered()
&& ! turn.both(target_operation)))
{
it->discarded = true;
// For all operations, discard xx and none/none
// For intersections, remove uu to avoid the need to travel
// a union (during intersection) in uu/cc clusters (e.g. #31,#32,#33)
// The ux is necessary to indicate impossible paths
// (especially if rescaling is removed)
// Similarly, for union, discard ii and ix
// For self-turns, only keep uu / ii
turn.discarded = true;
turn.cluster_id = -1;
continue;
}
if (! turn.discarded
&& turn.both(detail::overlay::operation_continue))
{
has_cc = true;
}
}
if (! is_dissolve)
{
detail::overlay::discard_closed_turns
<
OverlayType,
target_operation
>::apply(turns, clusters, geometry1, geometry2);
detail::overlay::discard_open_turns
<
OverlayType,
target_operation
>::apply(turns, clusters, geometry1, geometry2);
}
// Create a map of vectors of indexed operation-types to be able
// to sort intersection points PER RING
mapped_vector_type mapped_vector;
detail::overlay::create_map(turns, for_operation, mapped_vector);
detail::overlay::create_map(turns, mapped_vector);
// No const-iterator; contents of mapped copy is temporary,
// and changed by enrich
@@ -312,7 +500,7 @@ inline void enrich_intersection_points(Turns& turns,
<< mit->first << std::endl;
#endif
detail::overlay::enrich_sort<Reverse1, Reverse2>(
mit->second, turns, for_operation,
mit->second, turns,
geometry1, geometry2,
robust_policy, strategy);
}
@@ -326,13 +514,32 @@ inline void enrich_intersection_points(Turns& turns,
std::cout << "ENRICH-assign Ring "
<< mit->first << std::endl;
#endif
detail::overlay::enrich_assign(mit->second, turns);
if (is_dissolve)
{
detail::overlay::enrich_adapt(mit->second, turns);
}
detail::overlay::enrich_assign(mit->second, turns, ! is_dissolve);
}
if (has_colocations)
{
detail::overlay::gather_cluster_properties<Reverse1, Reverse2>(
clusters, turns, for_operation, geometry1, geometry2);
// First gather cluster properties (using even clusters with
// discarded turns - for open turns), then clean up clusters
detail::overlay::gather_cluster_properties
<
Reverse1,
Reverse2,
OverlayType
>(clusters, turns, target_operation,
geometry1, geometry2, strategy);
detail::overlay::cleanup_clusters(turns, clusters);
}
if (has_cc)
{
detail::overlay::calculate_remaining_distance(turns);
}
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH

View File

@@ -35,12 +35,20 @@ struct enrichment_info
, travels_to_ip_index(-1)
, next_ip_index(-1)
, startable(true)
, prefer_start(true)
, count_left(0)
, count_right(0)
, rank(-1)
, zone(-1)
, only_turn_on_ring(false)
, region_id(-1)
, isolated(false)
{}
inline signed_size_type get_next_turn_index() const
{
return next_ip_index == -1 ? travels_to_ip_index : next_ip_index;
}
// vertex to which is free travel after this IP,
// so from "segment_index+1" to "travels_to_vertex_index", without IP-s,
// can be -1
@@ -53,12 +61,15 @@ struct enrichment_info
signed_size_type next_ip_index;
bool startable; // Can be used to start in traverse
bool prefer_start; // Is preferred as starting point (if true)
// Counts if polygons left/right of this operation
std::size_t count_left;
std::size_t count_right;
signed_size_type rank; // in cluster
signed_size_type zone; // open zone, in cluster
bool only_turn_on_ring; // True if it is the only turn on a ring (for clusters)
signed_size_type region_id;
bool isolated;
};

View File

@@ -1,11 +1,12 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2014.
// Modifications copyright (c) 2014 Oracle and/or its affiliates.
// This file was modified by Oracle on 2014, 2017, 2018.
// Modifications copyright (c) 2014-2018 Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// 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
@@ -26,6 +27,7 @@
#include <boost/geometry/algorithms/covered_by.hpp>
#include <boost/geometry/algorithms/clear.hpp>
#include <boost/geometry/algorithms/detail/relate/turns.hpp>
namespace boost { namespace geometry
@@ -55,21 +57,14 @@ template
typename Turn,
typename Operation,
typename LineString,
typename Polygon
typename Polygon,
typename PtInPolyStrategy
>
static inline bool last_covered_by(Turn const& turn, Operation const& op,
LineString const& linestring, Polygon const& polygon)
static inline bool last_covered_by(Turn const& /*turn*/, Operation const& op,
LineString const& linestring, Polygon const& polygon,
PtInPolyStrategy const& strategy)
{
// Check any point between the this one and the first IP
typedef typename geometry::point_type<LineString>::type point_type;
point_type point_in_between;
detail::point_on_border::midpoint_helper
<
point_type,
0, dimension<point_type>::value
>::apply(point_in_between, *(::boost::begin(linestring) + op.seg_id.segment_index), turn.point);
return geometry::covered_by(point_in_between, polygon);
return geometry::covered_by(range::at(linestring, op.seg_id.segment_index), polygon, strategy);
}
@@ -78,17 +73,19 @@ template
typename Turn,
typename Operation,
typename LineString,
typename Polygon
typename Polygon,
typename PtInPolyStrategy
>
static inline bool is_leaving(Turn const& turn, Operation const& op,
bool entered, bool first,
LineString const& linestring, Polygon const& polygon)
LineString const& linestring, Polygon const& polygon,
PtInPolyStrategy const& strategy)
{
if (op.operation == operation_union)
{
return entered
|| turn.method == method_crosses
|| (first && last_covered_by(turn, op, linestring, polygon))
|| (first && last_covered_by(turn, op, linestring, polygon, strategy))
;
}
return false;
@@ -100,11 +97,13 @@ template
typename Turn,
typename Operation,
typename LineString,
typename Polygon
typename Polygon,
typename PtInPolyStrategy
>
static inline bool is_staying_inside(Turn const& turn, Operation const& op,
bool entered, bool first,
LineString const& linestring, Polygon const& polygon)
LineString const& linestring, Polygon const& polygon,
PtInPolyStrategy const& strategy)
{
if (turn.method == method_crosses)
{
@@ -115,7 +114,7 @@ static inline bool is_staying_inside(Turn const& turn, Operation const& op,
if (is_entering(turn, op))
{
return entered || (first && last_covered_by(turn, op, linestring, polygon));
return entered || (first && last_covered_by(turn, op, linestring, polygon, strategy));
}
return false;
@@ -126,14 +125,16 @@ template
typename Turn,
typename Operation,
typename Linestring,
typename Polygon
typename Polygon,
typename PtInPolyStrategy
>
static inline bool was_entered(Turn const& turn, Operation const& op, bool first,
Linestring const& linestring, Polygon const& polygon)
Linestring const& linestring, Polygon const& polygon,
PtInPolyStrategy const& strategy)
{
if (first && (turn.method == method_collinear || turn.method == method_equal))
{
return last_covered_by(turn, op, linestring, polygon);
return last_covered_by(turn, op, linestring, polygon, strategy);
}
return false;
}
@@ -158,6 +159,7 @@ struct action_selector<overlay_intersection, RemoveSpikes>
typename LineString,
typename Point,
typename Operation,
typename Strategy,
typename RobustPolicy
>
static inline void enter(LineStringOut& current_piece,
@@ -165,12 +167,13 @@ struct action_selector<overlay_intersection, RemoveSpikes>
segment_identifier& segment_id,
signed_size_type , Point const& point,
Operation const& operation,
Strategy const& strategy,
RobustPolicy const& ,
OutputIterator& )
{
// On enter, append the intersection point and remember starting point
// TODO: we don't check on spikes for linestrings (?). Consider this.
detail::overlay::append_no_duplicates(current_piece, point);
detail::overlay::append_no_duplicates(current_piece, point, strategy.get_equals_point_point_strategy());
segment_id = operation.seg_id;
}
@@ -181,6 +184,7 @@ struct action_selector<overlay_intersection, RemoveSpikes>
typename LineString,
typename Point,
typename Operation,
typename Strategy,
typename RobustPolicy
>
static inline void leave(LineStringOut& current_piece,
@@ -188,6 +192,7 @@ struct action_selector<overlay_intersection, RemoveSpikes>
segment_identifier& segment_id,
signed_size_type index, Point const& point,
Operation const& ,
Strategy const& strategy,
RobustPolicy const& robust_policy,
OutputIterator& out)
{
@@ -196,8 +201,8 @@ struct action_selector<overlay_intersection, RemoveSpikes>
detail::copy_segments::copy_segments_linestring
<
false, RemoveSpikes
>::apply(linestring, segment_id, index, robust_policy, current_piece);
detail::overlay::append_no_duplicates(current_piece, point);
>::apply(linestring, segment_id, index, strategy, robust_policy, current_piece);
detail::overlay::append_no_duplicates(current_piece, point, strategy.get_equals_point_point_strategy());
if (::boost::size(current_piece) > 1)
{
*out++ = current_piece;
@@ -235,17 +240,9 @@ struct action_selector<overlay_intersection, RemoveSpikes>
return entered;
}
template
<
typename Point,
typename Geometry,
typename RobustPolicy
>
static inline bool included(Point const& point,
Geometry const& geometry,
RobustPolicy const& )
static inline bool included(int inside_value)
{
return geometry::covered_by(point, geometry);
return inside_value >= 0; // covered_by
}
};
@@ -263,6 +260,7 @@ struct action_selector<overlay_difference, RemoveSpikes>
typename LineString,
typename Point,
typename Operation,
typename Strategy,
typename RobustPolicy
>
static inline void enter(LineStringOut& current_piece,
@@ -270,11 +268,12 @@ struct action_selector<overlay_difference, RemoveSpikes>
segment_identifier& segment_id,
signed_size_type index, Point const& point,
Operation const& operation,
Strategy const& strategy,
RobustPolicy const& robust_policy,
OutputIterator& out)
{
normal_action::leave(current_piece, linestring, segment_id, index,
point, operation, robust_policy, out);
point, operation, strategy, robust_policy, out);
}
template
@@ -284,6 +283,7 @@ struct action_selector<overlay_difference, RemoveSpikes>
typename LineString,
typename Point,
typename Operation,
typename Strategy,
typename RobustPolicy
>
static inline void leave(LineStringOut& current_piece,
@@ -291,11 +291,12 @@ struct action_selector<overlay_difference, RemoveSpikes>
segment_identifier& segment_id,
signed_size_type index, Point const& point,
Operation const& operation,
Strategy const& strategy,
RobustPolicy const& robust_policy,
OutputIterator& out)
{
normal_action::enter(current_piece, linestring, segment_id, index,
point, operation, robust_policy, out);
point, operation, strategy, robust_policy, out);
}
template
@@ -319,17 +320,9 @@ struct action_selector<overlay_difference, RemoveSpikes>
return ! normal_action::is_entered(entered);
}
template
<
typename Point,
typename Geometry,
typename RobustPolicy
>
static inline bool included(Point const& point,
Geometry const& geometry,
RobustPolicy const& robust_policy)
static inline bool included(int inside_value)
{
return ! normal_action::included(point, geometry, robust_policy);
return ! normal_action::included(inside_value);
}
};
@@ -352,6 +345,7 @@ template
class follow
{
#ifdef BOOST_GEOMETRY_SETOPS_LA_OLD_BEHAVIOR
template <typename Turn>
struct sort_on_segment
{
@@ -398,38 +392,32 @@ class follow
}
};
#endif // BOOST_GEOMETRY_SETOPS_LA_OLD_BEHAVIOR
public :
template
<
typename Point,
typename Geometry,
typename RobustPolicy
>
static inline bool included(Point const& point,
Geometry const& geometry,
RobustPolicy const& robust_policy)
static inline bool included(int inside_value)
{
return following::action_selector
<
OverlayType, RemoveSpikes
>::included(point, geometry, robust_policy);
>::included(inside_value);
}
template
<
typename Turns,
typename OutputIterator,
typename RobustPolicy
typename RobustPolicy,
typename Strategy
>
static inline OutputIterator apply(LineString const& linestring, Polygon const& polygon,
detail::overlay::operation_type , // TODO: this parameter might be redundant
Turns& turns,
RobustPolicy const& robust_policy,
OutputIterator out)
OutputIterator out,
Strategy const& strategy)
{
typedef typename boost::range_iterator<Turns>::type turn_iterator;
typedef typename boost::range_value<Turns>::type turn_type;
@@ -440,9 +428,23 @@ public :
typedef following::action_selector<OverlayType, RemoveSpikes> action;
typename Strategy::template point_in_geometry_strategy
<
LineString, Polygon
>::type const pt_in_poly_strategy
= strategy.template get_point_in_geometry_strategy<LineString, Polygon>();
// Sort intersection points on segments-along-linestring, and distance
// (like in enrich is done for poly/poly)
// sort turns by Linear seg_id, then by fraction, then
// for same ring id: x, u, i, c
// for different ring id: c, i, u, x
#ifdef BOOST_GEOMETRY_SETOPS_LA_OLD_BEHAVIOR
std::sort(boost::begin(turns), boost::end(turns), sort_on_segment<turn_type>());
#else
typedef relate::turns::less<0, relate::turns::less_op_linear_areal_single<0> > turn_less;
std::sort(boost::begin(turns), boost::end(turns), turn_less());
#endif
LineStringOut current_piece;
geometry::segment_identifier current_segment_id(0, -1, -1, -1);
@@ -454,13 +456,13 @@ public :
{
turn_operation_iterator_type iit = boost::begin(it->operations);
if (following::was_entered(*it, *iit, first, linestring, polygon))
if (following::was_entered(*it, *iit, first, linestring, polygon, pt_in_poly_strategy))
{
debug_traverse(*it, *iit, "-> Was entered");
entered = true;
}
if (following::is_staying_inside(*it, *iit, entered, first, linestring, polygon))
if (following::is_staying_inside(*it, *iit, entered, first, linestring, polygon, pt_in_poly_strategy))
{
debug_traverse(*it, *iit, "-> Staying inside");
@@ -473,17 +475,17 @@ public :
entered = true;
action::enter(current_piece, linestring, current_segment_id,
iit->seg_id.segment_index, it->point, *iit,
robust_policy,
strategy, robust_policy,
out);
}
else if (following::is_leaving(*it, *iit, entered, first, linestring, polygon))
else if (following::is_leaving(*it, *iit, entered, first, linestring, polygon, pt_in_poly_strategy))
{
debug_traverse(*it, *iit, "-> Leaving");
entered = false;
action::leave(current_piece, linestring, current_segment_id,
iit->seg_id.segment_index, it->point, *iit,
robust_policy,
strategy, robust_policy,
out);
}
first = false;
@@ -497,7 +499,7 @@ public :
>::apply(linestring,
current_segment_id,
static_cast<signed_size_type>(boost::size(linestring) - 1),
robust_policy,
strategy, robust_policy,
current_piece);
}

View File

@@ -2,12 +2,14 @@
// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
// Copyright (c) 2014-2015, Oracle and/or its affiliates.
// Copyright (c) 2014-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_LINEAR_LINEAR_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_LINEAR_LINEAR_HPP
@@ -183,7 +185,8 @@ protected:
typename TurnIterator,
typename TurnOperationIterator,
typename SegmentIdentifier,
typename OutputIterator
typename OutputIterator,
typename SideStrategy
>
static inline OutputIterator
process_turn(TurnIterator it,
@@ -193,7 +196,8 @@ protected:
Linestring const& linestring,
LinestringOut& current_piece,
SegmentIdentifier& current_segment_id,
OutputIterator oit)
OutputIterator oit,
SideStrategy const& strategy)
{
// We don't rescale linear/linear
detail::no_rescale_policy robust_policy;
@@ -208,7 +212,7 @@ protected:
action::enter(current_piece, linestring,
current_segment_id,
op_it->seg_id.segment_index,
it->point, *op_it, robust_policy, oit);
it->point, *op_it, strategy, robust_policy, oit);
}
++enter_count;
}
@@ -223,7 +227,7 @@ protected:
action::leave(current_piece, linestring,
current_segment_id,
op_it->seg_id.segment_index,
it->point, *op_it, robust_policy, oit);
it->point, *op_it, strategy, robust_policy, oit);
}
}
else if ( FollowIsolatedPoints
@@ -249,14 +253,16 @@ protected:
template
<
typename SegmentIdentifier,
typename OutputIterator
typename OutputIterator,
typename SideStrategy
>
static inline OutputIterator
process_end(bool entered,
Linestring const& linestring,
SegmentIdentifier const& current_segment_id,
LinestringOut& current_piece,
OutputIterator oit)
OutputIterator oit,
SideStrategy const& strategy)
{
if ( action::is_entered(entered) )
{
@@ -269,6 +275,7 @@ protected:
>::apply(linestring,
current_segment_id,
static_cast<signed_size_type>(boost::size(linestring) - 1),
strategy,
robust_policy,
current_piece);
}
@@ -283,11 +290,12 @@ protected:
}
public:
template <typename TurnIterator, typename OutputIterator>
template <typename TurnIterator, typename OutputIterator, typename SideStrategy>
static inline OutputIterator
apply(Linestring const& linestring, Linear const&,
TurnIterator first, TurnIterator beyond,
OutputIterator oit)
OutputIterator oit,
SideStrategy const& strategy)
{
// Iterate through all intersection points (they are
// ordered along the each line)
@@ -304,7 +312,8 @@ public:
entered, enter_count,
linestring,
current_piece, current_segment_id,
oit);
oit,
strategy);
}
#if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW)
@@ -318,7 +327,8 @@ public:
return process_end(entered, linestring,
current_segment_id, current_piece,
oit);
oit,
strategy);
}
};
@@ -413,11 +423,12 @@ protected:
};
public:
template <typename TurnIterator, typename OutputIterator>
template <typename TurnIterator, typename OutputIterator, typename SideStrategy>
static inline OutputIterator
apply(MultiLinestring const& multilinestring, Linear const& linear,
TurnIterator first, TurnIterator beyond,
OutputIterator oit)
OutputIterator oit,
SideStrategy const& strategy)
{
BOOST_GEOMETRY_ASSERT( first != beyond );
@@ -447,7 +458,7 @@ public:
has_other_multi_id(current_multi_id));
oit = Base::apply(*(ls_first + current_multi_id),
linear, per_ls_current, per_ls_next, oit);
linear, per_ls_current, per_ls_next, oit, strategy);
signed_size_type next_multi_id = -1;
linestring_iterator ls_next = ls_beyond;

View File

@@ -44,12 +44,16 @@ template
>
struct get_turn_without_info
{
template <typename Strategy, typename RobustPolicy, typename OutputIterator>
static inline OutputIterator apply(
Point1 const& pi, Point1 const& pj, Point1 const& /*pk*/,
Point2 const& qi, Point2 const& qj, Point2 const& /*qk*/,
bool /*is_p_first*/, bool /*is_p_last*/,
bool /*is_q_first*/, bool /*is_q_last*/,
template
<
typename UniqueSubRange1,
typename UniqueSubRange2,
typename Strategy,
typename RobustPolicy,
typename OutputIterator
>
static inline OutputIterator apply(UniqueSubRange1 const& range_p,
UniqueSubRange2 const& range_q,
TurnInfo const& ,
Strategy const& strategy,
RobustPolicy const& robust_policy,
@@ -71,6 +75,10 @@ struct get_turn_without_info
typedef model::referring_segment<Point1 const> segment_type1;
typedef model::referring_segment<Point2 const> segment_type2;
Point1 const& pi = range_p.at(0);
Point1 const& pj = range_p.at(1);
Point2 const& qi = range_q.at(0);
Point2 const& qj = range_q.at(1);
segment_type1 p1(pi, pj);
segment_type2 q1(qi, qj);

View File

@@ -2,6 +2,11 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2017.
// Modifications copyright (c) 2017 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)
@@ -31,20 +36,15 @@ namespace detail { namespace overlay
but we still need to know which comes first.
Therefore, it is useful that using sides we are able to discover this.
*/
template <typename Point1>
struct get_relative_order
{
typedef typename strategy::side::services::default_strategy
<
typename cs_tag<Point1>::type
>::type strategy;
template <typename Point>
template <typename Point, typename SideStrategy>
static inline int value_via_product(Point const& ti, Point const& tj,
Point const& ui, Point const& uj, int factor)
Point const& ui, Point const& uj, int factor,
SideStrategy const& strategy)
{
int const side_ti_u = strategy::apply(ti, tj, ui);
int const side_tj_u = strategy::apply(ti, tj, uj);
int const side_ti_u = strategy.apply(ti, tj, ui);
int const side_tj_u = strategy.apply(ti, tj, uj);
#ifdef BOOST_GEOMETRY_DEBUG_RELATIVE_ORDER
std::cout << (factor == 1 ? " r//s " : " s//r ")
@@ -57,13 +57,15 @@ struct get_relative_order
}
template <typename Point1, typename SideStrategy>
static inline int apply(
Point1 const& pi, Point1 const& pj,
Point1 const& ri, Point1 const& rj,
Point1 const& si, Point1 const& sj)
Point1 const& si, Point1 const& sj,
SideStrategy const& strategy)
{
int const side_ri_p = strategy::apply(pi, pj, ri);
int const side_si_p = strategy::apply(pi, pj, si);
int const side_ri_p = strategy.apply(pi, pj, ri);
int const side_si_p = strategy.apply(pi, pj, si);
#ifdef BOOST_GEOMETRY_DEBUG_RELATIVE_ORDER
int const side_rj_p = strategy::apply(pi, pj, rj);
@@ -72,10 +74,10 @@ struct get_relative_order
std::cout << " s//p: " << side_si_p << " / " << side_sj_p;
#endif
int value = value_via_product(si, sj, ri, rj, 1);
int value = value_via_product(si, sj, ri, rj, 1, strategy);
if (value == 0)
{
value = value_via_product(ri, rj, si, sj, -1);
value = value_via_product(ri, rj, si, sj, -1, strategy);
}
int const order = side_ri_p * side_ri_p * side_si_p * value;

View File

@@ -3,8 +3,8 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2015, 2017.
// Modifications copyright (c) 2015-2017 Oracle and/or its affiliates.
// This file was modified by Oracle on 2015, 2017, 2018, 2019.
// Modifications copyright (c) 2015-2019 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -21,6 +21,7 @@
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/core/exception.hpp>
#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
@@ -84,7 +85,7 @@ struct base_turn_handler
return side1 * side2 == 1;
}
// Both continue
// Both get the same operation
template <typename TurnInfo>
static inline void both(TurnInfo& ti, operation_type const op)
{
@@ -130,6 +131,17 @@ struct base_turn_handler
? 1 : 0;
}
template <typename Point1, typename Point2>
static inline typename geometry::coordinate_type<Point1>::type
distance_measure(Point1 const& a, Point2 const& b)
{
// TODO: use comparable distance for point-point instead - but that
// causes currently cycling include problems
typedef typename geometry::coordinate_type<Point1>::type ctype;
ctype const dx = get<0>(a) - get<0>(b);
ctype const dy = get<1>(a) - get<1>(b);
return dx * dx + dy * dy;
}
};
@@ -143,15 +155,14 @@ struct touch_interior : public base_turn_handler
template
<
unsigned int Index,
typename Point1,
typename Point2,
typename UniqueSubRange1,
typename UniqueSubRange2,
typename IntersectionInfo,
typename DirInfo,
typename SidePolicy
>
static inline void apply(
Point1 const& , Point1 const& , Point1 const& ,
Point2 const& , Point2 const& , Point2 const& ,
static inline void apply(UniqueSubRange1 const& range_p,
UniqueSubRange2 const& range_q,
TurnInfo& ti,
IntersectionInfo const& intersection_info,
DirInfo const& dir_info,
@@ -169,8 +180,10 @@ struct touch_interior : public base_turn_handler
static unsigned int const index_p = Index;
static unsigned int const index_q = 1 - Index;
bool const has_pk = ! range_p.is_last_segment();
bool const has_qk = ! range_q.is_last_segment();
int const side_qi_p = dir_info.sides.template get<index_q, 0>();
int const side_qk_p = side.qk_wrt_p1();
int const side_qk_p = has_qk ? side.qk_wrt_p1() : 0;
if (side_qi_p == -side_qk_p)
{
@@ -183,20 +196,36 @@ struct touch_interior : public base_turn_handler
return;
}
int const side_qk_q = side.qk_wrt_q1();
int const side_qk_q = has_qk ? side.qk_wrt_q1() : 0;
// Only necessary if rescaling is turned off:
int const side_pj_q2 = has_qk ? side.pj_wrt_q2() : 0;
if (side_qi_p == -1 && side_qk_p == -1 && side_qk_q == 1)
{
// Q turns left on the right side of P (test "MR3")
// Both directions for "intersection"
both(ti, operation_intersection);
ti.touch_only = true;
}
else if (side_qi_p == 1 && side_qk_p == 1 && side_qk_q == -1)
{
// Q turns right on the left side of P (test "ML3")
// Union: take both operation
// Intersection: skip
both(ti, operation_union);
if (has_qk && side_pj_q2 == -1)
{
// Q turns right on the left side of P (test "ML3")
// Union: take both operations
// Intersection: skip
both(ti, operation_union);
}
else
{
// q2 is collinear with p1, so it does not turn back. This
// can happen in floating point precision. In this case,
// block one of the operations to avoid taking that path.
ti.operations[index_p].operation = operation_union;
ti.operations[index_q].operation = operation_blocked;
}
ti.touch_only = true;
}
else if (side_qi_p == side_qk_p && side_qi_p == side_qk_q)
{
@@ -205,8 +234,32 @@ struct touch_interior : public base_turn_handler
// Union: take left turn (Q if Q turns left, P if Q turns right)
// Intersection: other turn
unsigned int index = side_qk_q == 1 ? index_q : index_p;
if (has_qk && side_pj_q2 == 0)
{
// Even though sides xk w.r.t. 1 are distinct, pj is collinear
// with q. Therefore swap the path
index = 1 - index;
}
if (has_pk && has_qk && opposite(side_pj_q2, side_qi_p))
{
// Without rescaling, floating point requires extra measures
int const side_qj_p1 = side.qj_wrt_p1();
int const side_qj_p2 = side.qj_wrt_p2();
if (same(side_qj_p1, side_qj_p2))
{
int const side_pj_q1 = side.pj_wrt_q1();
if (opposite(side_pj_q1, side_pj_q2))
{
index = 1 - index;
}
}
}
ti.operations[index].operation = operation_union;
ti.operations[1 - index].operation = operation_intersection;
ti.touch_only = true;
}
else if (side_qk_p == 0)
{
@@ -216,10 +269,16 @@ struct touch_interior : public base_turn_handler
// Collinearly in the same direction
// (Q comes from left of P and turns left,
// OR Q comes from right of P and turns right)
// Omit intersection point.
// Omit second intersection point.
// Union: just continue
// Intersection: just continue
both(ti, operation_continue);
// Calculate remaining distance.
// Q arrives at p, at point qj, so use qk for q
// and use pj for p
ti.operations[index_p].remaining_distance = distance_measure(ti.point, range_p.at(1));
ti.operations[index_q].remaining_distance = distance_measure(ti.point, range_q.at(2));
}
else
{
@@ -263,15 +322,14 @@ struct touch : public base_turn_handler
template
<
typename Point1,
typename Point2,
typename UniqueSubRange1,
typename UniqueSubRange2,
typename IntersectionInfo,
typename DirInfo,
typename SidePolicy
>
static inline void apply(
Point1 const& , Point1 const& , Point1 const& ,
Point2 const& , Point2 const& , Point2 const& ,
static inline void apply(UniqueSubRange1 const& range_p,
UniqueSubRange2 const& range_q,
TurnInfo& ti,
IntersectionInfo const& intersection_info,
DirInfo const& dir_info,
@@ -279,17 +337,20 @@ struct touch : public base_turn_handler
{
assign_point(ti, method_touch, intersection_info, 0);
bool const has_pk = ! range_p.is_last_segment();
bool const has_qk = ! range_q.is_last_segment();
int const side_qi_p1 = dir_info.sides.template get<1, 0>();
int const side_qk_p1 = side.qk_wrt_p1();
int const side_qk_p1 = has_qk ? side.qk_wrt_p1() : 0;
// If Qi and Qk are both at same side of Pi-Pj,
// or collinear (so: not opposite sides)
if (! opposite(side_qi_p1, side_qk_p1))
{
int const side_pk_q2 = side.pk_wrt_q2();
int const side_pk_p = side.pk_wrt_p1();
int const side_qk_q = side.qk_wrt_q1();
int const side_pk_q2 = has_pk && has_qk ? side.pk_wrt_q2() : 0;
int const side_pk_p = has_pk ? side.pk_wrt_p1() : 0;
int const side_qk_q = has_qk ? side.qk_wrt_q1() : 0;
bool const q_turns_left = side_qk_q == 1;
bool const block_q = side_qk_p1 == 0
@@ -312,7 +373,7 @@ struct touch : public base_turn_handler
return;
}
int const side_pk_q1 = side.pk_wrt_q1();
int const side_pk_q1 = has_pk && has_qk ? side.pk_wrt_q1() : 0;
// Collinear opposite case -> block P
@@ -346,6 +407,7 @@ struct touch : public base_turn_handler
if (side_pk_q2 == -side_qk_q)
{
ui_else_iu(! q_turns_left, ti);
ti.touch_only = true;
return;
}
@@ -358,6 +420,10 @@ struct touch : public base_turn_handler
{
ti.operations[1].operation = operation_blocked;
}
else
{
ti.touch_only = true;
}
//block_second(block_q, ti);
return;
}
@@ -373,6 +439,10 @@ struct touch : public base_turn_handler
: side_qi_p1 == 1 || side_qk_p1 == 1
? operation_union
: operation_intersection;
if (! block_q)
{
ti.touch_only = true;
}
return;
}
@@ -380,13 +450,13 @@ struct touch : public base_turn_handler
else
{
// From left to right or from right to left
int const side_pk_p = side.pk_wrt_p1();
int const side_pk_p = has_pk ? side.pk_wrt_p1() : 0;
bool const right_to_left = side_qk_p1 == 1;
// If p turns into direction of qi (1,2)
if (side_pk_p == side_qi_p1)
{
int const side_pk_q1 = side.pk_wrt_q1();
int const side_pk_q1 = has_pk ? side.pk_wrt_q1() : 0;
// Collinear opposite case -> block P
if (side_pk_q1 == 0)
@@ -400,6 +470,7 @@ struct touch : public base_turn_handler
if (side_pk_q1 == side_qk_p1)
{
uu_else_ii(right_to_left, ti);
ti.touch_only = true;
return;
}
}
@@ -407,7 +478,7 @@ struct touch : public base_turn_handler
// If p turns into direction of qk (4,5)
if (side_pk_p == side_qk_p1)
{
int const side_pk_q2 = side.pk_wrt_q2();
int const side_pk_q2 = has_pk ? side.pk_wrt_q2() : 0;
// Collinear case -> lines join, continue
if (side_pk_q2 == 0)
@@ -418,6 +489,7 @@ struct touch : public base_turn_handler
if (side_pk_q2 == side_qk_p1)
{
ui_else_iu(right_to_left, ti);
ti.touch_only = true;
return;
}
}
@@ -425,21 +497,6 @@ struct touch : public base_turn_handler
ui_else_iu(! right_to_left, ti);
return;
}
#ifdef BOOST_GEOMETRY_DEBUG_GET_TURNS
// Normally a robustness issue.
// TODO: more research if still occuring
std::cout << "Not yet handled" << std::endl
<< "pi " << get<0>(pi) << " , " << get<1>(pi)
<< " pj " << get<0>(pj) << " , " << get<1>(pj)
<< " pk " << get<0>(pk) << " , " << get<1>(pk)
<< std::endl
<< "qi " << get<0>(qi) << " , " << get<1>(qi)
<< " qj " << get<0>(qj) << " , " << get<1>(qj)
<< " qk " << get<0>(qk) << " , " << get<1>(qk)
<< std::endl;
#endif
}
};
@@ -452,15 +509,14 @@ struct equal : public base_turn_handler
{
template
<
typename Point1,
typename Point2,
typename UniqueSubRange1,
typename UniqueSubRange2,
typename IntersectionInfo,
typename DirInfo,
typename SidePolicy
>
static inline void apply(
Point1 const& , Point1 const& , Point1 const& ,
Point2 const& , Point2 const& , Point2 const& ,
static inline void apply(UniqueSubRange1 const& range_p,
UniqueSubRange2 const& range_q,
TurnInfo& ti,
IntersectionInfo const& info,
DirInfo const& ,
@@ -469,10 +525,12 @@ struct equal : public base_turn_handler
// Copy the intersection point in TO direction
assign_point(ti, method_equal, info, non_opposite_to_index(info));
int const side_pk_q2 = side.pk_wrt_q2();
int const side_pk_p = side.pk_wrt_p1();
int const side_qk_p = side.qk_wrt_p1();
bool const has_pk = ! range_p.is_last_segment();
bool const has_qk = ! range_q.is_last_segment();
int const side_pk_q2 = has_pk && has_qk ? side.pk_wrt_q2() : 0;
int const side_pk_p = has_pk ? side.pk_wrt_p1() : 0;
int const side_qk_p = has_qk ? side.qk_wrt_p1() : 0;
// If pk is collinear with qj-qk, they continue collinearly.
// This can be on either side of p1 (== q1), or collinear
@@ -511,12 +569,14 @@ struct equal_opposite : public base_turn_handler
{
template
<
typename Point1,
typename Point2,
typename UniqueSubRange1,
typename UniqueSubRange2,
typename OutputIterator,
typename IntersectionInfo
>
static inline void apply(Point1 const& pi, Point2 const& qi,
static inline void apply(
UniqueSubRange1 const& /*range_p*/,
UniqueSubRange2 const& /*range_q*/,
/* by value: */ TurnInfo tp,
OutputIterator& out,
IntersectionInfo const& intersection_info)
@@ -532,7 +592,6 @@ struct equal_opposite : public base_turn_handler
for (unsigned int i = 0; i < intersection_info.i_info().count; i++)
{
assign_point(tp, method_none, intersection_info.i_info(), i);
AssignPolicy::apply(tp, pi, qi, intersection_info);
*out++ = tp;
}
}
@@ -579,15 +638,15 @@ struct collinear : public base_turn_handler
*/
template
<
typename Point1,
typename Point2,
typename UniqueSubRange1,
typename UniqueSubRange2,
typename IntersectionInfo,
typename DirInfo,
typename SidePolicy
>
static inline void apply(
Point1 const& , Point1 const& pj, Point1 const& pk,
Point2 const& , Point2 const& qj, Point2 const& qk,
UniqueSubRange1 const& range_p,
UniqueSubRange2 const& range_q,
TurnInfo& ti,
IntersectionInfo const& info,
DirInfo const& dir_info,
@@ -600,8 +659,10 @@ struct collinear : public base_turn_handler
// Should not be 0, this is checked before
BOOST_GEOMETRY_ASSERT(arrival != 0);
int const side_p = side.pk_wrt_p1();
int const side_q = side.qk_wrt_q1();
bool const has_pk = ! range_p.is_last_segment();
bool const has_qk = ! range_q.is_last_segment();
int const side_p = has_pk ? side.pk_wrt_p1() : 0;
int const side_q = has_qk ? side.qk_wrt_q1() : 0;
// If p arrives, use p, else use q
int const side_p_or_q = arrival == 1
@@ -628,25 +689,13 @@ struct collinear : public base_turn_handler
// Calculate remaining distance. If it continues collinearly it is
// measured until the end of the next segment
ti.operations[0].remaining_distance
= side_p == 0
? distance_measure(ti.point, pk)
: distance_measure(ti.point, pj);
= side_p == 0 && has_pk
? distance_measure(ti.point, range_p.at(2))
: distance_measure(ti.point, range_p.at(1));
ti.operations[1].remaining_distance
= side_q == 0
? distance_measure(ti.point, qk)
: distance_measure(ti.point, qj);
}
template <typename Point1, typename Point2>
static inline typename geometry::coordinate_type<Point1>::type
distance_measure(Point1 const& a, Point2 const& b)
{
// TODO: use comparable distance for point-point instead - but that
// causes currently cycling include problems
typedef typename geometry::coordinate_type<Point1>::type ctype;
ctype const dx = get<0>(a) - get<0>(b);
ctype const dy = get<1>(a) - get<1>(b);
return dx * dx + dy * dy;
= side_q == 0 && has_qk
? distance_measure(ti.point, range_q.at(2))
: distance_measure(ti.point, range_q.at(1));
}
};
@@ -685,13 +734,10 @@ private :
template
<
unsigned int Index,
typename Point1,
typename Point2,
typename IntersectionInfo
>
static inline bool set_tp(Point1 const& , Point1 const& , Point1 const& , int side_rk_r,
bool const handle_robustness,
Point2 const& , Point2 const& , int side_rk_s,
static inline bool set_tp(int side_rk_r, bool handle_robustness,
int side_rk_s,
TurnInfo& tp, IntersectionInfo const& intersection_info)
{
BOOST_STATIC_ASSERT(Index <= 1);
@@ -743,15 +789,15 @@ public:
template
<
typename Point1,
typename Point2,
typename UniqueSubRange1,
typename UniqueSubRange2,
typename OutputIterator,
typename IntersectionInfo,
typename SidePolicy
>
static inline void apply(
Point1 const& pi, Point1 const& pj, Point1 const& pk,
Point2 const& qi, Point2 const& qj, Point2 const& qk,
UniqueSubRange1 const& range_p,
UniqueSubRange2 const& range_q,
// Opposite collinear can deliver 2 intersection points,
TurnInfo const& tp_model,
@@ -760,22 +806,24 @@ public:
IntersectionInfo const& intersection_info,
SidePolicy const& side)
{
apply(pi, pj, pk, qi, qj, qk, tp_model, out, intersection_info, side, empty_transformer);
apply(range_p, range_q,
tp_model, out, intersection_info, side, empty_transformer);
}
public:
template
<
typename Point1,
typename Point2,
typename UniqueSubRange1,
typename UniqueSubRange2,
typename OutputIterator,
typename IntersectionInfo,
typename SidePolicy,
typename TurnTransformer
>
static inline void apply(
Point1 const& pi, Point1 const& pj, Point1 const& pk,
Point2 const& qi, Point2 const& qj, Point2 const& qk,
UniqueSubRange1 const& range_p,
UniqueSubRange2 const& range_q,
// Opposite collinear can deliver 2 intersection points,
TurnInfo const& tp_model,
@@ -783,8 +831,7 @@ public:
IntersectionInfo const& info,
SidePolicy const& side,
TurnTransformer turn_transformer,
bool const is_pk_valid = true, bool const is_qk_valid = true)
TurnTransformer turn_transformer)
{
TurnInfo tp = tp_model;
@@ -793,23 +840,21 @@ public:
// If P arrives within Q, there is a turn dependent on P
if ( p_arrival == 1
&& is_pk_valid
&& set_tp<0>(pi, pj, pk, side.pk_wrt_p1(), true, qi, qj, side.pk_wrt_q1(), tp, info.i_info()) )
&& ! range_p.is_last_segment()
&& set_tp<0>(side.pk_wrt_p1(), true, side.pk_wrt_q1(), tp, info.i_info()) )
{
turn_transformer(tp);
AssignPolicy::apply(tp, pi, qi, info);
*out++ = tp;
}
// If Q arrives within P, there is a turn dependent on Q
if ( q_arrival == 1
&& is_qk_valid
&& set_tp<1>(qi, qj, qk, side.qk_wrt_q1(), false, pi, pj, side.qk_wrt_p1(), tp, info.i_info()) )
&& ! range_q.is_last_segment()
&& set_tp<1>(side.qk_wrt_q1(), false, side.qk_wrt_p1(), tp, info.i_info()) )
{
turn_transformer(tp);
AssignPolicy::apply(tp, pi, qi, info);
*out++ = tp;
}
@@ -826,7 +871,6 @@ public:
for (unsigned int i = 0; i < info.i_info().count; i++)
{
assign_point(tp, method_collinear, info.i_info(), i);
AssignPolicy::apply(tp, pi, qi, info);
*out++ = tp;
}
}
@@ -842,23 +886,14 @@ template
>
struct crosses : public base_turn_handler
{
template
<
typename Point1,
typename Point2,
typename IntersectionInfo,
typename DirInfo
>
static inline void apply(
Point1 const& , Point1 const& , Point1 const& ,
Point2 const& , Point2 const& , Point2 const& ,
TurnInfo& ti,
template <typename IntersectionInfo, typename DirInfo>
static inline void apply(TurnInfo& ti,
IntersectionInfo const& intersection_info,
DirInfo const& dir_info)
{
assign_point(ti, method_crosses, intersection_info, 0);
// In all casees:
// In all cases:
// If Q crosses P from left to right
// Union: take P
// Intersection: take Q
@@ -883,37 +918,21 @@ struct only_convert : public base_turn_handler
/*!
\brief Policy doing nothing
\details get_turn_info can have an optional policy to get/assign some
extra information. By default it does not, and this class
is that default.
\details get_turn_info can have an optional policy include extra
truns. By default it does not, and this class is that default.
*/
struct assign_null_policy
{
static bool const include_no_turn = false;
static bool const include_degenerate = false;
static bool const include_opposite = false;
template
<
typename Info,
typename Point1,
typename Point2,
typename IntersectionInfo
>
static inline void apply(Info& , Point1 const& , Point2 const&, IntersectionInfo const&)
{}
};
/*!
\brief Turn information: intersection point, method, and turn information
\details Information necessary for traversal phase (a phase
of the overlay process). The information is gathered during the
get_turns (segment intersection) phase.
\tparam Point1 point type of first segment
\tparam Point2 point type of second segment
\tparam TurnInfo type of class getting intersection and turn info
\tparam AssignPolicy policy to assign extra info,
e.g. to calculate distance from segment's first points
to intersection points.
@@ -923,23 +942,21 @@ struct assign_null_policy
template<typename AssignPolicy>
struct get_turn_info
{
// Intersect pi-pj with qi-qj
// The points pk and qk are used do determine more information
// about the turn (turn left/right)
// Intersect a segment p with a segment q
// Both p and q are modelled as sub_ranges to provide more points
// to be able to give more information about the turn (left/right)
template
<
typename Point1,
typename Point2,
typename UniqueSubRange1,
typename UniqueSubRange2,
typename TurnInfo,
typename IntersectionStrategy,
typename RobustPolicy,
typename OutputIterator
>
static inline OutputIterator apply(
Point1 const& pi, Point1 const& pj, Point1 const& pk,
Point2 const& qi, Point2 const& qj, Point2 const& qk,
bool /*is_p_first*/, bool /*is_p_last*/,
bool /*is_q_first*/, bool /*is_q_last*/,
UniqueSubRange1 const& range_p,
UniqueSubRange2 const& range_q,
TurnInfo const& tp_model,
IntersectionStrategy const& intersection_strategy,
RobustPolicy const& robust_policy,
@@ -947,13 +964,14 @@ struct get_turn_info
{
typedef intersection_info
<
Point1, Point2,
UniqueSubRange1, UniqueSubRange2,
typename TurnInfo::point_type,
IntersectionStrategy,
RobustPolicy
> inters_info;
inters_info inters(pi, pj, pk, qi, qj, qk, intersection_strategy, robust_policy);
inters_info inters(range_p, range_q,
intersection_strategy, robust_policy);
char const method = inters.d_info().how;
@@ -970,7 +988,6 @@ struct get_turn_info
&& inters.i_info().count > 0)
{
only_convert::apply(tp, inters.i_info());
AssignPolicy::apply(tp, pi, qi, inters);
*out++ = tp;
}
break;
@@ -988,45 +1005,28 @@ struct get_turn_info
// If Q (1) arrives (1)
if ( inters.d_info().arrival[1] == 1 )
{
policy::template apply<0>(pi, pj, pk, qi, qj, qk,
tp, inters.i_info(), inters.d_info(),
policy::template apply<0>(range_p, range_q, tp, inters.i_info(), inters.d_info(),
inters.sides());
}
else
{
// Swap p/q
side_calculator
<
typename inters_info::cs_tag,
typename inters_info::robust_point2_type,
typename inters_info::robust_point1_type,
typename inters_info::side_strategy_type
> swapped_side_calc(inters.rqi(), inters.rqj(), inters.rqk(),
inters.rpi(), inters.rpj(), inters.rpk(),
inters.get_side_strategy());
policy::template apply<1>(qi, qj, qk, pi, pj, pk,
tp, inters.i_info(), inters.d_info(),
swapped_side_calc);
policy::template apply<1>(range_q, range_p, tp, inters.i_info(), inters.d_info(),
inters.get_swapped_sides());
}
AssignPolicy::apply(tp, pi, qi, inters);
*out++ = tp;
}
break;
case 'i' :
{
crosses<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
tp, inters.i_info(), inters.d_info());
AssignPolicy::apply(tp, pi, qi, inters);
crosses<TurnInfo>::apply(tp, inters.i_info(), inters.d_info());
*out++ = tp;
}
break;
case 't' :
{
// Both touch (both arrive there)
touch<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
tp, inters.i_info(), inters.d_info(), inters.sides());
AssignPolicy::apply(tp, pi, qi, inters);
touch<TurnInfo>::apply(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides());
*out++ = tp;
}
break;
@@ -1036,9 +1036,7 @@ struct get_turn_info
{
// Both equal
// or collinear-and-ending at intersection point
equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
tp, inters.i_info(), inters.d_info(), inters.sides());
AssignPolicy::apply(tp, pi, qi, inters);
equal<TurnInfo>::apply(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides());
*out++ = tp;
}
else
@@ -1047,8 +1045,7 @@ struct get_turn_info
<
TurnInfo,
AssignPolicy
>::apply(pi, qi,
tp, out, inters);
>::apply(range_p, range_q, tp, out, inters);
}
}
break;
@@ -1061,19 +1058,18 @@ struct get_turn_info
if ( inters.d_info().arrival[0] == 0 )
{
// Collinear, but similar thus handled as equal
equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
tp, inters.i_info(), inters.d_info(), inters.sides());
equal<TurnInfo>::apply(range_p, range_q, tp,
inters.i_info(), inters.d_info(), inters.sides());
// override assigned method
tp.method = method_collinear;
}
else
{
collinear<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
tp, inters.i_info(), inters.d_info(), inters.sides());
collinear<TurnInfo>::apply(range_p, range_q, tp,
inters.i_info(), inters.d_info(), inters.sides());
}
AssignPolicy::apply(tp, pi, qi, inters);
*out++ = tp;
}
else
@@ -1082,7 +1078,7 @@ struct get_turn_info
<
TurnInfo,
AssignPolicy
>::apply(pi, pj, pk, qi, qj, qk,
>::apply(range_p, range_q,
tp, out, inters, inters.sides());
}
}
@@ -1093,7 +1089,6 @@ struct get_turn_info
if (AssignPolicy::include_degenerate)
{
only_convert::apply(tp, inters.i_info());
AssignPolicy::apply(tp, pi, qi, inters);
*out++ = tp;
}
}

View File

@@ -2,8 +2,8 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2013, 2014, 2017.
// Modifications copyright (c) 2013-2017 Oracle and/or its affiliates.
// This file was modified by Oracle on 2013, 2014, 2017, 2018.
// Modifications copyright (c) 2013-2018 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -14,8 +14,11 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_FOR_ENDPOINT_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_FOR_ENDPOINT_HPP
#include <boost/geometry/core/assert.hpp>
#include <boost/core/ignore_unused.hpp>
#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
namespace boost { namespace geometry {
@@ -108,11 +111,12 @@ namespace detail { namespace overlay {
class linear_intersections
{
public:
template <typename Point1, typename Point2, typename IntersectionResult>
template <typename Point1, typename Point2, typename IntersectionResult, typename EqPPStrategy>
linear_intersections(Point1 const& pi,
Point2 const& qi,
IntersectionResult const& result,
bool is_p_last, bool is_q_last)
bool is_p_last, bool is_q_last,
EqPPStrategy const& strategy)
{
int arrival_a = result.template get<1>().arrival[0];
int arrival_b = result.template get<1>().arrival[1];
@@ -132,10 +136,10 @@ public:
ips[0].is_pi
= equals::equals_point_point(
pi, result.template get<0>().intersections[0]);
pi, result.template get<0>().intersections[0], strategy);
ips[0].is_qi
= equals::equals_point_point(
qi, result.template get<0>().intersections[0]);
qi, result.template get<0>().intersections[0], strategy);
ips[1].is_pj = arrival_a != -1;
ips[1].is_qj = arrival_b != -1;
}
@@ -221,39 +225,53 @@ private:
ip_info ips[2];
};
template <typename AssignPolicy, bool EnableFirst, bool EnableLast>
template <bool EnableFirst, bool EnableLast>
struct get_turn_info_for_endpoint
{
typedef std::pair<operation_type, operation_type> operations_pair;
BOOST_STATIC_ASSERT(EnableFirst || EnableLast);
template<typename Point1,
typename Point2,
template<typename UniqueSubRange1,
typename UniqueSubRange2,
typename TurnInfo,
typename IntersectionInfo,
typename OutputIterator
typename OutputIterator,
typename EqPPStrategy
>
static inline bool apply(Point1 const& pi, Point1 const& pj, Point1 const& pk,
Point2 const& qi, Point2 const& qj, Point2 const& qk,
bool is_p_first, bool is_p_last,
bool is_q_first, bool is_q_last,
static inline bool apply(UniqueSubRange1 const& range_p,
UniqueSubRange2 const& range_q,
TurnInfo const& tp_model,
IntersectionInfo const& inters,
method_type /*method*/,
OutputIterator out)
OutputIterator out,
EqPPStrategy const& strategy)
{
std::size_t ip_count = inters.i_info().count;
// no intersection points
if ( ip_count == 0 )
if (ip_count == 0)
{
return false;
}
if ( !is_p_first && !is_p_last && !is_q_first && !is_q_last )
if (! range_p.is_first_segment()
&& ! range_q.is_first_segment()
&& ! range_p.is_last_segment()
&& ! range_q.is_last_segment())
{
// Not an end-point from segment p or q
return false;
}
linear_intersections intersections(pi, qi, inters.result(), is_p_last, is_q_last);
linear_intersections intersections(range_p.at(0),
range_q.at(0),
inters.result(),
range_p.is_last_segment(),
range_q.is_last_segment(),
strategy);
bool append0_last
= analyse_segment_and_assign_ip(pi, pj, pk, qi, qj, qk,
is_p_first, is_p_last, is_q_first, is_q_last,
= analyse_segment_and_assign_ip(range_p, range_q,
intersections.template get<0>(),
tp_model, inters, 0, out);
@@ -267,8 +285,7 @@ struct get_turn_info_for_endpoint
return result_ignore_ip0;
bool append1_last
= analyse_segment_and_assign_ip(pi, pj, pk, qi, qj, qk,
is_p_first, is_p_last, is_q_first, is_q_last,
= analyse_segment_and_assign_ip(range_p, range_q,
intersections.template get<1>(),
tp_model, inters, 1, out);
@@ -278,37 +295,25 @@ struct get_turn_info_for_endpoint
return result_ignore_ip0 || result_ignore_ip1;
}
template <typename Point1,
typename Point2,
template <typename UniqueSubRange1,
typename UniqueSubRange2,
typename TurnInfo,
typename IntersectionInfo,
typename OutputIterator>
static inline
bool analyse_segment_and_assign_ip(Point1 const& pi, Point1 const& pj, Point1 const& pk,
Point2 const& qi, Point2 const& qj, Point2 const& qk,
bool is_p_first, bool is_p_last,
bool is_q_first, bool is_q_last,
bool analyse_segment_and_assign_ip(UniqueSubRange1 const& range_p,
UniqueSubRange2 const& range_q,
linear_intersections::ip_info const& ip_info,
TurnInfo const& tp_model,
IntersectionInfo const& inters,
unsigned int ip_index,
OutputIterator out)
{
#ifdef BOOST_GEOMETRY_DEBUG_GET_TURNS_LINEAR_LINEAR
// may this give false positives for INTs?
typename IntersectionResult::point_type const&
inters_pt = result.template get<0>().intersections[ip_index];
BOOST_GEOMETRY_ASSERT(ip_info.is_pi == equals::equals_point_point(pi, inters_pt));
BOOST_GEOMETRY_ASSERT(ip_info.is_qi == equals::equals_point_point(qi, inters_pt));
BOOST_GEOMETRY_ASSERT(ip_info.is_pj == equals::equals_point_point(pj, inters_pt));
BOOST_GEOMETRY_ASSERT(ip_info.is_qj == equals::equals_point_point(qj, inters_pt));
#endif
// TODO - calculate first/last only if needed
bool is_p_first_ip = is_p_first && ip_info.is_pi;
bool is_p_last_ip = is_p_last && ip_info.is_pj;
bool is_q_first_ip = is_q_first && ip_info.is_qi;
bool is_q_last_ip = is_q_last && ip_info.is_qj;
bool is_p_first_ip = range_p.is_first_segment() && ip_info.is_pi;
bool is_p_last_ip = range_p.is_last_segment() && ip_info.is_pj;
bool is_q_first_ip = range_q.is_first_segment() && ip_info.is_qi;
bool is_q_last_ip = range_q.is_last_segment() && ip_info.is_qj;
bool append_first = EnableFirst && (is_p_first_ip || is_q_first_ip);
bool append_last = EnableLast && (is_p_last_ip || is_q_last_ip);
@@ -317,9 +322,7 @@ struct get_turn_info_for_endpoint
if ( append_first || append_last )
{
bool handled = handle_internal<0>(pi, pj, pk, qi, qj, qk,
inters.rpi(), inters.rpj(), inters.rpk(),
inters.rqi(), inters.rqj(), inters.rqk(),
bool handled = handle_internal<0>(range_p, range_q,
is_p_first_ip, is_p_last_ip,
is_q_first_ip, is_q_last_ip,
ip_info.is_qi, ip_info.is_qj,
@@ -327,9 +330,8 @@ struct get_turn_info_for_endpoint
p_operation, q_operation);
if ( !handled )
{
handle_internal<1>(qi, qj, qk, pi, pj, pk,
inters.rqi(), inters.rqj(), inters.rqk(),
inters.rpi(), inters.rpj(), inters.rpk(),
// Reverse p/q
handle_internal<1>(range_q, range_p,
is_q_first_ip, is_q_last_ip,
is_p_first_ip, is_p_last_ip,
ip_info.is_pi, ip_info.is_pj,
@@ -347,31 +349,29 @@ struct get_turn_info_for_endpoint
// handle spikes
// P is spike and should be handled
if ( !is_p_last
&& ip_info.is_pj // this check is redundant (also in is_spike_p) but faster
if (ip_info.is_pj // this check is redundant (also in is_spike_p) but faster
&& inters.i_info().count == 2
&& inters.is_spike_p() )
{
assign(pi, qi, inters.result(), ip_index, method, operation_blocked, q_operation,
assign(inters.result(), ip_index, method, operation_blocked, q_operation,
p_pos, q_pos, is_p_first_ip, is_q_first_ip, true, false, tp_model, out);
assign(pi, qi, inters.result(), ip_index, method, operation_intersection, q_operation,
assign(inters.result(), ip_index, method, operation_intersection, q_operation,
p_pos, q_pos, is_p_first_ip, is_q_first_ip, true, false, tp_model, out);
}
// Q is spike and should be handled
else if ( !is_q_last
&& ip_info.is_qj // this check is redundant (also in is_spike_q) but faster
else if (ip_info.is_qj // this check is redundant (also in is_spike_q) but faster
&& inters.i_info().count == 2
&& inters.is_spike_q() )
{
assign(pi, qi, inters.result(), ip_index, method, p_operation, operation_blocked,
assign(inters.result(), ip_index, method, p_operation, operation_blocked,
p_pos, q_pos, is_p_first_ip, is_q_first_ip, false, true, tp_model, out);
assign(pi, qi, inters.result(), ip_index, method, p_operation, operation_intersection,
assign(inters.result(), ip_index, method, p_operation, operation_intersection,
p_pos, q_pos, is_p_first_ip, is_q_first_ip, false, true, tp_model, out);
}
// no spikes
else
{
assign(pi, qi, inters.result(), ip_index, method, p_operation, q_operation,
assign(inters.result(), ip_index, method, p_operation, q_operation,
p_pos, q_pos, is_p_first_ip, is_q_first_ip, false, false, tp_model, out);
}
}
@@ -384,28 +384,22 @@ struct get_turn_info_for_endpoint
// however now it's lazily calculated and then it would be always calculated
template<std::size_t G1Index,
typename Point1,
typename Point2,
typename RobustPoint1,
typename RobustPoint2,
typename UniqueRange1,
typename UniqueRange2,
typename TurnInfo,
typename IntersectionInfo
>
static inline bool handle_internal(Point1 const& /*i1*/, Point1 const& /*j1*/, Point1 const& /*k1*/,
Point2 const& i2, Point2 const& j2, Point2 const& /*k2*/,
RobustPoint1 const& ri1, RobustPoint1 const& rj1, RobustPoint1 const& /*rk1*/,
RobustPoint2 const& ri2, RobustPoint2 const& rj2, RobustPoint2 const& rk2,
static inline bool handle_internal(UniqueRange1 const& range1,
UniqueRange2 const& range2,
bool first1, bool last1, bool first2, bool last2,
bool ip_i2, bool ip_j2, TurnInfo const& tp_model,
IntersectionInfo const& inters, unsigned int ip_index,
operation_type & op1, operation_type & op2)
{
typedef typename cs_tag<typename TurnInfo::point_type>::type cs_tag;
boost::ignore_unused(ip_index, tp_model);
boost::ignore_unused_variable_warning(i2);
boost::ignore_unused_variable_warning(j2);
boost::ignore_unused_variable_warning(ip_index);
boost::ignore_unused_variable_warning(tp_model);
typename IntersectionInfo::side_strategy_type const& sides
= inters.get_side_strategy();
if ( !first2 && !last2 )
{
@@ -427,14 +421,11 @@ struct get_turn_info_for_endpoint
}
else if ( ip_j2 )
{
side_calculator<cs_tag,
RobustPoint1, RobustPoint2,
typename IntersectionInfo::side_strategy_type,
RobustPoint2>
side_calc(ri2, ri1, rj1, ri2, rj2, rk2, inters.get_side_strategy());
int const side_pj_q2 = sides.apply(range2.at(1), range2.at(2), range1.at(1));
int const side_pj_q1 = sides.apply(range2.at(0), range2.at(1), range1.at(1));
int const side_qk_q1 = sides.apply(range2.at(0), range2.at(1), range2.at(2));
std::pair<operation_type, operation_type>
operations = operations_of_equal(side_calc);
operations_pair operations = operations_of_equal(side_pj_q2, side_pj_q1, side_qk_q1);
// TODO: must the above be calculated?
// wouldn't it be enough to check if segments are collinear?
@@ -481,13 +472,11 @@ struct get_turn_info_for_endpoint
}
else if ( ip_j2 )
{
side_calculator<cs_tag, RobustPoint1, RobustPoint2,
typename IntersectionInfo::side_strategy_type,
RobustPoint2>
side_calc(ri2, rj1, ri1, ri2, rj2, rk2, inters.get_side_strategy());
std::pair<operation_type, operation_type>
operations = operations_of_equal(side_calc);
int const side_pi_q2 = sides.apply(range2.at(1), range2.at(2), range1.at(0));
int const side_pi_q1 = sides.apply(range2.at(0), range2.at(1), range1.at(0));
int const side_qk_q1 = sides.apply(range2.at(0), range2.at(1), range2.at(2));
operations_pair operations = operations_of_equal(side_pi_q2, side_pi_q1, side_qk_q1);
// TODO: must the above be calculated?
// wouldn't it be enough to check if segments are collinear?
@@ -536,13 +525,10 @@ struct get_turn_info_for_endpoint
( is_ip_last_j ? position_back : position_middle );
}
template <typename Point1,
typename Point2,
typename IntersectionResult,
template <typename IntersectionResult,
typename TurnInfo,
typename OutputIterator>
static inline void assign(Point1 const& pi, Point2 const& qi,
IntersectionResult const& result,
static inline void assign(IntersectionResult const& result,
unsigned int ip_index,
method_type method,
operation_type op0, operation_type op1,
@@ -593,33 +579,27 @@ struct get_turn_info_for_endpoint
}
}
// TODO: this should get an intersection_info, which is unavailable here
// Because the assign_null policy accepts any structure, we pass the result instead for now
AssignPolicy::apply(tp, pi, qi, result);
*out++ = tp;
}
template <typename SidePolicy>
static inline std::pair<operation_type, operation_type> operations_of_equal(SidePolicy const& side)
static inline operations_pair operations_of_equal(int side_px_q2,
int side_px_q1,
int side_qk_q1)
{
int const side_pk_q2 = side.pk_wrt_q2();
int const side_pk_p = side.pk_wrt_p1();
int const side_qk_p = side.qk_wrt_p1();
// If pk is collinear with qj-qk, they continue collinearly.
// This can be on either side of p1 (== q1), or collinear
// If px (pi or pj) is collinear with qj-qk (q2), they continue collinearly.
// This can be on either side of q1, or collinear
// The second condition checks if they do not continue
// oppositely
if ( side_pk_q2 == 0 && side_pk_p == side_qk_p )
if (side_px_q2 == 0 && side_px_q1 == side_qk_q1)
{
return std::make_pair(operation_continue, operation_continue);
}
// If they turn to same side (not opposite sides)
if ( ! base_turn_handler::opposite(side_pk_p, side_qk_p) )
if ( ! base_turn_handler::opposite(side_px_q1, side_qk_q1) )
{
// If pk is left of q2 or collinear: p: union, q: intersection
if ( side_pk_q2 != -1 )
// If px is left of q2 or collinear: p: union, q: intersection
if (side_px_q2 != -1 )
{
return std::make_pair(operation_union, operation_intersection);
}
@@ -632,7 +612,7 @@ struct get_turn_info_for_endpoint
{
// They turn opposite sides. If p turns left (or collinear),
// p: union, q: intersection
if ( side_pk_p != -1 )
if (side_px_q1 != -1 )
{
return std::make_pair(operation_union, operation_intersection);
}
@@ -643,16 +623,15 @@ struct get_turn_info_for_endpoint
}
}
static inline bool operations_both(
std::pair<operation_type, operation_type> const& operations,
operation_type const op)
static inline bool operations_both(operations_pair const& operations,
operation_type const op)
{
return operations.first == op && operations.second == op;
}
static inline bool operations_combination(
std::pair<operation_type, operation_type> const& operations,
operation_type const op1, operation_type const op2)
static inline bool operations_combination(operations_pair const& operations,
operation_type const op1,
operation_type const op2)
{
return ( operations.first == op1 && operations.second == op2 )
|| ( operations.first == op2 && operations.second == op1 );

View File

@@ -2,8 +2,8 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2013, 2014, 2015, 2017.
// Modifications copyright (c) 2013-2017 Oracle and/or its affiliates.
// This file was modified by Oracle on 2013, 2014, 2015, 2017, 2018.
// Modifications copyright (c) 2013-2018 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -14,7 +14,16 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HELPERS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HELPERS_HPP
#include <boost/geometry/algorithms/detail/direction_code.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
#include <boost/geometry/algorithms/detail/recalculate.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/geometries/segment.hpp> // referring_segment
#include <boost/geometry/policies/relate/direction.hpp>
#include <boost/geometry/policies/relate/intersection_points.hpp>
#include <boost/geometry/policies/relate/tupled.hpp>
#include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
#include <boost/geometry/strategies/intersection_result.hpp>
namespace boost { namespace geometry {
@@ -36,183 +45,324 @@ struct turn_operation_linear
bool is_collinear; // valid only for Linear geometry
};
template <typename TurnPointCSTag, typename PointP, typename PointQ,
typename SideStrategy,
typename Pi = PointP, typename Pj = PointP, typename Pk = PointP,
typename Qi = PointQ, typename Qj = PointQ, typename Qk = PointQ
template
<
typename TurnPointCSTag,
typename UniqueSubRange1,
typename UniqueSubRange2,
typename SideStrategy
>
struct side_calculator
{
inline side_calculator(Pi const& pi, Pj const& pj, Pk const& pk,
Qi const& qi, Qj const& qj, Qk const& qk,
typedef typename UniqueSubRange1::point_type point1_type;
typedef typename UniqueSubRange2::point_type point2_type;
inline side_calculator(UniqueSubRange1 const& range_p,
UniqueSubRange2 const& range_q,
SideStrategy const& side_strategy)
: m_pi(pi), m_pj(pj), m_pk(pk)
, m_qi(qi), m_qj(qj), m_qk(qk)
, m_side_strategy(side_strategy)
: m_side_strategy(side_strategy)
, m_range_p(range_p)
, m_range_q(range_q)
{}
inline int pk_wrt_p1() const { return m_side_strategy.apply(m_pi, m_pj, m_pk); }
inline int pk_wrt_q1() const { return m_side_strategy.apply(m_qi, m_qj, m_pk); }
inline int qk_wrt_p1() const { return m_side_strategy.apply(m_pi, m_pj, m_qk); }
inline int qk_wrt_q1() const { return m_side_strategy.apply(m_qi, m_qj, m_qk); }
inline int pk_wrt_p1() const { return m_side_strategy.apply(get_pi(), get_pj(), get_pk()); }
inline int pk_wrt_q1() const { return m_side_strategy.apply(get_qi(), get_qj(), get_pk()); }
inline int qk_wrt_p1() const { return m_side_strategy.apply(get_pi(), get_pj(), get_qk()); }
inline int qk_wrt_q1() const { return m_side_strategy.apply(get_qi(), get_qj(), get_qk()); }
inline int pk_wrt_q2() const { return m_side_strategy.apply(m_qj, m_qk, m_pk); }
inline int qk_wrt_p2() const { return m_side_strategy.apply(m_pj, m_pk, m_qk); }
inline int pk_wrt_q2() const { return m_side_strategy.apply(get_qj(), get_qk(), get_pk()); }
inline int qk_wrt_p2() const { return m_side_strategy.apply(get_pj(), get_pk(), get_qk()); }
Pi const& m_pi;
Pj const& m_pj;
Pk const& m_pk;
Qi const& m_qi;
Qj const& m_qj;
Qk const& m_qk;
// Necessary when rescaling turns off:
inline int qj_wrt_p1() const { return m_side_strategy.apply(get_pi(), get_pj(), get_qj()); }
inline int qj_wrt_p2() const { return m_side_strategy.apply(get_pj(), get_pk(), get_qj()); }
inline int pj_wrt_q1() const { return m_side_strategy.apply(get_qi(), get_qj(), get_pj()); }
inline int pj_wrt_q2() const { return m_side_strategy.apply(get_qj(), get_qk(), get_pj()); }
SideStrategy const& m_side_strategy;
inline point1_type const& get_pi() const { return m_range_p.at(0); }
inline point1_type const& get_pj() const { return m_range_p.at(1); }
inline point1_type const& get_pk() const { return m_range_p.at(2); }
inline point2_type const& get_qi() const { return m_range_q.at(0); }
inline point2_type const& get_qj() const { return m_range_q.at(1); }
inline point2_type const& get_qk() const { return m_range_q.at(2); }
// Used side-strategy, owned by the calculator,
// created from .get_side_strategy()
SideStrategy m_side_strategy;
// Used ranges - owned by get_turns or (for robust points) by intersection_info_base
UniqueSubRange1 const& m_range_p;
UniqueSubRange2 const& m_range_q;
};
template <typename Point1, typename Point2, typename RobustPolicy>
template<typename Point, typename UniqueSubRange, typename RobustPolicy>
struct robust_subrange_adapter
{
typedef Point point_type;
robust_subrange_adapter(UniqueSubRange const& unique_sub_range,
Point const& robust_point_i, Point const& robust_point_j,
RobustPolicy const& robust_policy)
: m_unique_sub_range(unique_sub_range)
, m_robust_policy(robust_policy)
, m_robust_point_i(robust_point_i)
, m_robust_point_j(robust_point_j)
, m_k_retrieved(false)
{}
std::size_t size() const { return m_unique_sub_range.size(); }
//! Get precalculated point
Point const& at(std::size_t index) const
{
BOOST_GEOMETRY_ASSERT(index < size());
switch (index)
{
case 0 : return m_robust_point_i;
case 1 : return m_robust_point_j;
case 2 : return get_point_k();
default : return m_robust_point_i;
}
}
private :
Point const& get_point_k() const
{
if (! m_k_retrieved)
{
geometry::recalculate(m_robust_point_k, m_unique_sub_range.at(2), m_robust_policy);
m_k_retrieved = true;
}
return m_robust_point_k;
}
UniqueSubRange const& m_unique_sub_range;
RobustPolicy const& m_robust_policy;
Point const& m_robust_point_i;
Point const& m_robust_point_j;
mutable Point m_robust_point_k;
mutable bool m_k_retrieved;
};
template
<
typename UniqueSubRange1, typename UniqueSubRange2,
typename RobustPolicy
>
struct robust_points
{
typedef typename geometry::robust_point_type
<
Point1, RobustPolicy
typename UniqueSubRange1::point_type, RobustPolicy
>::type robust_point1_type;
// TODO: define robust_point2_type using Point2?
typedef robust_point1_type robust_point2_type;
inline robust_points(Point1 const& pi, Point1 const& pj, Point1 const& pk,
Point2 const& qi, Point2 const& qj, Point2 const& qk,
inline robust_points(UniqueSubRange1 const& range_p,
UniqueSubRange2 const& range_q,
RobustPolicy const& robust_policy)
: m_robust_policy(robust_policy)
, m_range_p(range_p)
, m_range_q(range_q)
, m_pk_retrieved(false)
, m_qk_retrieved(false)
{
geometry::recalculate(m_rpi, pi, robust_policy);
geometry::recalculate(m_rpj, pj, robust_policy);
geometry::recalculate(m_rpk, pk, robust_policy);
geometry::recalculate(m_rqi, qi, robust_policy);
geometry::recalculate(m_rqj, qj, robust_policy);
geometry::recalculate(m_rqk, qk, robust_policy);
// Calculate pi,pj and qi,qj which are almost always necessary
// But don't calculate pk/qk yet, which is retrieved (taking
// more time) and not always necessary.
geometry::recalculate(m_rpi, range_p.at(0), robust_policy);
geometry::recalculate(m_rpj, range_p.at(1), robust_policy);
geometry::recalculate(m_rqi, range_q.at(0), robust_policy);
geometry::recalculate(m_rqj, range_q.at(1), robust_policy);
}
robust_point1_type m_rpi, m_rpj, m_rpk;
robust_point2_type m_rqi, m_rqj, m_rqk;
inline robust_point1_type const& get_rpk() const
{
if (! m_pk_retrieved)
{
geometry::recalculate(m_rpk, m_range_p.at(2), m_robust_policy);
m_pk_retrieved = true;
}
return m_rpk;
}
inline robust_point2_type const& get_rqk() const
{
if (! m_qk_retrieved)
{
geometry::recalculate(m_rqk, m_range_q.at(2), m_robust_policy);
m_qk_retrieved = true;
}
return m_rqk;
}
robust_point1_type m_rpi, m_rpj;
robust_point2_type m_rqi, m_rqj;
private :
RobustPolicy const& m_robust_policy;
UniqueSubRange1 const& m_range_p;
UniqueSubRange2 const& m_range_q;
// On retrieval
mutable robust_point1_type m_rpk;
mutable robust_point2_type m_rqk;
mutable bool m_pk_retrieved;
mutable bool m_qk_retrieved;
};
template <typename Point1, typename Point2, typename TurnPoint, typename IntersectionStrategy, typename RobustPolicy>
template
<
typename UniqueSubRange1, typename UniqueSubRange2,
typename TurnPoint, typename IntersectionStrategy, typename RobustPolicy>
class intersection_info_base
: private robust_points<Point1, Point2, RobustPolicy>
: private robust_points<UniqueSubRange1, UniqueSubRange2, RobustPolicy>
{
typedef robust_points<Point1, Point2, RobustPolicy> base;
typedef robust_points<UniqueSubRange1, UniqueSubRange2, RobustPolicy> base;
public:
typedef Point1 point1_type;
typedef Point2 point2_type;
typedef typename base::robust_point1_type robust_point1_type;
typedef typename base::robust_point2_type robust_point2_type;
typedef robust_subrange_adapter<robust_point1_type, UniqueSubRange1, RobustPolicy> robust_subrange1;
typedef robust_subrange_adapter<robust_point2_type, UniqueSubRange2, RobustPolicy> robust_subrange2;
typedef typename cs_tag<TurnPoint>::type cs_tag;
typedef typename IntersectionStrategy::side_strategy_type side_strategy_type;
typedef side_calculator<cs_tag, robust_point1_type, robust_point2_type, side_strategy_type> side_calculator_type;
intersection_info_base(Point1 const& pi, Point1 const& pj, Point1 const& pk,
Point2 const& qi, Point2 const& qj, Point2 const& qk,
typedef side_calculator<cs_tag, robust_subrange1, robust_subrange2,
side_strategy_type> side_calculator_type;
typedef side_calculator
<
cs_tag, robust_subrange2, robust_subrange1,
side_strategy_type
> robust_swapped_side_calculator_type;
intersection_info_base(UniqueSubRange1 const& range_p,
UniqueSubRange2 const& range_q,
IntersectionStrategy const& intersection_strategy,
RobustPolicy const& robust_policy)
: base(pi, pj, pk, qi, qj, qk, robust_policy)
, m_side_calc(base::m_rpi, base::m_rpj, base::m_rpk,
base::m_rqi, base::m_rqj, base::m_rqk,
: base(range_p, range_q, robust_policy)
, m_range_p(range_p)
, m_range_q(range_q)
, m_robust_range_p(range_p, base::m_rpi, base::m_rpj, robust_policy)
, m_robust_range_q(range_q, base::m_rqi, base::m_rqj, robust_policy)
, m_side_calc(m_robust_range_p, m_robust_range_q,
intersection_strategy.get_side_strategy())
, m_pi(pi), m_pj(pj), m_pk(pk)
, m_qi(qi), m_qj(qj), m_qk(qk)
{}
inline Point1 const& pi() const { return m_pi; }
inline Point1 const& pj() const { return m_pj; }
inline Point1 const& pk() const { return m_pk; }
inline Point2 const& qi() const { return m_qi; }
inline Point2 const& qj() const { return m_qj; }
inline Point2 const& qk() const { return m_qk; }
inline typename UniqueSubRange1::point_type const& pi() const { return m_range_p.at(0); }
inline typename UniqueSubRange2::point_type const& qi() const { return m_range_q.at(0); }
inline robust_point1_type const& rpi() const { return base::m_rpi; }
inline robust_point1_type const& rpj() const { return base::m_rpj; }
inline robust_point1_type const& rpk() const { return base::m_rpk; }
inline robust_point1_type const& rpk() const { return base::get_rpk(); }
inline robust_point2_type const& rqi() const { return base::m_rqi; }
inline robust_point2_type const& rqj() const { return base::m_rqj; }
inline robust_point2_type const& rqk() const { return base::m_rqk; }
inline robust_point2_type const& rqk() const { return base::get_rqk(); }
inline side_calculator_type const& sides() const { return m_side_calc; }
private:
side_calculator_type m_side_calc;
robust_swapped_side_calculator_type get_swapped_sides() const
{
robust_swapped_side_calculator_type result(
m_robust_range_q, m_robust_range_p,
m_side_calc.m_side_strategy);
return result;
}
point1_type const& m_pi;
point1_type const& m_pj;
point1_type const& m_pk;
point2_type const& m_qi;
point2_type const& m_qj;
point2_type const& m_qk;
// Owned by get_turns
UniqueSubRange1 const& m_range_p;
UniqueSubRange2 const& m_range_q;
private :
// Owned by this class
robust_subrange1 m_robust_range_p;
robust_subrange2 m_robust_range_q;
side_calculator_type m_side_calc;
};
template <typename Point1, typename Point2, typename TurnPoint, typename IntersectionStrategy>
class intersection_info_base<Point1, Point2, TurnPoint, IntersectionStrategy, detail::no_rescale_policy>
template
<
typename UniqueSubRange1, typename UniqueSubRange2,
typename TurnPoint, typename IntersectionStrategy
>
class intersection_info_base<UniqueSubRange1, UniqueSubRange2,
TurnPoint, IntersectionStrategy, detail::no_rescale_policy>
{
public:
typedef Point1 point1_type;
typedef Point2 point2_type;
typedef typename UniqueSubRange1::point_type point1_type;
typedef typename UniqueSubRange2::point_type point2_type;
typedef Point1 robust_point1_type;
typedef Point2 robust_point2_type;
typedef typename UniqueSubRange1::point_type robust_point1_type;
typedef typename UniqueSubRange2::point_type robust_point2_type;
typedef typename cs_tag<TurnPoint>::type cs_tag;
typedef typename IntersectionStrategy::side_strategy_type side_strategy_type;
typedef side_calculator<cs_tag, Point1, Point2, side_strategy_type> side_calculator_type;
typedef side_calculator<cs_tag, UniqueSubRange1, UniqueSubRange2, side_strategy_type> side_calculator_type;
typedef side_calculator
<
cs_tag, UniqueSubRange2, UniqueSubRange1,
side_strategy_type
> swapped_side_calculator_type;
intersection_info_base(Point1 const& pi, Point1 const& pj, Point1 const& pk,
Point2 const& qi, Point2 const& qj, Point2 const& qk,
intersection_info_base(UniqueSubRange1 const& range_p,
UniqueSubRange2 const& range_q,
IntersectionStrategy const& intersection_strategy,
no_rescale_policy const& /*robust_policy*/)
: m_side_calc(pi, pj, pk, qi, qj, qk,
: m_range_p(range_p)
, m_range_q(range_q)
, m_side_calc(range_p, range_q,
intersection_strategy.get_side_strategy())
{}
inline Point1 const& pi() const { return m_side_calc.m_pi; }
inline Point1 const& pj() const { return m_side_calc.m_pj; }
inline Point1 const& pk() const { return m_side_calc.m_pk; }
inline point1_type const& rpi() const { return m_side_calc.get_pi(); }
inline point1_type const& rpj() const { return m_side_calc.get_pj(); }
inline point1_type const& rpk() const { return m_side_calc.get_pk(); }
inline Point2 const& qi() const { return m_side_calc.m_qi; }
inline Point2 const& qj() const { return m_side_calc.m_qj; }
inline Point2 const& qk() const { return m_side_calc.m_qk; }
inline Point1 const& rpi() const { return pi(); }
inline Point1 const& rpj() const { return pj(); }
inline Point1 const& rpk() const { return pk(); }
inline Point2 const& rqi() const { return qi(); }
inline Point2 const& rqj() const { return qj(); }
inline Point2 const& rqk() const { return qk(); }
inline point2_type const& rqi() const { return m_side_calc.get_qi(); }
inline point2_type const& rqj() const { return m_side_calc.get_qj(); }
inline point2_type const& rqk() const { return m_side_calc.get_qk(); }
inline side_calculator_type const& sides() const { return m_side_calc; }
private:
swapped_side_calculator_type get_swapped_sides() const
{
swapped_side_calculator_type result(
m_range_q, m_range_p,
m_side_calc.m_side_strategy);
return result;
}
protected :
// Owned by get_turns
UniqueSubRange1 const& m_range_p;
UniqueSubRange2 const& m_range_q;
private :
// Owned here, passed by .get_side_strategy()
side_calculator_type m_side_calc;
};
template
<
typename Point1,
typename Point2,
typename UniqueSubRange1, typename UniqueSubRange2,
typename TurnPoint,
typename IntersectionStrategy,
typename RobustPolicy
>
class intersection_info
: public intersection_info_base<Point1, Point2, TurnPoint, IntersectionStrategy, RobustPolicy>
: public intersection_info_base<UniqueSubRange1, UniqueSubRange2,
TurnPoint, IntersectionStrategy, RobustPolicy>
{
typedef intersection_info_base<Point1, Point2, TurnPoint, IntersectionStrategy, RobustPolicy> base;
typedef intersection_info_base<UniqueSubRange1, UniqueSubRange2,
TurnPoint, IntersectionStrategy, RobustPolicy> base;
public:
typedef segment_intersection_points
@@ -224,6 +374,9 @@ public:
>::type
> intersection_point_type;
typedef typename UniqueSubRange1::point_type point1_type;
typedef typename UniqueSubRange2::point_type point2_type;
// NOTE: formerly defined in intersection_strategies
typedef policies::relate::segments_tupled
<
@@ -237,22 +390,23 @@ public:
typedef IntersectionStrategy intersection_strategy_type;
typedef typename IntersectionStrategy::side_strategy_type side_strategy_type;
typedef model::referring_segment<Point1 const> segment_type1;
typedef model::referring_segment<Point2 const> segment_type2;
typedef model::referring_segment<point1_type const> segment_type1;
typedef model::referring_segment<point2_type const> segment_type2;
typedef typename base::side_calculator_type side_calculator_type;
typedef typename intersection_policy_type::return_type result_type;
typedef typename boost::tuples::element<0, result_type>::type i_info_type; // intersection_info
typedef typename boost::tuples::element<1, result_type>::type d_info_type; // dir_info
intersection_info(Point1 const& pi, Point1 const& pj, Point1 const& pk,
Point2 const& qi, Point2 const& qj, Point2 const& qk,
intersection_info(UniqueSubRange1 const& range_p,
UniqueSubRange2 const& range_q,
IntersectionStrategy const& intersection_strategy,
RobustPolicy const& robust_policy)
: base(pi, pj, pk, qi, qj, qk, intersection_strategy, robust_policy)
: base(range_p, range_q,
intersection_strategy, robust_policy)
, m_result(intersection_strategy.apply(
segment_type1(pi, pj),
segment_type2(qi, qj),
segment_type1(range_p.at(0), range_p.at(1)),
segment_type2(range_q.at(0), range_q.at(1)),
intersection_policy_type(),
robust_policy,
base::rpi(), base::rpj(),
@@ -265,11 +419,6 @@ public:
inline i_info_type const& i_info() const { return m_result.template get<0>(); }
inline d_info_type const& d_info() const { return m_result.template get<1>(); }
inline intersection_strategy_type const& get_intersection_strategy() const
{
return m_intersection_strategy;
}
inline side_strategy_type get_side_strategy() const
{
return m_intersection_strategy.get_side_strategy();
@@ -278,24 +427,36 @@ public:
// TODO: it's more like is_spike_ip_p
inline bool is_spike_p() const
{
if (base::m_range_p.is_last_segment())
{
return false;
}
if (base::sides().pk_wrt_p1() == 0)
{
// p: pi--------pj--------pk
// or: pi----pk==pj
if (! is_ip_j<0>())
{
return false;
}
int const qk_p1 = base::sides().qk_wrt_p1();
int const qk_p2 = base::sides().qk_wrt_p2();
// TODO: why is q used to determine spike property in p?
bool const has_qk = ! base::m_range_q.is_last_segment();
int const qk_p1 = has_qk ? base::sides().qk_wrt_p1() : 0;
int const qk_p2 = has_qk ? base::sides().qk_wrt_p2() : 0;
if (qk_p1 == -qk_p2)
{
if (qk_p1 == 0)
{
return is_spike_of_collinear(base::pi(), base::pj(),
base::pk());
// qk is collinear with both p1 and p2,
// verify if pk goes backwards w.r.t. pi/pj
return direction_code(base::rpi(), base::rpj(), base::rpk()) == -1;
}
// qk is at opposite side of p1/p2, therefore
// p1/p2 (collinear) are opposite and form a spike
return true;
}
}
@@ -303,9 +464,14 @@ public:
return false;
}
// TODO: it's more like is_spike_ip_q
inline bool is_spike_q() const
{
if (base::m_range_q.is_last_segment())
{
return false;
}
// See comments at is_spike_p
if (base::sides().qk_wrt_q1() == 0)
{
if (! is_ip_j<1>())
@@ -313,15 +479,16 @@ public:
return false;
}
int const pk_q1 = base::sides().pk_wrt_q1();
int const pk_q2 = base::sides().pk_wrt_q2();
// TODO: why is p used to determine spike property in q?
bool const has_pk = ! base::m_range_p.is_last_segment();
int const pk_q1 = has_pk ? base::sides().pk_wrt_q1() : 0;
int const pk_q2 = has_pk ? base::sides().pk_wrt_q2() : 0;
if (pk_q1 == -pk_q2)
{
if (pk_q1 == 0)
{
return is_spike_of_collinear(base::qi(), base::qj(),
base::qk());
return direction_code(base::rqi(), base::rqj(), base::rqk()) == -1;
}
return true;
@@ -332,26 +499,6 @@ public:
}
private:
template <typename Point>
inline bool is_spike_of_collinear(Point const& i, Point const& j,
Point const& k) const
{
typedef model::referring_segment<Point const> seg;
// no need to calcualte direction info
typedef policies::relate::segments_intersection_points
<
intersection_point_type
> policy_type;
typename policy_type::return_type const result
= m_intersection_strategy.apply(seg(i, j), seg(j, k),
policy_type(),
m_robust_policy);
return result.count == 2;
}
template <std::size_t OpId>
bool is_ip_j() const
{

Some files were not shown because too many files have changed in this diff Show More