mirror of
https://github.com/vdemydiuk/mtapi.git
synced 2026-08-04 14:37:46 +00:00
Added thirdparty: boost library
This commit is contained in:
+62
@@ -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
|
||||
+1062
File diff suppressed because it is too large
Load Diff
+300
@@ -0,0 +1,300 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
|
||||
|
||||
// This file was modified by Oracle on 2017-2020.
|
||||
// Modifications copyright (c) 2017-2020, Oracle and/or its affiliates.
|
||||
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
|
||||
|
||||
// Use, modification and distribution is subject to the Boost Software License,
|
||||
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_POLICIES_HPP
|
||||
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_POLICIES_HPP
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include <boost/range/value_type.hpp>
|
||||
|
||||
#include <boost/geometry/core/coordinate_type.hpp>
|
||||
#include <boost/geometry/core/point_type.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>
|
||||
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace buffer
|
||||
{
|
||||
|
||||
class backtrack_for_buffer
|
||||
{
|
||||
public :
|
||||
typedef detail::overlay::backtrack_state state_type;
|
||||
|
||||
template
|
||||
<
|
||||
typename Operation,
|
||||
typename Rings,
|
||||
typename Turns,
|
||||
typename Geometry,
|
||||
typename Strategy,
|
||||
typename RobustPolicy,
|
||||
typename Visitor
|
||||
>
|
||||
static inline void apply(std::size_t size_at_start,
|
||||
Rings& rings, typename boost::range_value<Rings>::type& ring,
|
||||
Turns& turns,
|
||||
typename boost::range_value<Turns>::type const& /*turn*/,
|
||||
Operation& operation,
|
||||
detail::overlay::traverse_error_type /*traverse_error*/,
|
||||
Geometry const& ,
|
||||
Geometry const& ,
|
||||
Strategy const& ,
|
||||
RobustPolicy const& ,
|
||||
state_type& state,
|
||||
Visitor& /*visitor*/
|
||||
)
|
||||
{
|
||||
#if defined(BOOST_GEOMETRY_COUNT_BACKTRACK_WARNINGS)
|
||||
extern int g_backtrack_warning_count;
|
||||
g_backtrack_warning_count++;
|
||||
#endif
|
||||
//std::cout << "!";
|
||||
//std::cout << "WARNING " << traverse_error_string(traverse_error) << std::endl;
|
||||
|
||||
state.m_good = false;
|
||||
|
||||
// Make bad output clean
|
||||
rings.resize(size_at_start);
|
||||
ring.clear();
|
||||
|
||||
// Reject this as a starting point
|
||||
operation.visited.set_rejected();
|
||||
|
||||
// And clear all visit info
|
||||
clear_visit_info(turns);
|
||||
}
|
||||
};
|
||||
|
||||
struct buffer_overlay_visitor
|
||||
{
|
||||
public :
|
||||
void print(char const* /*header*/)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename Turns>
|
||||
void print(char const* /*header*/, Turns const& /*turns*/, int /*turn_index*/)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename Turns>
|
||||
void print(char const* /*header*/, Turns const& /*turns*/, int /*turn_index*/, int /*op_index*/)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename Turns>
|
||||
void visit_turns(int , Turns const& ) {}
|
||||
|
||||
template <typename Clusters, typename Turns>
|
||||
void visit_clusters(Clusters const& , Turns const& ) {}
|
||||
|
||||
template <typename Turns, typename Turn, typename Operation>
|
||||
void visit_traverse(Turns const& /*turns*/, Turn const& /*turn*/, Operation const& /*op*/, const char* /*header*/)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename Turns, typename Turn, typename Operation>
|
||||
void visit_traverse_reject(Turns const& , Turn const& , Operation const& ,
|
||||
detail::overlay::traverse_error_type )
|
||||
{}
|
||||
|
||||
template <typename Rings>
|
||||
void visit_generated_rings(Rings const& )
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
// Should follow traversal-turn-concept (enrichment, visit structure)
|
||||
// and adds index in piece vector to find it back
|
||||
template <typename Point, typename SegmentRatio>
|
||||
struct buffer_turn_operation
|
||||
: public detail::overlay::traversal_turn_operation<Point, SegmentRatio>
|
||||
{
|
||||
signed_size_type piece_index;
|
||||
signed_size_type index_in_robust_ring;
|
||||
|
||||
inline buffer_turn_operation()
|
||||
: piece_index(-1)
|
||||
, index_in_robust_ring(-1)
|
||||
{}
|
||||
};
|
||||
|
||||
// Version of turn_info for buffer with its turn index and other helper variables
|
||||
template <typename Point, typename SegmentRatio>
|
||||
struct buffer_turn_info
|
||||
: public detail::overlay::turn_info
|
||||
<
|
||||
Point,
|
||||
SegmentRatio,
|
||||
buffer_turn_operation<Point, SegmentRatio>
|
||||
>
|
||||
{
|
||||
typedef Point point_type;
|
||||
|
||||
std::size_t turn_index;
|
||||
|
||||
// Information if turn can be used. It is not traversable if it is within
|
||||
// another piece, or within the original (depending on deflation),
|
||||
// or (for deflate) if there are not enough points to traverse it.
|
||||
bool is_turn_traversable;
|
||||
|
||||
bool is_linear_end_point;
|
||||
bool within_original;
|
||||
signed_size_type count_in_original; // increased by +1 for in ext.ring, -1 for int.ring
|
||||
|
||||
inline buffer_turn_info()
|
||||
: turn_index(0)
|
||||
, is_turn_traversable(true)
|
||||
, is_linear_end_point(false)
|
||||
, within_original(false)
|
||||
, count_in_original(0)
|
||||
{}
|
||||
};
|
||||
|
||||
struct buffer_less
|
||||
{
|
||||
template <typename Indexed>
|
||||
inline bool operator()(Indexed const& left, Indexed const& right) const
|
||||
{
|
||||
if (! (left.subject->seg_id == right.subject->seg_id))
|
||||
{
|
||||
return left.subject->seg_id < right.subject->seg_id;
|
||||
}
|
||||
|
||||
// Both left and right are located on the SAME segment.
|
||||
if (! (left.subject->fraction == right.subject->fraction))
|
||||
{
|
||||
return left.subject->fraction < right.subject->fraction;
|
||||
}
|
||||
|
||||
return left.turn_index < right.turn_index;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Strategy>
|
||||
struct piece_get_box
|
||||
{
|
||||
explicit piece_get_box(Strategy const& strategy)
|
||||
: m_strategy(strategy)
|
||||
{}
|
||||
|
||||
template <typename Box, typename Piece>
|
||||
inline void apply(Box& total, Piece const& piece) const
|
||||
{
|
||||
assert_coordinate_type_equal(total, piece.m_piece_border.m_envelope);
|
||||
|
||||
if (piece.m_piece_border.m_has_envelope)
|
||||
{
|
||||
geometry::expand(total, piece.m_piece_border.m_envelope,
|
||||
m_strategy);
|
||||
}
|
||||
}
|
||||
|
||||
Strategy const& m_strategy;
|
||||
};
|
||||
|
||||
template <typename Strategy>
|
||||
struct piece_overlaps_box
|
||||
{
|
||||
explicit piece_overlaps_box(Strategy const& strategy)
|
||||
: m_strategy(strategy)
|
||||
{}
|
||||
|
||||
template <typename Box, typename Piece>
|
||||
inline bool apply(Box const& box, Piece const& piece) const
|
||||
{
|
||||
assert_coordinate_type_equal(box, piece.m_piece_border.m_envelope);
|
||||
|
||||
if (piece.type == strategy::buffer::buffered_flat_end
|
||||
|| piece.type == strategy::buffer::buffered_concave)
|
||||
{
|
||||
// Turns cannot be inside a flat end (though they can be on border)
|
||||
// Neither we need to check if they are inside concave helper pieces
|
||||
|
||||
// Skip all pieces not used as soon as possible
|
||||
return false;
|
||||
}
|
||||
if (! piece.m_piece_border.m_has_envelope)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return ! geometry::detail::disjoint::disjoint_box_box(box, piece.m_piece_border.m_envelope,
|
||||
m_strategy);
|
||||
}
|
||||
|
||||
Strategy const& m_strategy;
|
||||
};
|
||||
|
||||
template <typename Strategy>
|
||||
struct turn_get_box
|
||||
{
|
||||
explicit turn_get_box(Strategy const& strategy)
|
||||
: m_strategy(strategy)
|
||||
{}
|
||||
|
||||
template <typename Box, typename Turn>
|
||||
inline void apply(Box& total, Turn const& turn) const
|
||||
{
|
||||
assert_coordinate_type_equal(total, turn.point);
|
||||
geometry::expand(total, turn.point, m_strategy);
|
||||
}
|
||||
|
||||
Strategy const& m_strategy;
|
||||
};
|
||||
|
||||
template <typename Strategy>
|
||||
struct turn_overlaps_box
|
||||
{
|
||||
explicit turn_overlaps_box(Strategy const& strategy)
|
||||
: m_strategy(strategy)
|
||||
{}
|
||||
|
||||
template <typename Box, typename Turn>
|
||||
inline bool apply(Box const& box, Turn const& turn) const
|
||||
{
|
||||
assert_coordinate_type_equal(turn.point, box);
|
||||
return ! geometry::detail::disjoint::disjoint_point_box(turn.point, box,
|
||||
m_strategy);
|
||||
}
|
||||
|
||||
Strategy const& m_strategy;
|
||||
};
|
||||
|
||||
struct enriched_map_buffer_include_policy
|
||||
{
|
||||
template <typename Operation>
|
||||
static inline bool include(Operation const& op)
|
||||
{
|
||||
return op != detail::overlay::operation_intersection
|
||||
&& op != detail::overlay::operation_blocked;
|
||||
}
|
||||
};
|
||||
|
||||
}} // namespace detail::buffer
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_POLICIES_HPP
|
||||
Vendored
Executable
+1100
File diff suppressed because it is too large
Load Diff
+290
@@ -0,0 +1,290 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// Copyright (c) 2012-2015 Barend Gehrels, Amsterdam, the Netherlands.
|
||||
|
||||
// This file was modified by Oracle on 2020.
|
||||
// Modifications copyright (c) 2020 Oracle and/or its affiliates.
|
||||
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
|
||||
|
||||
// Use, modification and distribution is subject to the Boost Software License,
|
||||
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_RING
|
||||
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_RING
|
||||
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include <boost/range/size.hpp>
|
||||
#include <boost/range/value_type.hpp>
|
||||
|
||||
#include <boost/geometry/core/assert.hpp>
|
||||
#include <boost/geometry/core/coordinate_type.hpp>
|
||||
#include <boost/geometry/core/closure.hpp>
|
||||
#include <boost/geometry/core/point_order.hpp>
|
||||
#include <boost/geometry/core/point_type.hpp>
|
||||
|
||||
#include <boost/geometry/strategies/buffer.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/within.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/enrichment_info.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/get_ring.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace buffer
|
||||
{
|
||||
|
||||
struct buffered_ring_collection_tag : polygonal_tag, multi_tag
|
||||
{};
|
||||
|
||||
|
||||
template <typename Ring>
|
||||
struct buffered_ring : public Ring
|
||||
{
|
||||
bool has_concave;
|
||||
bool has_accepted_intersections;
|
||||
bool has_discarded_intersections;
|
||||
bool is_untouched_outside_original;
|
||||
|
||||
inline buffered_ring()
|
||||
: has_concave(false)
|
||||
, has_accepted_intersections(false)
|
||||
, has_discarded_intersections(false)
|
||||
, is_untouched_outside_original(false)
|
||||
{}
|
||||
|
||||
inline bool discarded() const
|
||||
{
|
||||
return has_discarded_intersections && ! has_accepted_intersections;
|
||||
}
|
||||
inline bool has_intersections() const
|
||||
{
|
||||
return has_discarded_intersections || has_accepted_intersections;
|
||||
}
|
||||
};
|
||||
|
||||
// This is a collection now special for overlay (needs vector of rings)
|
||||
template <typename Ring>
|
||||
struct buffered_ring_collection : public std::vector<Ring>
|
||||
{
|
||||
};
|
||||
|
||||
}} // namespace detail::buffer
|
||||
|
||||
|
||||
// Turn off concept checking (for now)
|
||||
namespace concepts
|
||||
{
|
||||
|
||||
template <typename Geometry>
|
||||
struct concept_type<Geometry, geometry::detail::buffer::buffered_ring_collection_tag>
|
||||
{
|
||||
struct dummy {};
|
||||
using type = dummy;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
|
||||
|
||||
// Register the types
|
||||
namespace traits
|
||||
{
|
||||
|
||||
|
||||
template <typename Ring>
|
||||
struct tag<geometry::detail::buffer::buffered_ring<Ring> >
|
||||
{
|
||||
typedef ring_tag type;
|
||||
};
|
||||
|
||||
|
||||
template <typename Ring>
|
||||
struct point_order<geometry::detail::buffer::buffered_ring<Ring> >
|
||||
{
|
||||
static const order_selector value = geometry::point_order<Ring>::value;
|
||||
};
|
||||
|
||||
|
||||
template <typename Ring>
|
||||
struct closure<geometry::detail::buffer::buffered_ring<Ring> >
|
||||
{
|
||||
static const closure_selector value = geometry::closure<Ring>::value;
|
||||
};
|
||||
|
||||
|
||||
template <typename Ring>
|
||||
struct point_type<geometry::detail::buffer::buffered_ring_collection<Ring> >
|
||||
{
|
||||
typedef typename geometry::point_type<Ring>::type type;
|
||||
};
|
||||
|
||||
template <typename Ring>
|
||||
struct tag<geometry::detail::buffer::buffered_ring_collection<Ring> >
|
||||
{
|
||||
typedef geometry::detail::buffer::buffered_ring_collection_tag type;
|
||||
};
|
||||
|
||||
|
||||
} // namespace traits
|
||||
|
||||
|
||||
|
||||
|
||||
namespace core_dispatch
|
||||
{
|
||||
|
||||
template <typename Ring>
|
||||
struct ring_type
|
||||
<
|
||||
detail::buffer::buffered_ring_collection_tag,
|
||||
detail::buffer::buffered_ring_collection<Ring>
|
||||
>
|
||||
{
|
||||
typedef Ring type;
|
||||
};
|
||||
|
||||
|
||||
// There is a specific tag, so this specialization cannot be placed in traits
|
||||
template <typename Ring>
|
||||
struct point_order<detail::buffer::buffered_ring_collection_tag,
|
||||
geometry::detail::buffer::buffered_ring_collection
|
||||
<
|
||||
geometry::detail::buffer::buffered_ring<Ring>
|
||||
> >
|
||||
{
|
||||
static const order_selector value
|
||||
= core_dispatch::point_order<ring_tag, Ring>::value;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
template <>
|
||||
struct single_tag_of<detail::buffer::buffered_ring_collection_tag>
|
||||
{
|
||||
typedef ring_tag type;
|
||||
};
|
||||
|
||||
|
||||
namespace dispatch
|
||||
{
|
||||
|
||||
template
|
||||
<
|
||||
typename MultiRing,
|
||||
bool Reverse,
|
||||
typename SegmentIdentifier,
|
||||
typename PointOut
|
||||
>
|
||||
struct copy_segment_point
|
||||
<
|
||||
detail::buffer::buffered_ring_collection_tag,
|
||||
MultiRing,
|
||||
Reverse,
|
||||
SegmentIdentifier,
|
||||
PointOut
|
||||
>
|
||||
: detail::copy_segments::copy_segment_point_multi
|
||||
<
|
||||
MultiRing,
|
||||
SegmentIdentifier,
|
||||
PointOut,
|
||||
detail::copy_segments::copy_segment_point_range
|
||||
<
|
||||
typename boost::range_value<MultiRing>::type,
|
||||
Reverse,
|
||||
SegmentIdentifier,
|
||||
PointOut
|
||||
>
|
||||
>
|
||||
{};
|
||||
|
||||
|
||||
template<bool Reverse>
|
||||
struct copy_segments
|
||||
<
|
||||
detail::buffer::buffered_ring_collection_tag,
|
||||
Reverse
|
||||
>
|
||||
: detail::copy_segments::copy_segments_multi
|
||||
<
|
||||
detail::copy_segments::copy_segments_ring<Reverse>
|
||||
>
|
||||
{};
|
||||
|
||||
template <typename Point, typename MultiGeometry>
|
||||
struct within
|
||||
<
|
||||
Point,
|
||||
MultiGeometry,
|
||||
point_tag,
|
||||
detail::buffer::buffered_ring_collection_tag
|
||||
>
|
||||
{
|
||||
template <typename Strategy>
|
||||
static inline bool apply(Point const& point,
|
||||
MultiGeometry const& multi, Strategy const& strategy)
|
||||
{
|
||||
return detail::within::point_in_geometry(point, multi, strategy) == 1;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename Geometry>
|
||||
struct is_empty<Geometry, detail::buffer::buffered_ring_collection_tag>
|
||||
: detail::is_empty::multi_is_empty<detail::is_empty::range_is_empty>
|
||||
{};
|
||||
|
||||
|
||||
template <typename Geometry>
|
||||
struct envelope<Geometry, detail::buffer::buffered_ring_collection_tag>
|
||||
: detail::envelope::envelope_multi_range
|
||||
<
|
||||
detail::envelope::envelope_range
|
||||
>
|
||||
{};
|
||||
|
||||
|
||||
} // namespace dispatch
|
||||
|
||||
namespace detail { namespace overlay
|
||||
{
|
||||
|
||||
template<>
|
||||
struct get_ring<detail::buffer::buffered_ring_collection_tag>
|
||||
{
|
||||
template<typename MultiGeometry>
|
||||
static inline typename ring_type<MultiGeometry>::type const& apply(
|
||||
ring_identifier const& id,
|
||||
MultiGeometry const& multi_ring)
|
||||
{
|
||||
BOOST_GEOMETRY_ASSERT
|
||||
(
|
||||
id.multi_index >= 0
|
||||
&& id.multi_index < int(boost::size(multi_ring))
|
||||
);
|
||||
return get_ring<ring_tag>::apply(id, multi_ring[id.multi_index]);
|
||||
}
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_RING
|
||||
+327
@@ -0,0 +1,327 @@
|
||||
// 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-2020.
|
||||
// Modifications copyright (c) 2017-2020 Oracle and/or its affiliates.
|
||||
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
|
||||
|
||||
// Use, modification and distribution is subject to the Boost Software License,
|
||||
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_GET_PIECE_TURNS_HPP
|
||||
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_GET_PIECE_TURNS_HPP
|
||||
|
||||
#include <boost/core/ignore_unused.hpp>
|
||||
#include <boost/range/begin.hpp>
|
||||
#include <boost/range/end.hpp>
|
||||
#include <boost/range/value_type.hpp>
|
||||
|
||||
#include <boost/geometry/core/assert.hpp>
|
||||
#include <boost/geometry/algorithms/equals.hpp>
|
||||
#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
|
||||
#include <boost/geometry/algorithms/detail/sections/section_functions.hpp>
|
||||
#include <boost/geometry/algorithms/detail/buffer/buffer_policies.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace buffer
|
||||
{
|
||||
|
||||
// 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
|
||||
{
|
||||
typedef typename boost::range_iterator<Ring const>::type iterator_type;
|
||||
typedef typename geometry::point_type<Ring const>::type point_type;
|
||||
|
||||
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
|
||||
{
|
||||
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;
|
||||
};
|
||||
|
||||
template
|
||||
<
|
||||
typename Pieces,
|
||||
typename Rings,
|
||||
typename Turns,
|
||||
typename Strategy,
|
||||
typename RobustPolicy
|
||||
>
|
||||
class piece_turn_visitor
|
||||
{
|
||||
Pieces const& m_pieces;
|
||||
Rings const& m_rings;
|
||||
Turns& m_turns;
|
||||
Strategy const& m_strategy;
|
||||
RobustPolicy const& m_robust_policy;
|
||||
|
||||
template <typename Piece>
|
||||
inline bool is_adjacent(Piece const& piece1, Piece const& piece2) const
|
||||
{
|
||||
if (piece1.first_seg_id.multi_index != piece2.first_seg_id.multi_index)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return piece1.index == piece2.left_index
|
||||
|| piece1.index == piece2.right_index;
|
||||
}
|
||||
|
||||
template <typename Piece>
|
||||
inline bool is_on_same_convex_ring(Piece const& piece1, Piece const& piece2) const
|
||||
{
|
||||
if (piece1.first_seg_id.multi_index != piece2.first_seg_id.multi_index)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return ! m_rings[piece1.first_seg_id.multi_index].has_concave;
|
||||
}
|
||||
|
||||
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& 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),
|
||||
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& 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),
|
||||
this_bounding_box, other_bounding_box, m_robust_policy))
|
||||
{
|
||||
--it_beyond;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Piece, typename Section>
|
||||
inline void calculate_turns(Piece const& piece1, Piece const& piece2,
|
||||
Section const& section1, Section const& section2)
|
||||
{
|
||||
typedef typename boost::range_value<Rings const>::type ring_type;
|
||||
typedef typename boost::range_value<Turns const>::type turn_type;
|
||||
|
||||
signed_size_type const piece1_first_index = piece1.first_seg_id.segment_index;
|
||||
signed_size_type const piece2_first_index = piece2.first_seg_id.segment_index;
|
||||
if (piece1_first_index < 0 || piece2_first_index < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Get indices of part of offsetted_rings for this monotonic section:
|
||||
signed_size_type const sec1_first_index = piece1_first_index + section1.begin_index;
|
||||
signed_size_type const sec2_first_index = piece2_first_index + section2.begin_index;
|
||||
|
||||
// index of last point in section, beyond-end is one further
|
||||
signed_size_type const sec1_last_index = piece1_first_index + section1.end_index;
|
||||
signed_size_type const sec2_last_index = piece2_first_index + section2.end_index;
|
||||
|
||||
// get geometry and iterators over these sections
|
||||
ring_type const& ring1 = m_rings[piece1.first_seg_id.multi_index];
|
||||
auto it1_first = boost::begin(ring1) + sec1_first_index;
|
||||
auto it1_beyond = boost::begin(ring1) + sec1_last_index + 1;
|
||||
|
||||
ring_type const& ring2 = m_rings[piece2.first_seg_id.multi_index];
|
||||
auto it2_first = boost::begin(ring2) + sec2_first_index;
|
||||
auto it2_beyond = boost::begin(ring2) + sec2_last_index + 1;
|
||||
|
||||
// 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], section1.bounding_box, section2.bounding_box);
|
||||
move_end_iterator<0>(it1_first, it1_beyond,
|
||||
section1.directions[0], section1.bounding_box, section2.bounding_box);
|
||||
move_begin_iterator<1>(it1_first, it1_beyond, index1,
|
||||
section1.directions[1], section1.bounding_box, section2.bounding_box);
|
||||
move_end_iterator<1>(it1_first, it1_beyond,
|
||||
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], section2.bounding_box, section1.bounding_box);
|
||||
move_end_iterator<0>(it2_first, it2_beyond,
|
||||
section2.directions[0], section2.bounding_box, section1.bounding_box);
|
||||
move_begin_iterator<1>(it2_first, it2_beyond, index2,
|
||||
section2.directions[1], section2.bounding_box, section1.bounding_box);
|
||||
move_end_iterator<1>(it2_first, it2_beyond,
|
||||
section2.directions[1], section2.bounding_box, section1.bounding_box);
|
||||
|
||||
turn_type the_model;
|
||||
the_model.operations[0].piece_index = piece1.index;
|
||||
the_model.operations[0].seg_id = piece1.first_seg_id;
|
||||
the_model.operations[0].seg_id.segment_index = index1; // override
|
||||
|
||||
auto it1 = it1_first;
|
||||
for (auto prev1 = it1++;
|
||||
it1 != it1_beyond;
|
||||
prev1 = it1++, the_model.operations[0].seg_id.segment_index++)
|
||||
{
|
||||
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
|
||||
|
||||
unique_sub_range_from_piece<ring_type> unique_sub_range1(ring1, prev1, it1);
|
||||
|
||||
auto it2 = it2_first;
|
||||
for (auto prev2 = it2++;
|
||||
it2 != it2_beyond;
|
||||
prev2 = it2++, the_model.operations[1].seg_id.segment_index++)
|
||||
{
|
||||
unique_sub_range_from_piece<ring_type> unique_sub_range2(ring2, prev2, it2);
|
||||
|
||||
typedef detail::overlay::get_turn_info
|
||||
<
|
||||
detail::overlay::assign_policy_only_start_turns
|
||||
> turn_policy;
|
||||
|
||||
turn_policy::apply(unique_sub_range1, unique_sub_range2,
|
||||
the_model,
|
||||
m_strategy,
|
||||
m_robust_policy,
|
||||
std::back_inserter(m_turns));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
piece_turn_visitor(Pieces const& pieces,
|
||||
Rings const& ring_collection,
|
||||
Turns& turns,
|
||||
Strategy const& strategy,
|
||||
RobustPolicy const& robust_policy)
|
||||
: m_pieces(pieces)
|
||||
, m_rings(ring_collection)
|
||||
, m_turns(turns)
|
||||
, m_strategy(strategy)
|
||||
, m_robust_policy(robust_policy)
|
||||
{}
|
||||
|
||||
template <typename Section>
|
||||
inline bool apply(Section const& section1, Section const& section2,
|
||||
bool first = true)
|
||||
{
|
||||
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];
|
||||
piece_type const& piece2 = m_pieces[section2.ring_id.source_index];
|
||||
|
||||
if ( piece1.index == piece2.index
|
||||
|| is_adjacent(piece1, piece2)
|
||||
|| is_on_same_convex_ring(piece1, piece2)
|
||||
|| detail::disjoint::disjoint_box_box(section1.bounding_box,
|
||||
section2.bounding_box,
|
||||
m_strategy) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
calculate_turns(piece1, piece2, section1, section2);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}} // namespace detail::buffer
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_GET_PIECE_TURNS_HPP
|
||||
+214
@@ -0,0 +1,214 @@
|
||||
// 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 2017-2022.
|
||||
// Modifications copyright (c) 2017-2022 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_BUFFER_IMPLEMENTATION_HPP
|
||||
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_IMPLEMENTATION_HPP
|
||||
|
||||
#include <boost/range/value_type.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/detail/buffer/buffer_box.hpp>
|
||||
#include <boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp>
|
||||
#include <boost/geometry/algorithms/detail/buffer/interface.hpp>
|
||||
#include <boost/geometry/algorithms/detail/visit.hpp> // for GC
|
||||
#include <boost/geometry/algorithms/envelope.hpp>
|
||||
#include <boost/geometry/algorithms/is_empty.hpp>
|
||||
#include <boost/geometry/algorithms/union.hpp> // for GC
|
||||
#include <boost/geometry/arithmetic/arithmetic.hpp>
|
||||
#include <boost/geometry/geometries/box.hpp>
|
||||
#include <boost/geometry/strategies/buffer/cartesian.hpp>
|
||||
#include <boost/geometry/strategies/buffer/geographic.hpp>
|
||||
#include <boost/geometry/strategies/buffer/spherical.hpp>
|
||||
#include <boost/geometry/util/math.hpp>
|
||||
#include <boost/geometry/util/range.hpp>
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
#ifndef DOXYGEN_NO_DISPATCH
|
||||
namespace dispatch
|
||||
{
|
||||
|
||||
template <typename BoxIn, typename BoxOut>
|
||||
struct buffer_dc<BoxIn, BoxOut, box_tag, box_tag>
|
||||
{
|
||||
template <typename Distance>
|
||||
static inline void apply(BoxIn const& box_in, BoxOut& box_out,
|
||||
Distance const& distance, Distance const& )
|
||||
{
|
||||
detail::buffer::buffer_box(box_in, distance, box_out);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename Input, typename Output, typename TagIn>
|
||||
struct buffer_all<Input, Output, TagIn, multi_polygon_tag>
|
||||
{
|
||||
template
|
||||
<
|
||||
typename DistanceStrategy,
|
||||
typename SideStrategy,
|
||||
typename JoinStrategy,
|
||||
typename EndStrategy,
|
||||
typename PointStrategy,
|
||||
typename Strategies
|
||||
>
|
||||
static inline void apply(Input const& geometry_in,
|
||||
Output& geometry_out,
|
||||
DistanceStrategy const& distance_strategy,
|
||||
SideStrategy const& side_strategy,
|
||||
JoinStrategy const& join_strategy,
|
||||
EndStrategy const& end_strategy,
|
||||
PointStrategy const& point_strategy,
|
||||
Strategies const& strategies)
|
||||
{
|
||||
typedef typename boost::range_value<Output>::type polygon_type;
|
||||
|
||||
typedef typename point_type<Input>::type point_type;
|
||||
typedef typename rescale_policy_type
|
||||
<
|
||||
point_type,
|
||||
typename geometry::cs_tag<point_type>::type
|
||||
>::type rescale_policy_type;
|
||||
|
||||
if (geometry::is_empty(geometry_in))
|
||||
{
|
||||
// Then output geometry is kept empty as well
|
||||
return;
|
||||
}
|
||||
|
||||
model::box<point_type> box;
|
||||
geometry::envelope(geometry_in, box);
|
||||
geometry::buffer(box, box, distance_strategy.max_distance(join_strategy, end_strategy));
|
||||
|
||||
rescale_policy_type rescale_policy
|
||||
= boost::geometry::get_rescale_policy<rescale_policy_type>(
|
||||
box, strategies);
|
||||
|
||||
detail::buffer::buffer_inserter<polygon_type>(geometry_in,
|
||||
range::back_inserter(geometry_out),
|
||||
distance_strategy,
|
||||
side_strategy,
|
||||
join_strategy,
|
||||
end_strategy,
|
||||
point_strategy,
|
||||
strategies,
|
||||
rescale_policy);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename Input, typename Output>
|
||||
struct buffer_all<Input, Output, geometry_collection_tag, multi_polygon_tag>
|
||||
{
|
||||
template
|
||||
<
|
||||
typename DistanceStrategy,
|
||||
typename SideStrategy,
|
||||
typename JoinStrategy,
|
||||
typename EndStrategy,
|
||||
typename PointStrategy,
|
||||
typename Strategies
|
||||
>
|
||||
static inline void apply(Input const& geometry_in,
|
||||
Output& geometry_out,
|
||||
DistanceStrategy const& distance_strategy,
|
||||
SideStrategy const& side_strategy,
|
||||
JoinStrategy const& join_strategy,
|
||||
EndStrategy const& end_strategy,
|
||||
PointStrategy const& point_strategy,
|
||||
Strategies const& strategies)
|
||||
{
|
||||
// NOTE: The buffer normally calculates everything at once (by pieces) and traverses all
|
||||
// of them to apply the union operation. Not even by merging elements. But that is
|
||||
// complex and has led to issues as well. Here intermediate results are calculated
|
||||
// with buffer and the results are merged afterwards.
|
||||
// NOTE: This algorithm merges partial results iteratively.
|
||||
// We could first gather all of the results and after that
|
||||
// use some more optimal method like merge_elements().
|
||||
detail::visit_breadth_first([&](auto const& g)
|
||||
{
|
||||
Output buffer_result;
|
||||
buffer_all
|
||||
<
|
||||
util::remove_cref_t<decltype(g)>, Output
|
||||
>::apply(g, buffer_result, distance_strategy, side_strategy,
|
||||
join_strategy, end_strategy, point_strategy, strategies);
|
||||
|
||||
if (! geometry::is_empty(buffer_result))
|
||||
{
|
||||
Output union_result;
|
||||
geometry::union_(geometry_out, buffer_result, union_result, strategies);
|
||||
geometry_out = std::move(union_result);
|
||||
}
|
||||
|
||||
return true;
|
||||
}, geometry_in);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Input, typename Output>
|
||||
struct buffer_all<Input, Output, geometry_collection_tag, geometry_collection_tag>
|
||||
{
|
||||
template
|
||||
<
|
||||
typename DistanceStrategy,
|
||||
typename SideStrategy,
|
||||
typename JoinStrategy,
|
||||
typename EndStrategy,
|
||||
typename PointStrategy,
|
||||
typename Strategies
|
||||
>
|
||||
static inline void apply(Input const& geometry_in,
|
||||
Output& geometry_out,
|
||||
DistanceStrategy const& distance_strategy,
|
||||
SideStrategy const& side_strategy,
|
||||
JoinStrategy const& join_strategy,
|
||||
EndStrategy const& end_strategy,
|
||||
PointStrategy const& point_strategy,
|
||||
Strategies const& strategies)
|
||||
{
|
||||
// NOTE: We could also allow returning GC containing only polygons.
|
||||
// We'd have to wrap them in model::multi_polygon and then
|
||||
// iteratively emplace_back() into the GC.
|
||||
using mpo_t = typename util::sequence_find_if
|
||||
<
|
||||
typename traits::geometry_types<Output>::type,
|
||||
util::is_multi_polygon
|
||||
>::type;
|
||||
mpo_t result;
|
||||
buffer_all
|
||||
<
|
||||
Input, mpo_t
|
||||
>::apply(geometry_in, result, distance_strategy, side_strategy,
|
||||
join_strategy, end_strategy, point_strategy, strategies);
|
||||
range::emplace_back(geometry_out, std::move(result));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Input, typename Output, typename TagIn>
|
||||
struct buffer_all<Input, Output, TagIn, geometry_collection_tag>
|
||||
: buffer_all<Input, Output, geometry_collection_tag, geometry_collection_tag>
|
||||
{};
|
||||
|
||||
|
||||
} // namespace dispatch
|
||||
#endif // DOXYGEN_NO_DISPATCH
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
|
||||
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_IMPLEMENTATION_HPP
|
||||
+279
@@ -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 2017-2022.
|
||||
// Modifications copyright (c) 2017-2022 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_BUFFER_INTERFACE_HPP
|
||||
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_INTERFACE_HPP
|
||||
|
||||
#include <boost/geometry/algorithms/clear.hpp>
|
||||
#include <boost/geometry/algorithms/not_implemented.hpp>
|
||||
#include <boost/geometry/core/visit.hpp>
|
||||
#include <boost/geometry/core/tag.hpp>
|
||||
#include <boost/geometry/geometries/adapted/boost_variant.hpp>
|
||||
#include <boost/geometry/geometries/concepts/check.hpp>
|
||||
#include <boost/geometry/strategies/buffer/services.hpp>
|
||||
#include <boost/geometry/util/type_traits_std.hpp>
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
#ifndef DOXYGEN_NO_DISPATCH
|
||||
namespace dispatch
|
||||
{
|
||||
|
||||
template
|
||||
<
|
||||
typename Input,
|
||||
typename Output,
|
||||
typename TagIn = typename tag<Input>::type,
|
||||
typename TagOut = typename tag<Output>::type
|
||||
>
|
||||
struct buffer_dc : not_implemented<TagIn, TagOut>
|
||||
{};
|
||||
|
||||
template
|
||||
<
|
||||
typename Input,
|
||||
typename Output,
|
||||
typename TagIn = typename tag<Input>::type,
|
||||
typename TagOut = typename tag<Output>::type
|
||||
>
|
||||
struct buffer_all : not_implemented<TagIn, TagOut>
|
||||
{};
|
||||
|
||||
} // namespace dispatch
|
||||
#endif // DOXYGEN_NO_DISPATCH
|
||||
|
||||
|
||||
namespace resolve_dynamic
|
||||
{
|
||||
|
||||
template
|
||||
<
|
||||
typename Input,
|
||||
typename TagIn = typename geometry::tag<Input>::type
|
||||
>
|
||||
struct buffer_dc
|
||||
{
|
||||
template <typename Output, typename Distance>
|
||||
static inline void apply(Input const& geometry_in,
|
||||
Output& geometry_out,
|
||||
Distance const& distance,
|
||||
Distance const& chord_length)
|
||||
{
|
||||
dispatch::buffer_dc<Input, Output>::apply(geometry_in, geometry_out, distance, chord_length);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Input>
|
||||
struct buffer_dc<Input, dynamic_geometry_tag>
|
||||
{
|
||||
template <typename Output, typename Distance>
|
||||
static inline void apply(Input const& geometry_in,
|
||||
Output& geometry_out,
|
||||
Distance const& distance,
|
||||
Distance const& chord_length)
|
||||
{
|
||||
traits::visit<Input>::apply([&](auto const& g)
|
||||
{
|
||||
dispatch::buffer_dc
|
||||
<
|
||||
util::remove_cref_t<decltype(g)>, Output
|
||||
>::apply(g, geometry_out, distance, chord_length);
|
||||
}, geometry_in);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template
|
||||
<
|
||||
typename Input,
|
||||
typename TagIn = typename geometry::tag<Input>::type
|
||||
>
|
||||
struct buffer_all
|
||||
{
|
||||
template
|
||||
<
|
||||
typename Output,
|
||||
typename DistanceStrategy,
|
||||
typename SideStrategy,
|
||||
typename JoinStrategy,
|
||||
typename EndStrategy,
|
||||
typename PointStrategy
|
||||
>
|
||||
static inline void apply(Input const& geometry_in,
|
||||
Output& geometry_out,
|
||||
DistanceStrategy const& distance_strategy,
|
||||
SideStrategy const& side_strategy,
|
||||
JoinStrategy const& join_strategy,
|
||||
EndStrategy const& end_strategy,
|
||||
PointStrategy const& point_strategy)
|
||||
{
|
||||
typename strategies::buffer::services::default_strategy
|
||||
<
|
||||
Input
|
||||
>::type strategies;
|
||||
|
||||
dispatch::buffer_all
|
||||
<
|
||||
Input, Output
|
||||
>::apply(geometry_in, geometry_out, distance_strategy, side_strategy,
|
||||
join_strategy, end_strategy, point_strategy, strategies);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Input>
|
||||
struct buffer_all<Input, dynamic_geometry_tag>
|
||||
{
|
||||
template
|
||||
<
|
||||
typename Output,
|
||||
typename DistanceStrategy,
|
||||
typename SideStrategy,
|
||||
typename JoinStrategy,
|
||||
typename EndStrategy,
|
||||
typename PointStrategy
|
||||
>
|
||||
static inline void apply(Input const& geometry_in,
|
||||
Output& geometry_out,
|
||||
DistanceStrategy const& distance_strategy,
|
||||
SideStrategy const& side_strategy,
|
||||
JoinStrategy const& join_strategy,
|
||||
EndStrategy const& end_strategy,
|
||||
PointStrategy const& point_strategy)
|
||||
{
|
||||
traits::visit<Input>::apply([&](auto const& g)
|
||||
{
|
||||
buffer_all
|
||||
<
|
||||
util::remove_cref_t<decltype(g)>
|
||||
>::apply(g, geometry_out, distance_strategy, side_strategy,
|
||||
join_strategy, end_strategy, point_strategy);
|
||||
}, geometry_in);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace resolve_dynamic
|
||||
|
||||
|
||||
/*!
|
||||
\brief \brief_calc{buffer}
|
||||
\ingroup buffer
|
||||
\details \details_calc{buffer, \det_buffer}.
|
||||
\tparam Input \tparam_geometry
|
||||
\tparam Output \tparam_geometry
|
||||
\tparam Distance \tparam_numeric
|
||||
\param geometry_in \param_geometry
|
||||
\param geometry_out \param_geometry
|
||||
\param distance The distance to be used for the buffer
|
||||
\param chord_length (optional) The length of the chord's in the generated arcs around points or bends
|
||||
|
||||
\qbk{[include reference/algorithms/buffer.qbk]}
|
||||
*/
|
||||
template <typename Input, typename Output, typename Distance>
|
||||
inline void buffer(Input const& geometry_in, Output& geometry_out,
|
||||
Distance const& distance, Distance const& chord_length = -1)
|
||||
{
|
||||
concepts::check<Input const>();
|
||||
concepts::check<Output>();
|
||||
|
||||
resolve_dynamic::buffer_dc<Input>::apply(geometry_in, geometry_out, distance, chord_length);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief \brief_calc{buffer}
|
||||
\ingroup buffer
|
||||
\details \details_calc{return_buffer, \det_buffer}. \details_return{buffer}.
|
||||
\tparam Input \tparam_geometry
|
||||
\tparam Output \tparam_geometry
|
||||
\tparam Distance \tparam_numeric
|
||||
\param geometry \param_geometry
|
||||
\param distance The distance to be used for the buffer
|
||||
\param chord_length (optional) The length of the chord's in the generated arcs
|
||||
around points or bends (RESERVED, NOT YET USED)
|
||||
\return \return_calc{buffer}
|
||||
*/
|
||||
template <typename Output, typename Input, typename Distance>
|
||||
inline Output return_buffer(Input const& geometry, Distance const& distance,
|
||||
Distance const& chord_length = -1)
|
||||
{
|
||||
concepts::check<Input const>();
|
||||
concepts::check<Output>();
|
||||
|
||||
Output geometry_out;
|
||||
|
||||
resolve_dynamic::buffer_dc<Input>::apply(geometry, geometry_out, distance, chord_length);
|
||||
|
||||
return geometry_out;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief \brief_calc{buffer}
|
||||
\ingroup buffer
|
||||
\details \details_calc{buffer, \det_buffer}.
|
||||
\tparam GeometryIn \tparam_geometry
|
||||
\tparam GeometryOut \tparam_geometry{GeometryOut}
|
||||
\tparam DistanceStrategy A strategy defining distance (or radius)
|
||||
\tparam SideStrategy A strategy defining creation along sides
|
||||
\tparam JoinStrategy A strategy defining creation around convex corners
|
||||
\tparam EndStrategy A strategy defining creation at linestring ends
|
||||
\tparam PointStrategy A strategy defining creation around points
|
||||
\param geometry_in \param_geometry
|
||||
\param geometry_out output geometry, e.g. multi polygon,
|
||||
will contain a buffered version of the input geometry
|
||||
\param distance_strategy The distance strategy to be used
|
||||
\param side_strategy The side strategy to be used
|
||||
\param join_strategy The join strategy to be used
|
||||
\param end_strategy The end strategy to be used
|
||||
\param point_strategy The point strategy to be used
|
||||
|
||||
\qbk{distinguish,with strategies}
|
||||
\qbk{[include reference/algorithms/buffer_with_strategies.qbk]}
|
||||
*/
|
||||
template
|
||||
<
|
||||
typename GeometryIn,
|
||||
typename GeometryOut,
|
||||
typename DistanceStrategy,
|
||||
typename SideStrategy,
|
||||
typename JoinStrategy,
|
||||
typename EndStrategy,
|
||||
typename PointStrategy
|
||||
>
|
||||
inline void buffer(GeometryIn const& geometry_in,
|
||||
GeometryOut& geometry_out,
|
||||
DistanceStrategy const& distance_strategy,
|
||||
SideStrategy const& side_strategy,
|
||||
JoinStrategy const& join_strategy,
|
||||
EndStrategy const& end_strategy,
|
||||
PointStrategy const& point_strategy)
|
||||
{
|
||||
concepts::check<GeometryIn const>();
|
||||
concepts::check<GeometryOut>();
|
||||
|
||||
geometry::clear(geometry_out);
|
||||
|
||||
resolve_dynamic::buffer_all
|
||||
<
|
||||
GeometryIn, GeometryOut
|
||||
>::apply(geometry_in, geometry_out, distance_strategy, side_strategy,
|
||||
join_strategy, end_strategy, point_strategy);
|
||||
}
|
||||
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_INTERFACE_HPP
|
||||
Vendored
Executable
+120
@@ -0,0 +1,120 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// Copyright (c) 2012-2020 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_LINE_LINE_INTERSECTION_HPP
|
||||
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_LINE_LINE_INTERSECTION_HPP
|
||||
|
||||
#include <boost/geometry/algorithms/detail/make/make.hpp>
|
||||
#include <boost/geometry/arithmetic/infinite_line_functions.hpp>
|
||||
#include <boost/geometry/util/math.hpp>
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace buffer
|
||||
{
|
||||
|
||||
struct line_line_intersection
|
||||
{
|
||||
template <typename Point>
|
||||
static Point between_point(Point const& a, Point const& b)
|
||||
{
|
||||
Point result;
|
||||
geometry::set<0>(result, (geometry::get<0>(a) + geometry::get<0>(b)) / 2.0);
|
||||
geometry::set<1>(result, (geometry::get<1>(a) + geometry::get<1>(b)) / 2.0);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename Point>
|
||||
static bool
|
||||
apply(Point const& pi, Point const& pj, Point const& qi, Point const& qj,
|
||||
Point const& vertex, bool equidistant, Point& ip)
|
||||
{
|
||||
// Calculates ip (below) by either intersecting p (pi, pj)
|
||||
// with q (qi, qj) or by taking a point between pj and qi (b) and
|
||||
// intersecting r (b, v), where v is the original vertex, with p (or q).
|
||||
// The reason for dual approach: p might be nearly collinear with q,
|
||||
// and in that case the intersection points can lose precision
|
||||
// (or be plainly wrong).
|
||||
// Therefore it takes the most precise option (this is usually p, r)
|
||||
//
|
||||
// /qj |
|
||||
// / |
|
||||
// / / |
|
||||
// / / |
|
||||
// / / |
|
||||
// /qi / |
|
||||
// / |
|
||||
// ip * + b * v |
|
||||
// \ |
|
||||
// \pj \ |
|
||||
// \ \ |
|
||||
// \ \ |
|
||||
// \ \ |
|
||||
// \pi \ |
|
||||
//
|
||||
// If generated sides along the segments can have an adapted distance,
|
||||
// in a custom strategy, then the calculation of the point in between
|
||||
// might be incorrect and the optimization is not used.
|
||||
|
||||
using ct = typename coordinate_type<Point>::type;
|
||||
|
||||
auto const p = detail::make::make_infinite_line<ct>(pi, pj);
|
||||
auto const q = detail::make::make_infinite_line<ct>(qi, qj);
|
||||
|
||||
using line = decltype(p);
|
||||
using arithmetic::determinant;
|
||||
using arithmetic::assign_intersection_point;
|
||||
|
||||
// The denominator is the determinant of (a,b) values of lines p q
|
||||
// | pa pa |
|
||||
// | qb qb |
|
||||
auto const denominator_pq = determinant<line, &line::a, &line::b>(p, q);
|
||||
static decltype(denominator_pq) const zero = 0;
|
||||
|
||||
if (equidistant)
|
||||
{
|
||||
auto const between = between_point(pj, qi);
|
||||
auto const r = detail::make::make_infinite_line<ct>(vertex, between);
|
||||
auto const denominator_pr = determinant<line, &line::a, &line::b>(p, r);
|
||||
|
||||
if (math::equals(denominator_pq, zero)
|
||||
&& math::equals(denominator_pr, zero))
|
||||
{
|
||||
// Degenerate case (for example when length results in <inf>)
|
||||
return false;
|
||||
}
|
||||
|
||||
ip = geometry::math::abs(denominator_pq) > geometry::math::abs(denominator_pr)
|
||||
? assign_intersection_point<Point>(p, q, denominator_pq)
|
||||
: assign_intersection_point<Point>(p, r, denominator_pr);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (math::equals(denominator_pq, zero))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
ip = assign_intersection_point<Point>(p, q, denominator_pq);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}} // namespace detail::buffer
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
|
||||
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_LINE_LINE_INTERSECTION_HPP
|
||||
+512
@@ -0,0 +1,512 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// Copyright (c) 2020-2021 Barend Gehrels, Amsterdam, the Netherlands.
|
||||
// Copyright (c) 2023 Adam Wulkiewicz, Lodz, Poland.
|
||||
|
||||
// This file was modified by Oracle on 2020-2022.
|
||||
// Modifications copyright (c) 2020-2022, Oracle and/or its affiliates.
|
||||
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
|
||||
|
||||
// Use, modification and distribution is subject to the Boost Software License,
|
||||
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_PIECE_BORDER_HPP
|
||||
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_PIECE_BORDER_HPP
|
||||
|
||||
|
||||
#include <array>
|
||||
|
||||
#include <boost/core/addressof.hpp>
|
||||
#include <boost/range/size.hpp>
|
||||
|
||||
#include <boost/geometry/core/assert.hpp>
|
||||
#include <boost/geometry/core/config.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/assign.hpp>
|
||||
#include <boost/geometry/algorithms/comparable_distance.hpp>
|
||||
#include <boost/geometry/algorithms/equals.hpp>
|
||||
#include <boost/geometry/algorithms/expand.hpp>
|
||||
#include <boost/geometry/algorithms/detail/buffer/buffer_policies.hpp>
|
||||
#include <boost/geometry/algorithms/detail/expand_by_epsilon.hpp>
|
||||
#include <boost/geometry/strategies/cartesian/turn_in_ring_winding.hpp>
|
||||
#include <boost/geometry/geometries/box.hpp>
|
||||
#include <boost/geometry/geometries/segment.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail
|
||||
{
|
||||
template <typename It, typename T, typename Compare>
|
||||
inline bool get_range_around(It begin, It end, T const& value, Compare const& compare, It& lower, It& upper)
|
||||
{
|
||||
lower = end;
|
||||
upper = end;
|
||||
|
||||
// Get first element not smaller than value
|
||||
if (begin == end)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (compare(value, *begin))
|
||||
{
|
||||
// The value is smaller than the first item, therefore not in range
|
||||
return false;
|
||||
}
|
||||
// *(begin + std::distance(begin, end) - 1))
|
||||
if (compare(*(end - 1), value))
|
||||
{
|
||||
// The last item is larger than the value, therefore not in range
|
||||
return false;
|
||||
}
|
||||
|
||||
// Assign the iterators.
|
||||
// lower >= begin and lower < end
|
||||
// upper > lower and upper <= end
|
||||
// lower_bound points to first element NOT LESS than value - but because
|
||||
// we want the first value LESS than value, we decrease it
|
||||
lower = std::lower_bound(begin, end, value, compare);
|
||||
// upper_bound points to first element of which value is LESS
|
||||
upper = std::upper_bound(begin, end, value, compare);
|
||||
|
||||
if (lower != begin)
|
||||
{
|
||||
--lower;
|
||||
}
|
||||
if (upper != end)
|
||||
{
|
||||
++upper;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
namespace detail { namespace buffer
|
||||
{
|
||||
|
||||
//! Contains the border of the piece, consisting of 4 parts:
|
||||
//! 1: the part of the offsetted ring (referenced, not copied)
|
||||
//! 2: the part of the original (one or two points)
|
||||
//! 3: the left part (from original to offsetted)
|
||||
//! 4: the right part (from offsetted to original)
|
||||
//! Besides that, it contains some properties of the piece(border);
|
||||
//! - convexity
|
||||
//! - envelope
|
||||
//! - monotonicity of the offsetted ring
|
||||
//! - min/max radius of a point buffer
|
||||
//! - if it is a "reversed" piece (linear features with partly negative buffers)
|
||||
template <typename Ring, typename Point>
|
||||
struct piece_border
|
||||
{
|
||||
typedef typename geometry::coordinate_type<Point>::type coordinate_type;
|
||||
typedef typename default_comparable_distance_result<Point>::type radius_type;
|
||||
typedef typename geometry::strategy::buffer::turn_in_ring_winding<coordinate_type>::state_type state_type;
|
||||
|
||||
bool m_reversed;
|
||||
|
||||
// Points from the offsetted ring. They are not copied, this structure
|
||||
// refers to those points
|
||||
Ring const* m_ring;
|
||||
std::size_t m_begin;
|
||||
std::size_t m_end;
|
||||
|
||||
// Points from the original (one or two, depending on piece shape)
|
||||
// Note, if there are 2 points, they are REVERSED w.r.t. the original
|
||||
// Therefore here we can walk in its order.
|
||||
std::array<Point, 2> m_originals;
|
||||
std::size_t m_original_size;
|
||||
|
||||
geometry::model::box<Point> m_envelope;
|
||||
bool m_has_envelope;
|
||||
|
||||
// True if piece is determined as "convex"
|
||||
bool m_is_convex;
|
||||
|
||||
// True if offsetted part is monotonically changing in x-direction
|
||||
bool m_is_monotonic_increasing;
|
||||
bool m_is_monotonic_decreasing;
|
||||
|
||||
radius_type m_min_comparable_radius;
|
||||
radius_type m_max_comparable_radius;
|
||||
|
||||
piece_border()
|
||||
: m_reversed(false)
|
||||
, m_ring(NULL)
|
||||
, m_begin(0)
|
||||
, m_end(0)
|
||||
, m_original_size(0)
|
||||
, m_has_envelope(false)
|
||||
, m_is_convex(false)
|
||||
, m_is_monotonic_increasing(false)
|
||||
, m_is_monotonic_decreasing(false)
|
||||
, m_min_comparable_radius(0)
|
||||
, m_max_comparable_radius(0)
|
||||
{
|
||||
}
|
||||
|
||||
// Only used for debugging (SVG)
|
||||
Ring get_full_ring() const
|
||||
{
|
||||
Ring result;
|
||||
if (ring_or_original_empty())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
std::copy(m_ring->begin() + m_begin,
|
||||
m_ring->begin() + m_end,
|
||||
std::back_inserter(result));
|
||||
std::copy(m_originals.begin(),
|
||||
m_originals.begin() + m_original_size,
|
||||
std::back_inserter(result));
|
||||
// Add the closing point
|
||||
result.push_back(*(m_ring->begin() + m_begin));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename Strategy>
|
||||
void get_properties_of_border(bool is_point_buffer, Point const& center,
|
||||
Strategy const& strategy)
|
||||
{
|
||||
m_has_envelope = calculate_envelope(m_envelope, strategy);
|
||||
if (m_has_envelope)
|
||||
{
|
||||
// Take roundings into account, enlarge box
|
||||
geometry::detail::expand_by_epsilon(m_envelope);
|
||||
}
|
||||
if (! ring_or_original_empty() && is_point_buffer)
|
||||
{
|
||||
// Determine min/max radius
|
||||
calculate_radii(center, m_ring->begin() + m_begin, m_ring->begin() + m_end);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Strategy>
|
||||
void get_properties_of_offsetted_ring_part(Strategy const& strategy)
|
||||
{
|
||||
if (! ring_or_original_empty())
|
||||
{
|
||||
m_is_convex = is_convex(strategy);
|
||||
check_monotonicity(m_ring->begin() + m_begin, m_ring->begin() + m_end);
|
||||
}
|
||||
}
|
||||
|
||||
void set_offsetted(Ring const& ring, std::size_t begin, std::size_t end)
|
||||
{
|
||||
BOOST_GEOMETRY_ASSERT(begin <= end);
|
||||
BOOST_GEOMETRY_ASSERT(begin < boost::size(ring));
|
||||
BOOST_GEOMETRY_ASSERT(end <= boost::size(ring));
|
||||
|
||||
m_ring = boost::addressof(ring);
|
||||
m_begin = begin;
|
||||
m_end = end;
|
||||
}
|
||||
|
||||
void add_original_point(Point const& point)
|
||||
{
|
||||
BOOST_GEOMETRY_ASSERT(m_original_size < 2);
|
||||
m_originals[m_original_size++] = point;
|
||||
}
|
||||
|
||||
template <typename Box, typename Strategy>
|
||||
bool calculate_envelope(Box& envelope, Strategy const& strategy) const
|
||||
{
|
||||
geometry::assign_inverse(envelope);
|
||||
if (ring_or_original_empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
expand_envelope(envelope, m_ring->begin() + m_begin, m_ring->begin() + m_end, strategy);
|
||||
expand_envelope(envelope, m_originals.begin(), m_originals.begin() + m_original_size, strategy);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Whatever the return value, the state should be checked.
|
||||
template <typename TurnPoint, typename State>
|
||||
bool point_on_piece(TurnPoint const& point,
|
||||
bool one_sided, bool is_linear_end_point,
|
||||
State& state) const
|
||||
{
|
||||
if (ring_or_original_empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Walk over the different parts of the ring, in clockwise order
|
||||
// For performance reasons: start with the helper part (one segment)
|
||||
// then the original part (one segment, if any), then the other helper
|
||||
// part (one segment), and only then the offsetted part
|
||||
// (probably more segments, check monotonicity)
|
||||
geometry::strategy::buffer::turn_in_ring_winding<coordinate_type> tir;
|
||||
|
||||
Point const offsetted_front = *(m_ring->begin() + m_begin);
|
||||
Point const offsetted_back = *(m_ring->begin() + m_end - 1);
|
||||
|
||||
// For onesided buffers, or turns colocated with linear end points,
|
||||
// the place on the ring is changed to offsetted (because of colocation)
|
||||
geometry::strategy::buffer::place_on_ring_type const por_original
|
||||
= adapted_place_on_ring(geometry::strategy::buffer::place_on_ring_original,
|
||||
one_sided, is_linear_end_point);
|
||||
geometry::strategy::buffer::place_on_ring_type const por_from_offsetted
|
||||
= adapted_place_on_ring(geometry::strategy::buffer::place_on_ring_from_offsetted,
|
||||
one_sided, is_linear_end_point);
|
||||
geometry::strategy::buffer::place_on_ring_type const por_to_offsetted
|
||||
= adapted_place_on_ring(geometry::strategy::buffer::place_on_ring_to_offsetted,
|
||||
one_sided, is_linear_end_point);
|
||||
|
||||
bool continue_processing = true;
|
||||
if (m_original_size == 1)
|
||||
{
|
||||
// One point. Walk from last offsetted to point, and from point to first offsetted
|
||||
continue_processing = step(point, offsetted_back, m_originals[0],
|
||||
tir, por_from_offsetted, state)
|
||||
&& step(point, m_originals[0], offsetted_front,
|
||||
tir, por_to_offsetted, state);
|
||||
}
|
||||
else if (m_original_size == 2)
|
||||
{
|
||||
// Two original points. Walk from last offsetted point to first original point,
|
||||
// then along original, then from second oginal to first offsetted point
|
||||
continue_processing = step(point, offsetted_back, m_originals[0],
|
||||
tir, por_from_offsetted, state)
|
||||
&& step(point, m_originals[0], m_originals[1],
|
||||
tir, por_original, state)
|
||||
&& step(point, m_originals[1], offsetted_front,
|
||||
tir, por_to_offsetted, state);
|
||||
}
|
||||
|
||||
if (continue_processing)
|
||||
{
|
||||
// Check the offsetted ring (in rounded joins, these might be
|
||||
// several segments)
|
||||
walk_offsetted(point, m_ring->begin() + m_begin, m_ring->begin() + m_end,
|
||||
tir, state);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//! Returns true if empty (no ring, or no points, or no original)
|
||||
bool ring_or_original_empty() const
|
||||
{
|
||||
return m_ring == NULL || m_begin >= m_end || m_original_size == 0;
|
||||
}
|
||||
|
||||
private :
|
||||
|
||||
static geometry::strategy::buffer::place_on_ring_type
|
||||
adapted_place_on_ring(geometry::strategy::buffer::place_on_ring_type target,
|
||||
bool one_sided, bool is_linear_end_point)
|
||||
{
|
||||
return one_sided || is_linear_end_point
|
||||
? geometry::strategy::buffer::place_on_ring_offsetted
|
||||
: target;
|
||||
}
|
||||
|
||||
template
|
||||
<
|
||||
typename TurnPoint, typename Iterator,
|
||||
typename TiRStrategy,
|
||||
typename State
|
||||
>
|
||||
bool walk_offsetted(TurnPoint const& point, Iterator begin, Iterator end,
|
||||
TiRStrategy const & strategy,
|
||||
State& state) const
|
||||
{
|
||||
Iterator it = begin;
|
||||
Iterator beyond = end;
|
||||
|
||||
// Move iterators if the offsetted ring is monotonic increasing or decreasing
|
||||
if (m_is_monotonic_increasing)
|
||||
{
|
||||
if (! get_range_around(begin, end, point, geometry::less<Point, 0>(), it, beyond))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (m_is_monotonic_decreasing)
|
||||
{
|
||||
if (! get_range_around(begin, end, point, geometry::greater<Point, 0>(), it, beyond))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (Iterator previous = it++ ; it != beyond ; ++previous, ++it )
|
||||
{
|
||||
if (! step(point, *previous, *it, strategy,
|
||||
geometry::strategy::buffer::place_on_ring_offsetted, state))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename TurnPoint, typename TiRStrategy, typename State>
|
||||
bool step(TurnPoint const& point, Point const& p1, Point const& p2,
|
||||
TiRStrategy const& strategy,
|
||||
geometry::strategy::buffer::place_on_ring_type place_on_ring, State& state) const
|
||||
{
|
||||
return strategy.apply(point, p1, p2, place_on_ring, m_is_convex, state);
|
||||
}
|
||||
|
||||
template <typename It, typename Box, typename Strategy>
|
||||
void expand_envelope(Box& envelope, It begin, It end, Strategy const& strategy) const
|
||||
{
|
||||
for (It it = begin; it != end; ++it)
|
||||
{
|
||||
geometry::expand(envelope, *it, strategy);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Strategy>
|
||||
bool is_convex(Strategy const& strategy) const
|
||||
{
|
||||
if (ring_or_original_empty())
|
||||
{
|
||||
// Convexity is undetermined, and for this case it does not matter,
|
||||
// because it is only used for optimization in point_on_piece,
|
||||
// but that is not called if the piece border is not valid
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_end - m_begin <= 2)
|
||||
{
|
||||
// The offsetted ring part of this piece has only two points.
|
||||
// If this is true, and the original ring part has only one point,
|
||||
// a triangle and it is convex. If the original ring part has two
|
||||
// points, it is a rectangle and theoretically could be concave,
|
||||
// but because of the way the buffer is generated, that is never
|
||||
// the case.
|
||||
return true;
|
||||
}
|
||||
|
||||
// The offsetted ring part of thie piece has at least three points
|
||||
// (this is often the case in a piece marked as "join")
|
||||
|
||||
// We can assume all points of the offset ring are different, and also
|
||||
// that all points on the original are different, and that the offsetted
|
||||
// ring is different from the original(s)
|
||||
Point const offsetted_front = *(m_ring->begin() + m_begin);
|
||||
Point const offsetted_second = *(m_ring->begin() + m_begin + 1);
|
||||
|
||||
// These two points will be reassigned in every is_convex call
|
||||
Point previous = offsetted_front;
|
||||
Point current = offsetted_second;
|
||||
|
||||
// Verify the offsetted range (from the second point on), the original,
|
||||
// and loop through the first two points of the offsetted range
|
||||
bool const result = is_convex(previous, current, m_ring->begin() + m_begin + 2, m_ring->begin() + m_end, strategy)
|
||||
&& is_convex(previous, current, m_originals.begin(), m_originals.begin() + m_original_size, strategy)
|
||||
&& is_convex(previous, current, offsetted_front, strategy)
|
||||
&& is_convex(previous, current, offsetted_second, strategy);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename It, typename Strategy>
|
||||
bool is_convex(Point& previous, Point& current, It begin, It end, Strategy const& strategy) const
|
||||
{
|
||||
for (It it = begin; it != end; ++it)
|
||||
{
|
||||
if (! is_convex(previous, current, *it, strategy))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Strategy>
|
||||
bool is_convex(Point& previous, Point& current, Point const& next, Strategy const& strategy) const
|
||||
{
|
||||
int const side = strategy.side().apply(previous, current, next);
|
||||
if (side == 1)
|
||||
{
|
||||
// Next is on the left side of clockwise ring: piece is not convex
|
||||
return false;
|
||||
}
|
||||
if (! equals::equals_point_point(current, next, strategy))
|
||||
{
|
||||
previous = current;
|
||||
current = next;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <int Direction>
|
||||
inline void step_for_monotonicity(Point const& current, Point const& next)
|
||||
{
|
||||
if (geometry::get<Direction>(current) >= geometry::get<Direction>(next))
|
||||
{
|
||||
m_is_monotonic_increasing = false;
|
||||
}
|
||||
if (geometry::get<Direction>(current) <= geometry::get<Direction>(next))
|
||||
{
|
||||
m_is_monotonic_decreasing = false;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename It>
|
||||
void check_monotonicity(It begin, It end)
|
||||
{
|
||||
m_is_monotonic_increasing = true;
|
||||
m_is_monotonic_decreasing = true;
|
||||
|
||||
if (begin == end || begin + 1 == end)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
It it = begin;
|
||||
for (It previous = it++; it != end; ++previous, ++it)
|
||||
{
|
||||
step_for_monotonicity<0>(*previous, *it);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename It>
|
||||
inline void calculate_radii(Point const& center, It begin, It end)
|
||||
{
|
||||
typedef geometry::model::referring_segment<Point const> segment_type;
|
||||
|
||||
bool first = true;
|
||||
|
||||
// An offsetted point-buffer ring around a point is supposed to be closed,
|
||||
// therefore walking from start to end is fine.
|
||||
It it = begin;
|
||||
for (It previous = it++; it != end; ++previous, ++it)
|
||||
{
|
||||
Point const& p0 = *previous;
|
||||
Point const& p1 = *it;
|
||||
segment_type const s(p0, p1);
|
||||
radius_type const d = geometry::comparable_distance(center, s);
|
||||
|
||||
if (first || d < m_min_comparable_radius)
|
||||
{
|
||||
m_min_comparable_radius = d;
|
||||
}
|
||||
if (first || d > m_max_comparable_radius)
|
||||
{
|
||||
m_max_comparable_radius = d;
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}} // namespace detail::buffer
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_PIECE_BORDER_HPP
|
||||
Vendored
Executable
+300
@@ -0,0 +1,300 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// Copyright (c) 2014 Barend Gehrels, Amsterdam, the Netherlands.
|
||||
|
||||
// This file was modified by Oracle on 2016-2023.
|
||||
// Modifications copyright (c) 2016-2023 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_BUFFER_TURN_IN_ORIGINAL_VISITOR
|
||||
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_ORIGINAL_VISITOR
|
||||
|
||||
|
||||
#include <boost/core/ignore_unused.hpp>
|
||||
#include <boost/range/size.hpp>
|
||||
|
||||
#include <boost/geometry/core/coordinate_type.hpp>
|
||||
#include <boost/geometry/algorithms/detail/buffer/buffer_policies.hpp>
|
||||
#include <boost/geometry/algorithms/detail/disjoint/interface.hpp>
|
||||
#include <boost/geometry/algorithms/expand.hpp>
|
||||
#include <boost/geometry/strategies/agnostic/point_in_poly_winding.hpp>
|
||||
#include <boost/geometry/strategies/buffer.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace buffer
|
||||
{
|
||||
|
||||
|
||||
template <typename Strategy>
|
||||
struct original_get_box
|
||||
{
|
||||
explicit original_get_box(Strategy const& strategy)
|
||||
: m_strategy(strategy)
|
||||
{}
|
||||
|
||||
template <typename Box, typename Original>
|
||||
inline void apply(Box& total, Original const& original) const
|
||||
{
|
||||
assert_coordinate_type_equal(total, original.m_box);
|
||||
geometry::expand(total, original.m_box, m_strategy);
|
||||
}
|
||||
|
||||
Strategy const& m_strategy;
|
||||
};
|
||||
|
||||
template <typename Strategy>
|
||||
struct original_overlaps_box
|
||||
{
|
||||
explicit original_overlaps_box(Strategy const& strategy)
|
||||
: m_strategy(strategy)
|
||||
{}
|
||||
|
||||
template <typename Box, typename Original>
|
||||
inline bool apply(Box const& box, Original const& original) const
|
||||
{
|
||||
assert_coordinate_type_equal(box, original.m_box);
|
||||
return ! detail::disjoint::disjoint_box_box(box, original.m_box,
|
||||
m_strategy);
|
||||
}
|
||||
|
||||
Strategy const& m_strategy;
|
||||
};
|
||||
|
||||
struct include_turn_policy
|
||||
{
|
||||
template <typename Turn>
|
||||
static inline bool apply(Turn const& turn)
|
||||
{
|
||||
return turn.is_turn_traversable;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Strategy>
|
||||
struct turn_in_original_overlaps_box
|
||||
{
|
||||
explicit turn_in_original_overlaps_box(Strategy const& strategy)
|
||||
: m_strategy(strategy)
|
||||
{}
|
||||
|
||||
template <typename Box, typename Turn>
|
||||
inline bool apply(Box const& box, Turn const& turn) const
|
||||
{
|
||||
if (! turn.is_turn_traversable || turn.within_original)
|
||||
{
|
||||
// Skip all points already processed
|
||||
return false;
|
||||
}
|
||||
|
||||
return ! geometry::detail::disjoint::disjoint_point_box(
|
||||
turn.point, box, m_strategy);
|
||||
}
|
||||
|
||||
Strategy const& m_strategy;
|
||||
};
|
||||
|
||||
//! Check if specified is in range of specified iterators
|
||||
//! Return value of strategy (true if we can bail out)
|
||||
template
|
||||
<
|
||||
typename Strategy,
|
||||
typename State,
|
||||
typename Point,
|
||||
typename Iterator
|
||||
>
|
||||
inline bool point_in_range(Strategy& strategy, State& state,
|
||||
Point const& point, Iterator begin, Iterator end)
|
||||
{
|
||||
boost::ignore_unused(strategy);
|
||||
|
||||
Iterator it = begin;
|
||||
for (Iterator previous = it++; it != end; ++previous, ++it)
|
||||
{
|
||||
if (! strategy.apply(point, *previous, *it, state))
|
||||
{
|
||||
// We're probably on the boundary
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template
|
||||
<
|
||||
typename Strategy,
|
||||
typename State,
|
||||
typename Point,
|
||||
typename CoordinateType,
|
||||
typename Iterator
|
||||
>
|
||||
inline bool point_in_section(Strategy& strategy, State& state,
|
||||
Point const& point, CoordinateType const& point_x,
|
||||
Iterator begin, Iterator end,
|
||||
int direction)
|
||||
{
|
||||
if (direction == 0)
|
||||
{
|
||||
// Not a monotonic section, or no change in X-direction
|
||||
return point_in_range(strategy, state, point, begin, end);
|
||||
}
|
||||
|
||||
// We're in a monotonic section in x-direction
|
||||
Iterator it = begin;
|
||||
|
||||
for (Iterator previous = it++; it != end; ++previous, ++it)
|
||||
{
|
||||
// Depending on sections.direction we can quit for this section
|
||||
CoordinateType const previous_x = geometry::get<0>(*previous);
|
||||
|
||||
if (direction == 1 && point_x < previous_x)
|
||||
{
|
||||
// Section goes upwards, x increases, point is is below section
|
||||
return true;
|
||||
}
|
||||
else if (direction == -1 && point_x > previous_x)
|
||||
{
|
||||
// Section goes downwards, x decreases, point is above section
|
||||
return true;
|
||||
}
|
||||
|
||||
if (! strategy.apply(point, *previous, *it, state))
|
||||
{
|
||||
// We're probably on the boundary
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template <typename Point, typename Original, typename PointInGeometryStrategy>
|
||||
inline int point_in_original(Point const& point, Original const& original,
|
||||
PointInGeometryStrategy const& strategy)
|
||||
{
|
||||
typename PointInGeometryStrategy::state_type state;
|
||||
|
||||
if (boost::size(original.m_sections) == 0
|
||||
|| boost::size(original.m_ring) - boost::size(original.m_sections) < 16)
|
||||
{
|
||||
// There are no sections, or it does not profit to walk over sections
|
||||
// instead of over points. Boundary of 16 is arbitrary but can influence
|
||||
// performance
|
||||
point_in_range(strategy, state, point,
|
||||
original.m_ring.begin(), original.m_ring.end());
|
||||
return strategy.result(state);
|
||||
}
|
||||
|
||||
auto const point_x = geometry::get<0>(point);
|
||||
|
||||
// Walk through all monotonic sections of this original
|
||||
for (auto const& section : original.m_sections)
|
||||
{
|
||||
if (! section.duplicate
|
||||
&& section.begin_index < section.end_index
|
||||
&& point_x >= geometry::get<min_corner, 0>(section.bounding_box)
|
||||
&& point_x <= geometry::get<max_corner, 0>(section.bounding_box))
|
||||
{
|
||||
// x-coordinate of point overlaps with section
|
||||
if (! point_in_section(strategy, state, point, point_x,
|
||||
boost::begin(original.m_ring) + section.begin_index,
|
||||
boost::begin(original.m_ring) + section.end_index + 1,
|
||||
section.directions[0]))
|
||||
{
|
||||
// We're probably on the boundary
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return strategy.result(state);
|
||||
}
|
||||
|
||||
|
||||
template <typename Turns, typename Strategy>
|
||||
class turn_in_original_visitor
|
||||
{
|
||||
public:
|
||||
turn_in_original_visitor(Turns& turns, Strategy const& strategy)
|
||||
: m_mutable_turns(turns)
|
||||
, m_strategy(strategy)
|
||||
{}
|
||||
|
||||
template <typename Turn, typename Original>
|
||||
inline bool apply(Turn const& turn, Original const& original)
|
||||
{
|
||||
if (boost::empty(original.m_ring))
|
||||
{
|
||||
// Skip empty rings
|
||||
return true;
|
||||
}
|
||||
|
||||
if (! turn.is_turn_traversable || turn.within_original)
|
||||
{
|
||||
// Skip all points already processed
|
||||
return true;
|
||||
}
|
||||
|
||||
if (geometry::disjoint(turn.point, original.m_box, m_strategy))
|
||||
{
|
||||
// Skip all disjoint
|
||||
return true;
|
||||
}
|
||||
|
||||
int const code = point_in_original(turn.point, original,
|
||||
m_strategy.relate(turn.point, original.m_ring));
|
||||
|
||||
if (code == -1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Turn& mutable_turn = m_mutable_turns[turn.turn_index];
|
||||
|
||||
if (code == 0)
|
||||
{
|
||||
// On border of original: always discard
|
||||
mutable_turn.is_turn_traversable = false;
|
||||
}
|
||||
|
||||
// Point is inside an original ring
|
||||
if (original.m_is_interior)
|
||||
{
|
||||
mutable_turn.count_in_original--;
|
||||
}
|
||||
else if (original.m_has_interiors)
|
||||
{
|
||||
mutable_turn.count_in_original++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// It is an exterior ring and there are no interior rings.
|
||||
// Then we are completely ready with this turn
|
||||
mutable_turn.within_original = true;
|
||||
mutable_turn.count_in_original = 1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private :
|
||||
Turns& m_mutable_turns;
|
||||
Strategy const& m_strategy;
|
||||
};
|
||||
|
||||
|
||||
}} // namespace detail::buffer
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_ORIGINAL_VISITOR
|
||||
Vendored
Executable
+194
@@ -0,0 +1,194 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// Copyright (c) 2012-2020 Barend Gehrels, Amsterdam, the Netherlands.
|
||||
// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
|
||||
|
||||
// This file was modified by Oracle on 2016-2022.
|
||||
// Modifications copyright (c) 2016-2022 Oracle and/or its affiliates.
|
||||
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
|
||||
|
||||
// Use, modification and distribution is subject to the Boost Software License,
|
||||
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_PIECE_VISITOR_HPP
|
||||
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_PIECE_VISITOR_HPP
|
||||
|
||||
#include <boost/geometry/core/assert.hpp>
|
||||
#include <boost/geometry/core/config.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/comparable_distance.hpp>
|
||||
#include <boost/geometry/algorithms/covered_by.hpp>
|
||||
#include <boost/geometry/algorithms/detail/disjoint/point_box.hpp>
|
||||
#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
|
||||
#include <boost/geometry/algorithms/detail/dummy_geometries.hpp>
|
||||
#include <boost/geometry/algorithms/detail/buffer/buffer_policies.hpp>
|
||||
#include <boost/geometry/geometries/box.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
|
||||
namespace detail { namespace buffer
|
||||
{
|
||||
|
||||
template
|
||||
<
|
||||
typename CsTag,
|
||||
typename Turns,
|
||||
typename Pieces,
|
||||
typename DistanceStrategy,
|
||||
typename UmbrellaStrategy
|
||||
|
||||
>
|
||||
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
|
||||
DistanceStrategy const& m_distance_strategy; // to check if point is on original or one_sided
|
||||
UmbrellaStrategy const& m_umbrella_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;
|
||||
}
|
||||
|
||||
template <typename NumericType>
|
||||
inline bool is_one_sided(NumericType const& left, NumericType const& right) const
|
||||
{
|
||||
static NumericType const zero = 0;
|
||||
return geometry::math::equals(left, zero)
|
||||
|| geometry::math::equals(right, zero);
|
||||
}
|
||||
|
||||
template <typename Point>
|
||||
inline bool has_zero_distance_at(Point const& point) const
|
||||
{
|
||||
return is_one_sided(m_distance_strategy.apply(point, point,
|
||||
strategy::buffer::buffer_side_left),
|
||||
m_distance_strategy.apply(point, point,
|
||||
strategy::buffer::buffer_side_right));
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
inline turn_in_piece_visitor(Turns& turns, Pieces const& pieces,
|
||||
DistanceStrategy const& distance_strategy,
|
||||
UmbrellaStrategy const& umbrella_strategy)
|
||||
: m_turns(turns)
|
||||
, m_pieces(pieces)
|
||||
, m_distance_strategy(distance_strategy)
|
||||
, m_umbrella_strategy(umbrella_strategy)
|
||||
{}
|
||||
|
||||
template <typename Turn, typename Piece>
|
||||
inline bool apply(Turn const& turn, Piece const& piece)
|
||||
{
|
||||
if (! turn.is_turn_traversable)
|
||||
{
|
||||
// Already handled
|
||||
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 true;
|
||||
}
|
||||
|
||||
if (skip(turn.operations[0], piece) || skip(turn.operations[1], piece))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return apply(turn, piece, piece.m_piece_border);
|
||||
}
|
||||
|
||||
template <typename Turn, typename Piece, typename Border>
|
||||
inline bool apply(Turn const& turn, Piece const& piece, Border const& border)
|
||||
{
|
||||
if (! geometry::covered_by(turn.point, border.m_envelope, m_umbrella_strategy))
|
||||
{
|
||||
// Easy check: if turn is not in the (expanded) envelope
|
||||
return true;
|
||||
}
|
||||
|
||||
if (piece.type == geometry::strategy::buffer::buffered_empty_side)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (piece.type == geometry::strategy::buffer::buffered_point)
|
||||
{
|
||||
// Optimization for a buffer around points: if distance from center
|
||||
// is not between min/max radius, it is either inside or outside,
|
||||
// and more expensive checks are not necessary.
|
||||
auto const d = geometry::comparable_distance(piece.m_center, turn.point,
|
||||
m_umbrella_strategy);
|
||||
|
||||
if (d < border.m_min_comparable_radius)
|
||||
{
|
||||
Turn& mutable_turn = m_turns[turn.turn_index];
|
||||
mutable_turn.is_turn_traversable = false;
|
||||
return true;
|
||||
}
|
||||
if (d > border.m_max_comparable_radius)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if buffer is one-sided (at this point), because then a point
|
||||
// on the original border is not considered as within.
|
||||
bool const one_sided = has_zero_distance_at(turn.point);
|
||||
|
||||
typename Border::state_type state;
|
||||
if (! border.point_on_piece(turn.point, one_sided,
|
||||
turn.is_linear_end_point, state))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (state.is_inside() && ! state.is_on_boundary())
|
||||
{
|
||||
Turn& mutable_turn = m_turns[turn.turn_index];
|
||||
mutable_turn.is_turn_traversable = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}} // namespace detail::buffer
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_PIECE_VISITOR_HPP
|
||||
Reference in New Issue
Block a user