blob: ceeb1a3b8bf885ea3ec6c7751553127be1e2a6e2 [file] [log] [blame]
// Boost.Geometry (aka GGL, Generic Geometry Library)
// 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.
// 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
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENTS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENTS_HPP
#include <vector>
#include <boost/array.hpp>
#include <boost/assert.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/range.hpp>
#include <boost/type_traits/integral_constant.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/ring_type.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/util/range.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace copy_segments
{
template <bool Reverse>
struct copy_segments_ring
{
template
<
typename Ring,
typename SegmentIdentifier,
typename RobustPolicy,
typename RangeOut
>
static inline void apply(Ring const& ring,
SegmentIdentifier const& seg_id,
signed_index_type to_index,
RobustPolicy const& robust_policy,
RangeOut& current_output)
{
typedef typename closeable_view
<
Ring const,
closure<Ring>::value
>::type cview_type;
typedef typename reversible_view
<
cview_type const,
Reverse ? iterate_reverse : iterate_forward
>::type rview_type;
typedef typename boost::range_iterator<rview_type const>::type iterator;
typedef geometry::ever_circling_iterator<iterator> ec_iterator;
cview_type cview(ring);
rview_type view(cview);
// The problem: sometimes we want to from "3" to "2"
// -> end = "3" -> end == begin
// This is not convenient with iterators.
// So we use the ever-circling iterator and determine when to step out
signed_index_type const from_index = seg_id.segment_index + 1;
// Sanity check
BOOST_ASSERT(from_index < static_cast<signed_index_type>(boost::size(view)));
ec_iterator it(boost::begin(view), boost::end(view),
boost::begin(view) + from_index);
// [2..4] -> 4 - 2 + 1 = 3 -> {2,3,4} -> OK
// [4..2],size=6 -> 6 - 4 + 2 + 1 = 5 -> {4,5,0,1,2} -> OK
// [1..1], travel the whole ring round
signed_index_type const count = from_index <= to_index
? to_index - from_index + 1
: static_cast<signed_index_type>(boost::size(view))
- from_index + to_index + 1;
for (signed_index_type i = 0; i < count; ++i, ++it)
{
detail::overlay::append_no_dups_or_spikes(current_output, *it, robust_policy);
}
}
};
template <bool Reverse, bool RemoveSpikes = true>
class copy_segments_linestring
{
private:
// remove spikes
template <typename RangeOut, typename Point, typename RobustPolicy>
static inline void append_to_output(RangeOut& current_output,
Point const& point,
RobustPolicy const& robust_policy,
boost::true_type const&)
{
detail::overlay::append_no_dups_or_spikes(current_output, point,
robust_policy);
}
// keep spikes
template <typename RangeOut, typename Point, typename RobustPolicy>
static inline void append_to_output(RangeOut& current_output,
Point const& point,
RobustPolicy const&,
boost::false_type const&)
{
detail::overlay::append_no_duplicates(current_output, point);
}
public:
template
<
typename LineString,
typename SegmentIdentifier,
typename RobustPolicy,
typename RangeOut
>
static inline void apply(LineString const& ls,
SegmentIdentifier const& seg_id,
signed_index_type to_index,
RobustPolicy const& robust_policy,
RangeOut& current_output)
{
signed_index_type const from_index = seg_id.segment_index + 1;
// Sanity check
if ( from_index > to_index
|| from_index < 0
|| to_index >= static_cast<signed_index_type>(boost::size(ls)) )
{
return;
}
signed_index_type const count = to_index - from_index + 1;
typename boost::range_iterator<LineString const>::type
it = boost::begin(ls) + from_index;
for (signed_index_type i = 0; i < count; ++i, ++it)
{
append_to_output(current_output, *it, robust_policy,
boost::integral_constant<bool, RemoveSpikes>());
}
}
};
template <bool Reverse>
struct copy_segments_polygon
{
template
<
typename Polygon,
typename SegmentIdentifier,
typename RobustPolicy,
typename RangeOut
>
static inline void apply(Polygon const& polygon,
SegmentIdentifier const& seg_id,
signed_index_type to_index,
RobustPolicy const& robust_policy,
RangeOut& current_output)
{
// Call ring-version with the right ring
copy_segments_ring<Reverse>::apply
(
seg_id.ring_index < 0
? geometry::exterior_ring(polygon)
: range::at(geometry::interior_rings(polygon), seg_id.ring_index),
seg_id, to_index,
robust_policy,
current_output
);
}
};
template <bool Reverse>
struct copy_segments_box
{
template
<
typename Box,
typename SegmentIdentifier,
typename RobustPolicy,
typename RangeOut
>
static inline void apply(Box const& box,
SegmentIdentifier const& seg_id,
signed_index_type to_index,
RobustPolicy const& robust_policy,
RangeOut& current_output)
{
signed_index_type index = seg_id.segment_index + 1;
BOOST_ASSERT(index < 5);
signed_index_type const count = index <= to_index
? to_index - index + 1
: 5 - index + to_index + 1;
// Create array of points, the fifth one closes it
boost::array<typename point_type<Box>::type, 5> bp;
assign_box_corners_oriented<Reverse>(box, bp);
bp[4] = bp[0];
// (possibly cyclic) copy to output
// (see comments in ring-version)
for (signed_index_type i = 0; i < count; i++, index++)
{
detail::overlay::append_no_dups_or_spikes(current_output,
bp[index % 5], robust_policy);
}
}
};
template<typename Policy>
struct copy_segments_multi
{
template
<
typename MultiGeometry,
typename SegmentIdentifier,
typename RobustPolicy,
typename RangeOut
>
static inline void apply(MultiGeometry const& multi_geometry,
SegmentIdentifier const& seg_id,
signed_index_type to_index,
RobustPolicy const& robust_policy,
RangeOut& current_output)
{
BOOST_ASSERT
(
seg_id.multi_index >= 0
&& seg_id.multi_index < int(boost::size(multi_geometry))
);
// Call the single-version
Policy::apply(range::at(multi_geometry, seg_id.multi_index),
seg_id, to_index,
robust_policy,
current_output);
}
};
}} // namespace detail::copy_segments
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template
<
typename Tag,
bool Reverse
>
struct copy_segments : not_implemented<Tag>
{};
template <bool Reverse>
struct copy_segments<ring_tag, Reverse>
: detail::copy_segments::copy_segments_ring<Reverse>
{};
template <bool Reverse>
struct copy_segments<linestring_tag, Reverse>
: detail::copy_segments::copy_segments_linestring<Reverse>
{};
template <bool Reverse>
struct copy_segments<polygon_tag, Reverse>
: detail::copy_segments::copy_segments_polygon<Reverse>
{};
template <bool Reverse>
struct copy_segments<box_tag, Reverse>
: detail::copy_segments::copy_segments_box<Reverse>
{};
template<bool Reverse>
struct copy_segments<multi_polygon_tag, Reverse>
: detail::copy_segments::copy_segments_multi
<
detail::copy_segments::copy_segments_polygon<Reverse>
>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
/*!
\brief Copy segments from a geometry, starting with the specified segment (seg_id)
until the specified index (to_index)
\ingroup overlay
*/
template
<
bool Reverse,
typename Geometry,
typename SegmentIdentifier,
typename RobustPolicy,
typename RangeOut
>
inline void copy_segments(Geometry const& geometry,
SegmentIdentifier const& seg_id,
signed_index_type to_index,
RobustPolicy const& robust_policy,
RangeOut& range_out)
{
concept::check<Geometry const>();
dispatch::copy_segments
<
typename tag<Geometry>::type,
Reverse
>::apply(geometry, seg_id, to_index, robust_policy, range_out);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENTS_HPP