add boost on mac
This commit is contained in:
62
macx64/include/boost/geometry/algorithms/detail/buffer/buffer_box.hpp
Executable file
62
macx64/include/boost/geometry/algorithms/detail/buffer/buffer_box.hpp
Executable file
@@ -0,0 +1,62 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// Copyright (c) 2018-2019 Barend Gehrels, Amsterdam, the Netherlands.
|
||||
|
||||
// Use, modification and distribution is subject to the Boost Software License,
|
||||
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_BOX_HPP
|
||||
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_BOX_HPP
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include <boost/geometry/core/coordinate_dimension.hpp>
|
||||
#include <boost/geometry/core/coordinate_type.hpp>
|
||||
#include <boost/geometry/core/access.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace buffer
|
||||
{
|
||||
|
||||
template <typename BoxIn, typename BoxOut, typename T, std::size_t C, std::size_t D, std::size_t N>
|
||||
struct box_loop
|
||||
{
|
||||
typedef typename coordinate_type<BoxOut>::type coordinate_type;
|
||||
|
||||
static inline void apply(BoxIn const& box_in, T const& distance, BoxOut& box_out)
|
||||
{
|
||||
coordinate_type d = distance;
|
||||
set<C, D>(box_out, get<C, D>(box_in) + d);
|
||||
box_loop<BoxIn, BoxOut, T, C, D + 1, N>::apply(box_in, distance, box_out);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename BoxIn, typename BoxOut, typename T, std::size_t C, std::size_t N>
|
||||
struct box_loop<BoxIn, BoxOut, T, C, N, N>
|
||||
{
|
||||
static inline void apply(BoxIn const&, T const&, BoxOut&) {}
|
||||
};
|
||||
|
||||
// Extends a box with the same amount in all directions
|
||||
template<typename BoxIn, typename BoxOut, typename T>
|
||||
inline void buffer_box(BoxIn const& box_in, T const& distance, BoxOut& box_out)
|
||||
{
|
||||
assert_dimension_equal<BoxIn, BoxOut>();
|
||||
|
||||
static const std::size_t N = dimension<BoxIn>::value;
|
||||
|
||||
box_loop<BoxIn, BoxOut, T, min_corner, 0, N>::apply(box_in, -distance, box_out);
|
||||
box_loop<BoxIn, BoxOut, T, max_corner, 0, N>::apply(box_in, distance, box_out);
|
||||
}
|
||||
|
||||
}} // namespace detail::buffer
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_BOX_HPP
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,236 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
|
||||
|
||||
// This file was modified by Oracle on 2017, 2018.
|
||||
// Modifications copyright (c) 2017-2018, Oracle and/or its affiliates.
|
||||
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
|
||||
|
||||
// Use, modification and distribution is subject to the Boost Software License,
|
||||
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_POLICIES_HPP
|
||||
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_POLICIES_HPP
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include <boost/range.hpp>
|
||||
|
||||
#include <boost/geometry/core/coordinate_type.hpp>
|
||||
#include <boost/geometry/core/point_type.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/covered_by.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
|
||||
|
||||
#include <boost/geometry/strategies/buffer.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace buffer
|
||||
{
|
||||
|
||||
|
||||
enum intersection_location_type
|
||||
{
|
||||
location_ok, inside_buffer, location_discard
|
||||
};
|
||||
|
||||
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 for buffer including type of location, is_opposite, and helper variables
|
||||
template <typename Point, typename RobustPoint, typename SegmentRatio>
|
||||
struct buffer_turn_info
|
||||
: public detail::overlay::turn_info
|
||||
<
|
||||
Point,
|
||||
SegmentRatio,
|
||||
buffer_turn_operation<Point, SegmentRatio>
|
||||
>
|
||||
{
|
||||
typedef Point point_type;
|
||||
typedef RobustPoint robust_point_type;
|
||||
|
||||
std::size_t turn_index; // TODO: this might go if partition can operate on non-const input
|
||||
|
||||
RobustPoint robust_point;
|
||||
#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS)
|
||||
// Will (most probably) be removed later
|
||||
RobustPoint mapped_robust_point; // alas... we still need to adapt our points, offsetting them 1 integer to be co-located with neighbours
|
||||
#endif
|
||||
|
||||
|
||||
inline RobustPoint const& get_robust_point() const
|
||||
{
|
||||
#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS)
|
||||
return mapped_robust_point;
|
||||
#endif
|
||||
return robust_point;
|
||||
}
|
||||
|
||||
intersection_location_type location;
|
||||
|
||||
robust_point_type rob_pi, rob_pj, rob_qi, rob_qj;
|
||||
|
||||
std::size_t count_within;
|
||||
|
||||
bool within_original;
|
||||
std::size_t count_on_original_boundary;
|
||||
signed_size_type count_in_original; // increased by +1 for in ext.ring, -1 for int.ring
|
||||
|
||||
std::size_t count_on_offsetted;
|
||||
std::size_t count_on_helper;
|
||||
std::size_t count_within_near_offsetted;
|
||||
|
||||
bool remove_on_multi;
|
||||
|
||||
// Obsolete:
|
||||
std::size_t count_on_occupied;
|
||||
std::size_t count_on_multi;
|
||||
|
||||
inline buffer_turn_info()
|
||||
: turn_index(0)
|
||||
, location(location_ok)
|
||||
, count_within(0)
|
||||
, within_original(false)
|
||||
, count_on_original_boundary(0)
|
||||
, count_in_original(0)
|
||||
, count_on_offsetted(0)
|
||||
, count_on_helper(0)
|
||||
, count_within_near_offsetted(0)
|
||||
, remove_on_multi(false)
|
||||
, count_on_occupied(0)
|
||||
, count_on_multi(0)
|
||||
{}
|
||||
};
|
||||
|
||||
struct buffer_operation_less
|
||||
{
|
||||
template <typename Turn>
|
||||
inline bool operator()(Turn const& left, Turn const& right) const
|
||||
{
|
||||
segment_identifier const& sl = left.seg_id;
|
||||
segment_identifier const& sr = right.seg_id;
|
||||
|
||||
// Sort them descending
|
||||
return sl == sr
|
||||
? left.fraction < right.fraction
|
||||
: sl < sr;
|
||||
}
|
||||
};
|
||||
|
||||
}} // namespace detail::buffer
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_POLICIES_HPP
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,282 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// Copyright (c) 2012-2015 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_BUFFERED_RING
|
||||
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_RING
|
||||
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include <boost/range.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 dispatch
|
||||
{
|
||||
template <typename Geometry, bool IsConst>
|
||||
struct check<Geometry, detail::buffer::buffered_ring_collection_tag, IsConst>
|
||||
{
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,337 @@
|
||||
// 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, 2018.
|
||||
// Modifications copyright (c) 2017-2018 Oracle and/or its affiliates.
|
||||
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
|
||||
|
||||
// Use, modification and distribution is subject to the Boost Software License,
|
||||
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_GET_PIECE_TURNS_HPP
|
||||
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_GET_PIECE_TURNS_HPP
|
||||
|
||||
#include <boost/core/ignore_unused.hpp>
|
||||
#include <boost/range.hpp>
|
||||
|
||||
#include <boost/geometry/core/assert.hpp>
|
||||
#include <boost/geometry/algorithms/equals.hpp>
|
||||
#include <boost/geometry/algorithms/expand.hpp>
|
||||
#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
|
||||
#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 IntersectionStrategy,
|
||||
typename RobustPolicy
|
||||
>
|
||||
class piece_turn_visitor
|
||||
{
|
||||
Pieces const& m_pieces;
|
||||
Rings const& m_rings;
|
||||
Turns& m_turns;
|
||||
IntersectionStrategy const& m_intersection_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;
|
||||
typedef typename boost::range_iterator<ring_type const>::type iterator;
|
||||
|
||||
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];
|
||||
iterator it1_first = boost::begin(ring1) + sec1_first_index;
|
||||
iterator it1_beyond = boost::begin(ring1) + sec1_last_index + 1;
|
||||
|
||||
ring_type const& ring2 = m_rings[piece2.first_seg_id.multi_index];
|
||||
iterator it2_first = boost::begin(ring2) + sec2_first_index;
|
||||
iterator 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
|
||||
|
||||
iterator it1 = it1_first;
|
||||
for (iterator 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
|
||||
geometry::recalculate(the_model.rob_pi, *prev1, m_robust_policy);
|
||||
geometry::recalculate(the_model.rob_pj, *it1, m_robust_policy);
|
||||
|
||||
unique_sub_range_from_piece<ring_type> unique_sub_range1(ring1, prev1, it1);
|
||||
|
||||
iterator it2 = it2_first;
|
||||
for (iterator prev2 = it2++;
|
||||
it2 != it2_beyond;
|
||||
prev2 = it2++, the_model.operations[1].seg_id.segment_index++)
|
||||
{
|
||||
unique_sub_range_from_piece<ring_type> unique_sub_range2(ring2, prev2, it2);
|
||||
geometry::recalculate(the_model.rob_qi, *prev2, m_robust_policy);
|
||||
geometry::recalculate(the_model.rob_qj, *it2, m_robust_policy);
|
||||
|
||||
// TODO: internally get_turn_info calculates robust points.
|
||||
// But they are already calculated.
|
||||
// We should be able to use them.
|
||||
// this means passing them to this visitor,
|
||||
// and iterating in sync with them...
|
||||
typedef detail::overlay::get_turn_info
|
||||
<
|
||||
detail::overlay::assign_null_policy
|
||||
> turn_policy;
|
||||
|
||||
turn_policy::apply(unique_sub_range1, unique_sub_range2,
|
||||
the_model,
|
||||
m_intersection_strategy,
|
||||
m_robust_policy,
|
||||
std::back_inserter(m_turns));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
piece_turn_visitor(Pieces const& pieces,
|
||||
Rings const& ring_collection,
|
||||
Turns& turns,
|
||||
IntersectionStrategy const& intersection_strategy,
|
||||
RobustPolicy const& robust_policy)
|
||||
: m_pieces(pieces)
|
||||
, m_rings(ring_collection)
|
||||
, m_turns(turns)
|
||||
, m_intersection_strategy(intersection_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_intersection_strategy.get_disjoint_box_box_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
|
||||
@@ -0,0 +1,88 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// Copyright (c) 2012-2014 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/arithmetic/determinant.hpp>
|
||||
#include <boost/geometry/util/math.hpp>
|
||||
#include <boost/geometry/strategies/buffer.hpp>
|
||||
#include <boost/geometry/algorithms/detail/buffer/parallel_continue.hpp>
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace buffer
|
||||
{
|
||||
|
||||
|
||||
// TODO: once change this to proper strategy
|
||||
// It is different from current segment intersection because these are not segments but lines
|
||||
// If we have the Line concept, we can create a strategy
|
||||
// Assumes a convex corner
|
||||
struct line_line_intersection
|
||||
{
|
||||
|
||||
template <typename Point>
|
||||
static inline strategy::buffer::join_selector apply(Point const& pi, Point const& pj,
|
||||
Point const& qi, Point const& qj, Point& ip)
|
||||
{
|
||||
// See http://mathworld.wolfram.com/Line-LineIntersection.html
|
||||
typedef typename coordinate_type<Point>::type coordinate_type;
|
||||
|
||||
coordinate_type const denominator
|
||||
= determinant<coordinate_type>(get<0>(pi) - get<0>(pj),
|
||||
get<1>(pi) - get<1>(pj),
|
||||
get<0>(qi) - get<0>(qj),
|
||||
get<1>(qi) - get<1>(qj));
|
||||
|
||||
// Even if the corner was checked before (so it is convex now), that
|
||||
// was done on the original geometry. This function runs on the buffered
|
||||
// geometries, where sides are generated and might be slightly off. In
|
||||
// Floating Point, that slightly might just exceed the limit and we have
|
||||
// to check it again.
|
||||
|
||||
// For round joins, it will not be used at all.
|
||||
// For miter joints, there is a miter limit
|
||||
// If segments are parallel/collinear we must be distinguish two cases:
|
||||
// they continue each other, or they form a spike
|
||||
if (math::equals(denominator, coordinate_type()))
|
||||
{
|
||||
return parallel_continue(get<0>(qj) - get<0>(qi),
|
||||
get<1>(qj) - get<1>(qi),
|
||||
get<0>(pj) - get<0>(pi),
|
||||
get<1>(pj) - get<1>(pi))
|
||||
? strategy::buffer::join_continue
|
||||
: strategy::buffer::join_spike
|
||||
;
|
||||
}
|
||||
|
||||
coordinate_type d1 = determinant<coordinate_type>(get<0>(pi), get<1>(pi), get<0>(pj), get<1>(pj));
|
||||
coordinate_type d2 = determinant<coordinate_type>(get<0>(qi), get<1>(qi), get<0>(qj), get<1>(qj));
|
||||
|
||||
double const multiplier = 1.0 / denominator;
|
||||
|
||||
set<0>(ip, determinant<coordinate_type>(d1, get<0>(pi) - get<0>(pj), d2, get<0>(qi) - get<0>(qj)) * multiplier);
|
||||
set<1>(ip, determinant<coordinate_type>(d1, get<1>(pi) - get<1>(pj), d2, get<1>(qi) - get<1>(qj)) * multiplier);
|
||||
|
||||
return strategy::buffer::join_convex;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}} // namespace detail::buffer
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
|
||||
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_LINE_LINE_INTERSECTION_HPP
|
||||
@@ -0,0 +1,33 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// Copyright (c) 2012-2014 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_PARALLEL_CONTINUE_HPP
|
||||
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_PARALLEL_CONTINUE_HPP
|
||||
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace buffer
|
||||
{
|
||||
|
||||
template <typename T>
|
||||
inline bool parallel_continue(T dx1, T dy1, T dx2, T dy2)
|
||||
{
|
||||
T const dot = dx1 * dx2 + dy1 * dy2;
|
||||
return dot > 0;
|
||||
}
|
||||
|
||||
}} // namespace detail::buffer
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_PARALLEL_CONTINUE_HPP
|
||||
@@ -0,0 +1,281 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// Copyright (c) 2014 Barend Gehrels, Amsterdam, the Netherlands.
|
||||
|
||||
// This file was modified by Oracle on 2016, 2018.
|
||||
// Modifications copyright (c) 2016-2018 Oracle and/or its affiliates.
|
||||
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
|
||||
|
||||
// Use, modification and distribution is subject to the Boost Software License,
|
||||
// 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/geometry/algorithms/detail/buffer/buffer_policies.hpp>
|
||||
#include <boost/geometry/algorithms/expand.hpp>
|
||||
#include <boost/geometry/strategies/agnostic/point_in_poly_winding.hpp>
|
||||
#include <boost/geometry/strategies/buffer.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace buffer
|
||||
{
|
||||
|
||||
struct original_get_box
|
||||
{
|
||||
template <typename Box, typename Original>
|
||||
static inline void apply(Box& total, Original const& original)
|
||||
{
|
||||
geometry::expand(total, original.m_box);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename DisjointBoxBoxStrategy>
|
||||
struct original_ovelaps_box
|
||||
{
|
||||
template <typename Box, typename Original>
|
||||
static inline bool apply(Box const& box, Original const& original)
|
||||
{
|
||||
return ! detail::disjoint::disjoint_box_box(box, original.m_box,
|
||||
DisjointBoxBoxStrategy());
|
||||
}
|
||||
};
|
||||
|
||||
struct include_turn_policy
|
||||
{
|
||||
template <typename Turn>
|
||||
static inline bool apply(Turn const& turn)
|
||||
{
|
||||
return turn.location == location_ok;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename DisjointPointBoxStrategy>
|
||||
struct turn_in_original_ovelaps_box
|
||||
{
|
||||
template <typename Box, typename Turn>
|
||||
static inline bool apply(Box const& box, Turn const& turn)
|
||||
{
|
||||
if (turn.location != location_ok || turn.within_original)
|
||||
{
|
||||
// Skip all points already processed
|
||||
return false;
|
||||
}
|
||||
|
||||
return ! geometry::detail::disjoint::disjoint_point_box(
|
||||
turn.robust_point, box, DisjointPointBoxStrategy());
|
||||
}
|
||||
};
|
||||
|
||||
//! 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>
|
||||
inline int point_in_original(Point const& point, Original const& original)
|
||||
{
|
||||
// The winding strategy is scanning in x direction
|
||||
// therefore it's critical to pass direction calculated
|
||||
// for x dimension below.
|
||||
typedef strategy::within::winding<Point> strategy_type;
|
||||
|
||||
typename strategy_type::state_type state;
|
||||
strategy_type strategy;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
typedef typename Original::sections_type sections_type;
|
||||
typedef typename boost::range_iterator<sections_type const>::type iterator_type;
|
||||
typedef typename boost::range_value<sections_type const>::type section_type;
|
||||
typedef typename geometry::coordinate_type<Point>::type coordinate_type;
|
||||
|
||||
coordinate_type const point_x = geometry::get<0>(point);
|
||||
|
||||
// Walk through all monotonic sections of this original
|
||||
for (iterator_type it = boost::begin(original.m_sections);
|
||||
it != boost::end(original.m_sections);
|
||||
++it)
|
||||
{
|
||||
section_type const& section = *it;
|
||||
|
||||
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>
|
||||
class turn_in_original_visitor
|
||||
{
|
||||
public:
|
||||
turn_in_original_visitor(Turns& turns)
|
||||
: m_mutable_turns(turns)
|
||||
{}
|
||||
|
||||
template <typename Turn, typename Original>
|
||||
inline bool apply(Turn const& turn, Original const& original, bool first = true)
|
||||
{
|
||||
boost::ignore_unused(first);
|
||||
|
||||
if (turn.location != location_ok || turn.within_original)
|
||||
{
|
||||
// Skip all points already processed
|
||||
return true;
|
||||
}
|
||||
|
||||
if (geometry::disjoint(turn.robust_point, original.m_box))
|
||||
{
|
||||
// Skip all disjoint
|
||||
return true;
|
||||
}
|
||||
|
||||
int const code = point_in_original(turn.robust_point, original);
|
||||
|
||||
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.location = location_discard;
|
||||
}
|
||||
|
||||
// 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;
|
||||
};
|
||||
|
||||
|
||||
}} // namespace detail::buffer
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_ORIGINAL_VISITOR
|
||||
@@ -0,0 +1,931 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
|
||||
// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
|
||||
|
||||
// This file was modified by Oracle on 2016, 2018.
|
||||
// Modifications copyright (c) 2016-2018 Oracle and/or its affiliates.
|
||||
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
|
||||
|
||||
// Use, modification and distribution is subject to the Boost Software License,
|
||||
// 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
|
||||
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_PIECE_VISITOR
|
||||
|
||||
|
||||
#include <boost/core/ignore_unused.hpp>
|
||||
|
||||
#include <boost/range.hpp>
|
||||
|
||||
#include <boost/geometry/core/assert.hpp>
|
||||
#include <boost/geometry/core/config.hpp>
|
||||
|
||||
#include <boost/geometry/arithmetic/dot_product.hpp>
|
||||
#include <boost/geometry/algorithms/assign.hpp>
|
||||
#include <boost/geometry/algorithms/comparable_distance.hpp>
|
||||
#include <boost/geometry/algorithms/equals.hpp>
|
||||
#include <boost/geometry/algorithms/expand.hpp>
|
||||
#include <boost/geometry/algorithms/detail/disjoint/point_box.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/policies/compare.hpp>
|
||||
#include <boost/geometry/strategies/buffer.hpp>
|
||||
#include <boost/geometry/algorithms/detail/buffer/buffer_policies.hpp>
|
||||
|
||||
#include <boost/geometry/strategies/cartesian/side_of_intersection.hpp>
|
||||
#include <boost/geometry/strategies/agnostic/point_in_poly_winding.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace buffer
|
||||
{
|
||||
|
||||
struct piece_get_box
|
||||
{
|
||||
template <typename Box, typename Piece>
|
||||
static inline void apply(Box& total, Piece const& piece)
|
||||
{
|
||||
geometry::expand(total, piece.robust_envelope);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename DisjointBoxBoxStrategy>
|
||||
struct piece_ovelaps_box
|
||||
{
|
||||
template <typename Box, typename Piece>
|
||||
static inline bool apply(Box const& box, Piece const& piece)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
return ! geometry::detail::disjoint::disjoint_box_box(box, piece.robust_envelope,
|
||||
DisjointBoxBoxStrategy());
|
||||
}
|
||||
};
|
||||
|
||||
struct turn_get_box
|
||||
{
|
||||
template <typename Box, typename Turn>
|
||||
static inline void apply(Box& total, Turn const& turn)
|
||||
{
|
||||
geometry::expand(total, turn.robust_point);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename DisjointPointBoxStrategy>
|
||||
struct turn_ovelaps_box
|
||||
{
|
||||
template <typename Box, typename Turn>
|
||||
static inline bool apply(Box const& box, Turn const& turn)
|
||||
{
|
||||
return ! geometry::detail::disjoint::disjoint_point_box(turn.robust_point, box,
|
||||
DisjointPointBoxStrategy());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
enum analyse_result
|
||||
{
|
||||
analyse_unknown,
|
||||
analyse_continue,
|
||||
analyse_disjoint,
|
||||
analyse_within,
|
||||
analyse_on_original_boundary,
|
||||
analyse_on_offsetted,
|
||||
analyse_near_offsetted
|
||||
};
|
||||
|
||||
template <typename Point>
|
||||
inline bool in_box(Point const& previous,
|
||||
Point const& current, Point const& point)
|
||||
{
|
||||
// Get its box (TODO: this can be prepared-on-demand later)
|
||||
typedef geometry::model::box<Point> box_type;
|
||||
box_type box;
|
||||
geometry::assign_inverse(box);
|
||||
geometry::expand(box, previous);
|
||||
geometry::expand(box, current);
|
||||
|
||||
return geometry::covered_by(point, box);
|
||||
}
|
||||
|
||||
// meta-programming-structure defining if to use side-of-intersection
|
||||
// (only for cartesian / only necessary with rescaling)
|
||||
template <typename Tag>
|
||||
struct use_side_of_intersection {};
|
||||
|
||||
#if defined(BOOST_GEOMETRY_USE_RESCALING)
|
||||
// With rescaling, let Cartesian use side-of-intersection
|
||||
template <>
|
||||
struct use_side_of_intersection<cartesian_tag> { static bool const value = true; };
|
||||
#else
|
||||
template <>
|
||||
struct use_side_of_intersection<cartesian_tag> { static bool const value = false; };
|
||||
#endif
|
||||
|
||||
template <>
|
||||
struct use_side_of_intersection<spherical_tag> { static bool const value = false; };
|
||||
|
||||
template <>
|
||||
struct use_side_of_intersection<geographic_tag> { static bool const value = false; };
|
||||
|
||||
|
||||
template <bool UseSideOfIntersection>
|
||||
struct check_segment {};
|
||||
|
||||
// Implementation using side-of-intersection
|
||||
template <>
|
||||
struct check_segment<true>
|
||||
{
|
||||
template <typename Point, typename Turn>
|
||||
static inline analyse_result apply(Point const& previous,
|
||||
Point const& current, Turn const& turn,
|
||||
bool from_monotonic)
|
||||
{
|
||||
typedef geometry::model::referring_segment<Point const> segment_type;
|
||||
segment_type const p(turn.rob_pi, turn.rob_pj);
|
||||
segment_type const q(turn.rob_qi, turn.rob_qj);
|
||||
segment_type const r(previous, current);
|
||||
int const side = strategy::side::side_of_intersection::apply(p, q, r,
|
||||
turn.robust_point);
|
||||
|
||||
if (side == 0)
|
||||
{
|
||||
return analyse_on_offsetted;
|
||||
}
|
||||
if (side == -1 && from_monotonic)
|
||||
{
|
||||
return analyse_within;
|
||||
}
|
||||
if (side == 1 && from_monotonic)
|
||||
{
|
||||
return analyse_disjoint;
|
||||
}
|
||||
return analyse_continue;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct check_segment<false>
|
||||
{
|
||||
template <typename Point, typename Turn>
|
||||
static inline analyse_result apply(Point const& previous,
|
||||
Point const& current, Turn const& turn,
|
||||
bool from_monotonic)
|
||||
{
|
||||
typedef typename strategy::side::services::default_strategy
|
||||
<
|
||||
typename cs_tag<Point>::type
|
||||
>::type side_strategy;
|
||||
|
||||
int const side = side_strategy::apply(previous, current, turn.robust_point);
|
||||
|
||||
if (side == 0)
|
||||
{
|
||||
// Collinear, only on segment if it is covered by its bbox
|
||||
if (in_box(previous, current, turn.robust_point))
|
||||
{
|
||||
return analyse_on_offsetted;
|
||||
}
|
||||
}
|
||||
else if (side == -1)
|
||||
{
|
||||
// It is in the triangle right-of the segment where the
|
||||
// segment is the hypothenusa. Check if it is close
|
||||
// (within rounding-area)
|
||||
if (in_box(previous, current, turn.robust_point))
|
||||
{
|
||||
return analyse_near_offsetted;
|
||||
}
|
||||
else if (from_monotonic)
|
||||
{
|
||||
return analyse_within;
|
||||
}
|
||||
}
|
||||
else if (from_monotonic)
|
||||
{
|
||||
// Left of segment
|
||||
return analyse_disjoint;
|
||||
}
|
||||
|
||||
// Not monotonic, on left or right side: continue analysing
|
||||
return analyse_continue;
|
||||
}
|
||||
};
|
||||
|
||||
template <bool UseSideOfIntersection>
|
||||
class analyse_turn_wrt_point_piece {};
|
||||
|
||||
template <>
|
||||
class analyse_turn_wrt_point_piece<true>
|
||||
{
|
||||
public :
|
||||
template <typename Turn, typename Piece>
|
||||
static inline analyse_result apply(Turn const& turn, Piece const& piece)
|
||||
{
|
||||
typedef typename Piece::section_type section_type;
|
||||
typedef typename Turn::robust_point_type point_type;
|
||||
typedef typename geometry::coordinate_type<point_type>::type coordinate_type;
|
||||
|
||||
typedef geometry::model::referring_segment<point_type const> segment_type;
|
||||
segment_type const p(turn.rob_pi, turn.rob_pj);
|
||||
segment_type const q(turn.rob_qi, turn.rob_qj);
|
||||
|
||||
BOOST_GEOMETRY_ASSERT(! piece.sections.empty());
|
||||
|
||||
coordinate_type const point_x = geometry::get<0>(turn.robust_point);
|
||||
|
||||
for (std::size_t s = 0; s < piece.sections.size(); s++)
|
||||
{
|
||||
section_type const& section = piece.sections[s];
|
||||
// If point within horizontal range of monotonic section:
|
||||
if (! section.duplicate
|
||||
&& section.begin_index < section.end_index
|
||||
&& point_x >= geometry::get<min_corner, 0>(section.bounding_box) - 1
|
||||
&& point_x <= geometry::get<max_corner, 0>(section.bounding_box) + 1)
|
||||
{
|
||||
for (signed_size_type i = section.begin_index + 1; i <= section.end_index; i++)
|
||||
{
|
||||
point_type const& previous = piece.robust_ring[i - 1];
|
||||
point_type const& current = piece.robust_ring[i];
|
||||
|
||||
|
||||
// First check if it is in range - if it is not, the
|
||||
// expensive side_of_intersection does not need to be
|
||||
// applied
|
||||
coordinate_type x1 = geometry::get<0>(previous);
|
||||
coordinate_type x2 = geometry::get<0>(current);
|
||||
|
||||
if (x1 > x2)
|
||||
{
|
||||
std::swap(x1, x2);
|
||||
}
|
||||
|
||||
if (point_x >= x1 - 1 && point_x <= x2 + 1)
|
||||
{
|
||||
segment_type const r(previous, current);
|
||||
int const side = strategy::side::side_of_intersection::apply(p, q, r,
|
||||
turn.robust_point);
|
||||
|
||||
// Sections are monotonic in x-dimension
|
||||
if (side == 1)
|
||||
{
|
||||
// Left on segment
|
||||
return analyse_disjoint;
|
||||
}
|
||||
else if (side == 0)
|
||||
{
|
||||
// Collinear - TODO: check if really on segment
|
||||
return analyse_on_offsetted;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// It is nowhere outside, and not on segment, so it is within
|
||||
return analyse_within;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <>
|
||||
class analyse_turn_wrt_point_piece<false>
|
||||
{
|
||||
public :
|
||||
template <typename Turn, typename Piece>
|
||||
static inline analyse_result apply(Turn const& turn, Piece const& piece)
|
||||
{
|
||||
typedef typename Piece::section_type section_type;
|
||||
typedef typename Turn::robust_point_type point_type;
|
||||
typedef typename geometry::coordinate_type<point_type>::type coordinate_type;
|
||||
|
||||
typedef strategy::within::winding<point_type> strategy_type;
|
||||
|
||||
typename strategy_type::state_type state;
|
||||
strategy_type strategy;
|
||||
|
||||
BOOST_GEOMETRY_ASSERT(! piece.sections.empty());
|
||||
|
||||
coordinate_type const point_x = geometry::get<0>(turn.robust_point);
|
||||
|
||||
for (std::size_t s = 0; s < piece.sections.size(); s++)
|
||||
{
|
||||
section_type const& section = piece.sections[s];
|
||||
// If point within horizontal range of monotonic section:
|
||||
if (! section.duplicate
|
||||
&& section.begin_index < section.end_index
|
||||
&& point_x >= geometry::get<min_corner, 0>(section.bounding_box) - 1
|
||||
&& point_x <= geometry::get<max_corner, 0>(section.bounding_box) + 1)
|
||||
{
|
||||
for (signed_size_type i = section.begin_index + 1; i <= section.end_index; i++)
|
||||
{
|
||||
point_type const& previous = piece.robust_ring[i - 1];
|
||||
point_type const& current = piece.robust_ring[i];
|
||||
|
||||
analyse_result code = check_segment<false>::apply(previous, current, turn, false);
|
||||
if (code != analyse_continue)
|
||||
{
|
||||
return code;
|
||||
}
|
||||
|
||||
// Get the state (to determine it is within), we don't have
|
||||
// to cover the on-segment case (covered above)
|
||||
strategy.apply(turn.robust_point, previous, current, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int const code = strategy.result(state);
|
||||
if (code == 1)
|
||||
{
|
||||
return analyse_within;
|
||||
}
|
||||
else if (code == -1)
|
||||
{
|
||||
return analyse_disjoint;
|
||||
}
|
||||
|
||||
// Should normally not occur - on-segment is covered
|
||||
return analyse_unknown;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <bool UseSideOfIntersection>
|
||||
struct check_helper_segment {};
|
||||
|
||||
template <>
|
||||
struct check_helper_segment<true>
|
||||
{
|
||||
template <typename Point, typename Turn>
|
||||
static inline analyse_result apply(Point const& s1,
|
||||
Point const& s2, Turn const& turn,
|
||||
bool is_original,
|
||||
Point const& offsetted)
|
||||
{
|
||||
boost::ignore_unused(offsetted);
|
||||
boost::ignore_unused(is_original);
|
||||
typedef geometry::model::referring_segment<Point const> segment_type;
|
||||
segment_type const p(turn.rob_pi, turn.rob_pj);
|
||||
segment_type const q(turn.rob_qi, turn.rob_qj);
|
||||
segment_type const r(s1, s2);
|
||||
int const side = strategy::side::side_of_intersection::apply(p, q, r,
|
||||
turn.robust_point);
|
||||
|
||||
if (side == 1)
|
||||
{
|
||||
// left of segment
|
||||
return analyse_disjoint;
|
||||
}
|
||||
else if (side == 0)
|
||||
{
|
||||
// If is collinear, either on segment or before/after
|
||||
typedef geometry::model::box<Point> box_type;
|
||||
|
||||
box_type box;
|
||||
geometry::assign_inverse(box);
|
||||
geometry::expand(box, s1);
|
||||
geometry::expand(box, s2);
|
||||
|
||||
if (geometry::covered_by(turn.robust_point, box))
|
||||
{
|
||||
// Points on helper-segments (and not on its corners)
|
||||
// are considered as within
|
||||
return analyse_within;
|
||||
}
|
||||
|
||||
// It is collinear but not on the segment. Because these
|
||||
// segments are convex, it is outside
|
||||
// Unless the offsetted ring is collinear or concave w.r.t.
|
||||
// helper-segment but that scenario is not yet supported
|
||||
return analyse_disjoint;
|
||||
}
|
||||
|
||||
// right of segment
|
||||
return analyse_continue;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <>
|
||||
struct check_helper_segment<false>
|
||||
{
|
||||
template <typename Point, typename Turn>
|
||||
static inline analyse_result apply(Point const& s1,
|
||||
Point const& s2, Turn const& turn,
|
||||
bool is_original,
|
||||
Point const& offsetted)
|
||||
{
|
||||
boost::ignore_unused(offsetted);
|
||||
typedef typename strategy::side::services::default_strategy
|
||||
<
|
||||
typename cs_tag<Point>::type
|
||||
>::type side_strategy;
|
||||
|
||||
switch(side_strategy::apply(s1, s2, turn.robust_point))
|
||||
{
|
||||
case 1 :
|
||||
return analyse_disjoint; // left of segment
|
||||
case 0 :
|
||||
{
|
||||
// If is collinear, either on segment or before/after
|
||||
typedef geometry::model::box<Point> box_type;
|
||||
|
||||
box_type box;
|
||||
geometry::assign_inverse(box);
|
||||
geometry::expand(box, s1);
|
||||
geometry::expand(box, s2);
|
||||
|
||||
if (geometry::covered_by(turn.robust_point, box))
|
||||
{
|
||||
// It is on the segment
|
||||
if (! is_original
|
||||
&& geometry::comparable_distance(turn.robust_point, offsetted) <= 1)
|
||||
{
|
||||
// It is close to the offsetted-boundary, take
|
||||
// any rounding-issues into account
|
||||
return analyse_near_offsetted;
|
||||
}
|
||||
|
||||
// Points on helper-segments are considered as within
|
||||
// Points on original boundary are processed differently
|
||||
return is_original
|
||||
? analyse_on_original_boundary
|
||||
: analyse_within;
|
||||
}
|
||||
|
||||
// It is collinear but not on the segment. Because these
|
||||
// segments are convex, it is outside
|
||||
// Unless the offsetted ring is collinear or concave w.r.t.
|
||||
// helper-segment but that scenario is not yet supported
|
||||
return analyse_disjoint;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// right of segment
|
||||
return analyse_continue;
|
||||
}
|
||||
};
|
||||
|
||||
template <bool UseSideOfIntersection>
|
||||
class analyse_turn_wrt_piece
|
||||
{
|
||||
template <typename Turn, typename Piece>
|
||||
static inline analyse_result check_helper_segments(Turn const& turn, Piece const& piece)
|
||||
{
|
||||
typedef typename Turn::robust_point_type point_type;
|
||||
geometry::equal_to<point_type> comparator;
|
||||
|
||||
point_type points[4];
|
||||
|
||||
signed_size_type helper_count = static_cast<signed_size_type>(piece.robust_ring.size())
|
||||
- piece.offsetted_count;
|
||||
if (helper_count == 4)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
points[i] = piece.robust_ring[piece.offsetted_count + i];
|
||||
}
|
||||
|
||||
// 3--offsetted outline--0
|
||||
// | |
|
||||
// left | | right
|
||||
// | |
|
||||
// 2===>==original===>===1
|
||||
|
||||
}
|
||||
else if (helper_count == 3)
|
||||
{
|
||||
// Triangular piece, assign points but assign second twice
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
int index = i < 2 ? i : i - 1;
|
||||
points[i] = piece.robust_ring[piece.offsetted_count + index];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Some pieces (e.g. around points) do not have helper segments.
|
||||
// Others should have 3 (join) or 4 (side)
|
||||
return analyse_continue;
|
||||
}
|
||||
|
||||
// First check point-equality
|
||||
point_type const& point = turn.robust_point;
|
||||
if (comparator(point, points[0]) || comparator(point, points[3]))
|
||||
{
|
||||
return analyse_on_offsetted;
|
||||
}
|
||||
if (comparator(point, points[1]))
|
||||
{
|
||||
// On original, right corner
|
||||
return piece.is_flat_end ? analyse_continue : analyse_on_original_boundary;
|
||||
}
|
||||
if (comparator(point, points[2]))
|
||||
{
|
||||
// On original, left corner
|
||||
return piece.is_flat_start ? analyse_continue : analyse_on_original_boundary;
|
||||
}
|
||||
|
||||
// Right side of the piece
|
||||
analyse_result result
|
||||
= check_helper_segment<UseSideOfIntersection>::apply(points[0], points[1], turn,
|
||||
false, points[0]);
|
||||
if (result != analyse_continue)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
// Left side of the piece
|
||||
result = check_helper_segment<UseSideOfIntersection>::apply(points[2], points[3], turn,
|
||||
false, points[3]);
|
||||
if (result != analyse_continue)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (! comparator(points[1], points[2]))
|
||||
{
|
||||
// Side of the piece at side of original geometry
|
||||
result = check_helper_segment<UseSideOfIntersection>::apply(points[1], points[2], turn,
|
||||
true, point);
|
||||
if (result != analyse_continue)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// We are within the \/ or |_| shaped piece, where the top is the
|
||||
// offsetted ring.
|
||||
if (! geometry::covered_by(point, piece.robust_offsetted_envelope))
|
||||
{
|
||||
// Not in offsetted-area. This makes a cheap check possible
|
||||
typedef typename strategy::side::services::default_strategy
|
||||
<
|
||||
typename cs_tag<point_type>::type
|
||||
>::type side_strategy;
|
||||
|
||||
switch(side_strategy::apply(points[3], points[0], point))
|
||||
{
|
||||
case 1 : return analyse_disjoint;
|
||||
case -1 : return analyse_within;
|
||||
case 0 : return analyse_disjoint;
|
||||
}
|
||||
}
|
||||
|
||||
return analyse_continue;
|
||||
}
|
||||
|
||||
template <typename Turn, typename Piece, typename Compare>
|
||||
static inline analyse_result check_monotonic(Turn const& turn, Piece const& piece, Compare const& compare)
|
||||
{
|
||||
typedef typename Piece::piece_robust_ring_type ring_type;
|
||||
typedef typename ring_type::const_iterator it_type;
|
||||
it_type end = piece.robust_ring.begin() + piece.offsetted_count;
|
||||
it_type it = std::lower_bound(piece.robust_ring.begin(),
|
||||
end,
|
||||
turn.robust_point,
|
||||
compare);
|
||||
|
||||
if (it != end
|
||||
&& it != piece.robust_ring.begin())
|
||||
{
|
||||
// iterator points to point larger than point
|
||||
// w.r.t. specified direction, and prev points to a point smaller
|
||||
// We now know if it is inside/outside
|
||||
it_type prev = it - 1;
|
||||
return check_segment<UseSideOfIntersection>::apply(*prev, *it, turn, true);
|
||||
}
|
||||
return analyse_continue;
|
||||
}
|
||||
|
||||
public :
|
||||
template <typename Turn, typename Piece>
|
||||
static inline analyse_result apply(Turn const& turn, Piece const& piece)
|
||||
{
|
||||
typedef typename Turn::robust_point_type point_type;
|
||||
analyse_result code = check_helper_segments(turn, piece);
|
||||
if (code != analyse_continue)
|
||||
{
|
||||
return code;
|
||||
}
|
||||
|
||||
geometry::equal_to<point_type> comparator;
|
||||
|
||||
if (piece.offsetted_count > 8)
|
||||
{
|
||||
// If the offset contains some points and is monotonic, we try
|
||||
// to avoid walking all points linearly.
|
||||
// We try it only once.
|
||||
if (piece.is_monotonic_increasing[0])
|
||||
{
|
||||
code = check_monotonic(turn, piece, geometry::less<point_type, 0>());
|
||||
if (code != analyse_continue) return code;
|
||||
}
|
||||
else if (piece.is_monotonic_increasing[1])
|
||||
{
|
||||
code = check_monotonic(turn, piece, geometry::less<point_type, 1>());
|
||||
if (code != analyse_continue) return code;
|
||||
}
|
||||
else if (piece.is_monotonic_decreasing[0])
|
||||
{
|
||||
code = check_monotonic(turn, piece, geometry::greater<point_type, 0>());
|
||||
if (code != analyse_continue) return code;
|
||||
}
|
||||
else if (piece.is_monotonic_decreasing[1])
|
||||
{
|
||||
code = check_monotonic(turn, piece, geometry::greater<point_type, 1>());
|
||||
if (code != analyse_continue) return code;
|
||||
}
|
||||
}
|
||||
|
||||
// It is small or not monotonic, walk linearly through offset
|
||||
// TODO: this will be combined with winding strategy
|
||||
|
||||
for (signed_size_type i = 1; i < piece.offsetted_count; i++)
|
||||
{
|
||||
point_type const& previous = piece.robust_ring[i - 1];
|
||||
point_type const& current = piece.robust_ring[i];
|
||||
|
||||
// The robust ring can contain duplicates
|
||||
// (on which any side or side-value would return 0)
|
||||
if (! comparator(previous, current))
|
||||
{
|
||||
code = check_segment<UseSideOfIntersection>::apply(previous, current, turn, false);
|
||||
if (code != analyse_continue)
|
||||
{
|
||||
return code;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return analyse_unknown;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// Helper Structure, of which the apply method returns a side value in {-1, 0, 1}
|
||||
template <bool UseSideOfIntersection>
|
||||
struct turn_in_piece {};
|
||||
|
||||
template <>
|
||||
struct turn_in_piece<true>
|
||||
{
|
||||
|
||||
private :
|
||||
template <typename Turn, typename Piece>
|
||||
static inline int in_convex_piece(Turn const& turn, Piece const& piece)
|
||||
{
|
||||
typedef typename Turn::robust_point_type point_type;
|
||||
typedef typename Piece::piece_robust_ring_type ring_type;
|
||||
typedef geometry::model::referring_segment<point_type const> segment;
|
||||
|
||||
segment const p(turn.rob_pi, turn.rob_pj);
|
||||
segment const q(turn.rob_qi, turn.rob_qj);
|
||||
|
||||
typedef typename boost::range_iterator<ring_type const>::type iterator_type;
|
||||
iterator_type it = boost::begin(piece.robust_ring);
|
||||
iterator_type end = boost::end(piece.robust_ring);
|
||||
|
||||
// A robust ring is always closed, and always clockwise
|
||||
for (iterator_type previous = it++; it != end; ++previous, ++it)
|
||||
{
|
||||
geometry::equal_to<point_type> comparator;
|
||||
if (comparator(*previous, *it))
|
||||
{
|
||||
// Points are the same
|
||||
continue;
|
||||
}
|
||||
|
||||
segment r(*previous, *it);
|
||||
|
||||
int const side = strategy::side::side_of_intersection::apply(p, q, r,
|
||||
turn.robust_point);
|
||||
|
||||
if (side == 1)
|
||||
{
|
||||
// IP is left of segment, so it is outside
|
||||
return -1; // outside
|
||||
}
|
||||
else if (side == 0)
|
||||
{
|
||||
// IP is collinear with segment. TODO: we should analyze this further
|
||||
// For now we use the fallback point
|
||||
if (in_box(*previous, *it, turn.robust_point))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1; // outside
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1; // inside
|
||||
}
|
||||
|
||||
public :
|
||||
|
||||
template <typename Turn, typename Piece, typename Strategy>
|
||||
static inline int apply(Turn const& turn, Piece const& piece,
|
||||
Strategy const& strategy)
|
||||
{
|
||||
if (piece.is_convex)
|
||||
{
|
||||
return in_convex_piece(turn, piece);
|
||||
}
|
||||
else
|
||||
{
|
||||
// side-of-intersection only supported for convex pieces
|
||||
// Call point_in_geometry, a performance-bottleneck
|
||||
// TODO: might be replaced by extending analysing piece
|
||||
return detail::within::point_in_geometry(turn.robust_point,
|
||||
piece.robust_ring, strategy);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct turn_in_piece<false>
|
||||
{
|
||||
public :
|
||||
|
||||
template <typename Turn, typename Piece, typename Strategy>
|
||||
static inline int apply(Turn const& turn, Piece const& piece,
|
||||
Strategy const& strategy)
|
||||
{
|
||||
return detail::within::point_in_geometry(turn.robust_point,
|
||||
piece.robust_ring, strategy);
|
||||
}
|
||||
};
|
||||
|
||||
template
|
||||
<
|
||||
typename CsTag,
|
||||
typename Turns,
|
||||
typename Pieces,
|
||||
typename PointInGeometryStrategy
|
||||
>
|
||||
class turn_in_piece_visitor
|
||||
{
|
||||
Turns& m_turns; // because partition is currently operating on const input only
|
||||
Pieces const& m_pieces; // to check for piece-type
|
||||
PointInGeometryStrategy const& m_point_in_geometry_strategy;
|
||||
|
||||
template <typename Operation, typename Piece>
|
||||
inline bool skip(Operation const& op, Piece const& piece) const
|
||||
{
|
||||
if (op.piece_index == piece.index)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
Piece const& pc = m_pieces[op.piece_index];
|
||||
if (pc.left_index == piece.index || pc.right_index == piece.index)
|
||||
{
|
||||
if (pc.type == strategy::buffer::buffered_flat_end)
|
||||
{
|
||||
// If it is a flat end, don't compare against its neighbor:
|
||||
// it will always be located on one of the helper segments
|
||||
return true;
|
||||
}
|
||||
if (pc.type == strategy::buffer::buffered_concave)
|
||||
{
|
||||
// If it is concave, the same applies: the IP will be
|
||||
// located on one of the helper segments
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
inline turn_in_piece_visitor(Turns& turns, Pieces const& pieces,
|
||||
PointInGeometryStrategy const& strategy)
|
||||
: m_turns(turns)
|
||||
, m_pieces(pieces)
|
||||
, m_point_in_geometry_strategy(strategy)
|
||||
{}
|
||||
|
||||
template <typename Turn, typename Piece>
|
||||
inline bool apply(Turn const& turn, Piece const& piece, bool first = true)
|
||||
{
|
||||
boost::ignore_unused(first);
|
||||
|
||||
if (turn.count_within > 0)
|
||||
{
|
||||
// Already inside - no need to check again
|
||||
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 (! geometry::covered_by(turn.robust_point, piece.robust_envelope))
|
||||
{
|
||||
// Easy check: if the turn is not in the envelope, we can safely return
|
||||
return true;
|
||||
}
|
||||
|
||||
if (skip(turn.operations[0], piece) || skip(turn.operations[1], piece))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: mutable_piece to make some on-demand preparations in analyse
|
||||
Turn& mutable_turn = m_turns[turn.turn_index];
|
||||
|
||||
if (piece.type == geometry::strategy::buffer::buffered_point)
|
||||
{
|
||||
// Optimization for buffer around points: if distance from center
|
||||
// is not between min/max radius, the result is clear
|
||||
typedef typename default_comparable_distance_result
|
||||
<
|
||||
typename Turn::robust_point_type
|
||||
>::type distance_type;
|
||||
|
||||
distance_type const cd
|
||||
= geometry::comparable_distance(piece.robust_center,
|
||||
turn.robust_point);
|
||||
|
||||
if (cd < piece.robust_min_comparable_radius)
|
||||
{
|
||||
mutable_turn.count_within++;
|
||||
return true;
|
||||
}
|
||||
if (cd > piece.robust_max_comparable_radius)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static const bool use_soi = use_side_of_intersection<CsTag>::value;
|
||||
boost::ignore_unused(use_soi);
|
||||
|
||||
analyse_result analyse_code =
|
||||
piece.type == geometry::strategy::buffer::buffered_point
|
||||
? analyse_turn_wrt_point_piece<use_soi>::apply(turn, piece)
|
||||
: analyse_turn_wrt_piece<use_soi>::apply(turn, piece);
|
||||
|
||||
switch(analyse_code)
|
||||
{
|
||||
case analyse_disjoint :
|
||||
return true;
|
||||
case analyse_on_offsetted :
|
||||
mutable_turn.count_on_offsetted++; // value is not used anymore
|
||||
return true;
|
||||
case analyse_on_original_boundary :
|
||||
mutable_turn.count_on_original_boundary++;
|
||||
return true;
|
||||
case analyse_within :
|
||||
mutable_turn.count_within++;
|
||||
return true;
|
||||
case analyse_near_offsetted :
|
||||
mutable_turn.count_within_near_offsetted++;
|
||||
return true;
|
||||
default :
|
||||
break;
|
||||
}
|
||||
|
||||
int const geometry_code = turn_in_piece<use_soi>::apply(turn, piece,
|
||||
m_point_in_geometry_strategy);
|
||||
|
||||
if (geometry_code == 1)
|
||||
{
|
||||
mutable_turn.count_within++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}} // namespace detail::buffer
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_PIECE_VISITOR
|
||||
Reference in New Issue
Block a user