summaryrefslogtreecommitdiff
path: root/boost/geometry/algorithms/detail/overlay
diff options
context:
space:
mode:
authorChanho Park <chanho61.park@samsung.com>2014-12-11 18:55:56 +0900
committerChanho Park <chanho61.park@samsung.com>2014-12-11 18:55:56 +0900
commit08c1e93fa36a49f49325a07fe91ff92c964c2b6c (patch)
tree7a7053ceb8874b28ec4b868d4c49b500008a102e /boost/geometry/algorithms/detail/overlay
parentbb4dd8289b351fae6b55e303f189127a394a1edd (diff)
downloadboost-08c1e93fa36a49f49325a07fe91ff92c964c2b6c.tar.gz
boost-08c1e93fa36a49f49325a07fe91ff92c964c2b6c.tar.bz2
boost-08c1e93fa36a49f49325a07fe91ff92c964c2b6c.zip
Imported Upstream version 1.57.0upstream/1.57.0
Diffstat (limited to 'boost/geometry/algorithms/detail/overlay')
-rw-r--r--boost/geometry/algorithms/detail/overlay/add_rings.hpp35
-rw-r--r--boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp4
-rw-r--r--boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp160
-rw-r--r--boost/geometry/algorithms/detail/overlay/assign_parents.hpp58
-rw-r--r--boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp23
-rw-r--r--boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp64
-rw-r--r--boost/geometry/algorithms/detail/overlay/check_enrich.hpp2
-rw-r--r--boost/geometry/algorithms/detail/overlay/convert_ring.hpp21
-rw-r--r--boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp94
-rw-r--r--boost/geometry/algorithms/detail/overlay/copy_segments.hpp320
-rw-r--r--boost/geometry/algorithms/detail/overlay/do_reverse.hpp47
-rw-r--r--boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp165
-rw-r--r--boost/geometry/algorithms/detail/overlay/enrichment_info.hpp20
-rw-r--r--boost/geometry/algorithms/detail/overlay/follow.hpp292
-rw-r--r--boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp536
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp71
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_relative_order.hpp13
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_ring.hpp37
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_turn_info.hpp528
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp657
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp329
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp805
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp720
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_turns.hpp422
-rw-r--r--boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp347
-rw-r--r--boost/geometry/algorithms/detail/overlay/intersection_box_box.hpp84
-rw-r--r--boost/geometry/algorithms/detail/overlay/intersection_insert.hpp571
-rw-r--r--boost/geometry/algorithms/detail/overlay/linear_linear.hpp326
-rw-r--r--boost/geometry/algorithms/detail/overlay/overlay.hpp76
-rw-r--r--boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp435
-rw-r--r--boost/geometry/algorithms/detail/overlay/segment_identifier.hpp31
-rw-r--r--boost/geometry/algorithms/detail/overlay/select_rings.hpp63
-rw-r--r--boost/geometry/algorithms/detail/overlay/self_turn_points.hpp117
-rw-r--r--boost/geometry/algorithms/detail/overlay/stream_info.hpp3
-rw-r--r--boost/geometry/algorithms/detail/overlay/traversal_info.hpp16
-rw-r--r--boost/geometry/algorithms/detail/overlay/traverse.hpp82
-rw-r--r--boost/geometry/algorithms/detail/overlay/turn_info.hpp12
-rw-r--r--boost/geometry/algorithms/detail/overlay/visit_info.hpp54
38 files changed, 6192 insertions, 1448 deletions
diff --git a/boost/geometry/algorithms/detail/overlay/add_rings.hpp b/boost/geometry/algorithms/detail/overlay/add_rings.hpp
index 74595fedd0..5ff0b57d6e 100644
--- a/boost/geometry/algorithms/detail/overlay/add_rings.hpp
+++ b/boost/geometry/algorithms/detail/overlay/add_rings.hpp
@@ -75,15 +75,15 @@ inline OutputIterator add_rings(SelectionMap const& map,
OutputIterator out)
{
typedef typename SelectionMap::const_iterator iterator;
- typedef typename SelectionMap::mapped_type property_type;
- typedef typename property_type::area_type area_type;
-
- area_type const zero = 0;
- std::size_t const min_num_points = core_detail::closure::minimum_ring_size
- <
- geometry::closure
- <
- typename boost::range_value
+ typedef typename SelectionMap::mapped_type property_type;
+ typedef typename property_type::area_type area_type;
+
+ area_type const zero = 0;
+ std::size_t const min_num_points = core_detail::closure::minimum_ring_size
+ <
+ geometry::closure
+ <
+ typename boost::range_value
<
RingCollection const
>::type
@@ -117,15 +117,14 @@ inline OutputIterator add_rings(SelectionMap const& map,
}
}
- // Only add rings if they satisfy minimal requirements.
- // This cannot be done earlier (during traversal), not
- // everything is figured out yet (sum of positive/negative rings)
- // TODO: individual rings can still contain less than 3 points.
- if (geometry::num_points(result) >= min_num_points
- && math::larger(geometry::area(result), zero))
- {
- *out++ = result;
- }
+ // Only add rings if they satisfy minimal requirements.
+ // This cannot be done earlier (during traversal), not
+ // everything is figured out yet (sum of positive/negative rings)
+ if (geometry::num_points(result) >= min_num_points
+ && math::larger(geometry::area(result), zero))
+ {
+ *out++ = result;
+ }
}
}
return out;
diff --git a/boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp b/boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp
index 2c0f88e2aa..0fd1fe4de9 100644
--- a/boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp
+++ b/boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp
@@ -13,7 +13,7 @@
#include <boost/range.hpp>
#include <boost/geometry/algorithms/append.hpp>
-#include <boost/geometry/algorithms/detail/disjoint.hpp>
+#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
@@ -29,7 +29,7 @@ template <typename Range, typename Point>
inline void append_no_duplicates(Range& range, Point const& point, bool force = false)
{
if (boost::size(range) == 0
- || force
+ || force
|| ! geometry::detail::equals::equals_point_point(*(boost::end(range)-1), point))
{
#ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION
diff --git a/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp b/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp
new file mode 100644
index 0000000000..d44db17ad3
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp
@@ -0,0 +1,160 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_APPEND_NO_DUPS_OR_SPIKES_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_APPEND_NO_DUPS_OR_SPIKES_HPP
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/algorithms/append.hpp>
+#include <boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp>
+#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
+
+#include <boost/geometry/util/range.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+// TODO: move this / rename this
+template <typename Point1, typename Point2, typename RobustPolicy>
+inline bool points_equal_or_close(Point1 const& point1,
+ Point2 const& point2,
+ RobustPolicy const& robust_policy)
+{
+ if (detail::equals::equals_point_point(point1, point2))
+ {
+ return true;
+ }
+
+ if (! RobustPolicy::enabled)
+ {
+ return false;
+ }
+
+ // Try using specified robust policy
+ typedef typename geometry::robust_point_type
+ <
+ Point1,
+ RobustPolicy
+ >::type robust_point_type;
+
+ robust_point_type point1_rob, point2_rob;
+ geometry::recalculate(point1_rob, point1, robust_policy);
+ geometry::recalculate(point2_rob, point2, robust_policy);
+
+ return detail::equals::equals_point_point(point1_rob, point2_rob);
+}
+
+
+template <typename Range, typename Point, typename RobustPolicy>
+inline void append_no_dups_or_spikes(Range& range, Point const& point,
+ RobustPolicy const& robust_policy)
+{
+#ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION
+ std::cout << " add: ("
+ << geometry::get<0>(point) << ", " << geometry::get<1>(point) << ")"
+ << std::endl;
+#endif
+ // The code below thies condition checks all spikes/dups
+ // for geometries >= 3 points.
+ // So we have to check the first potential duplicate differently
+ if (boost::size(range) == 1
+ && points_equal_or_close(*(boost::begin(range)), point, robust_policy))
+ {
+ return;
+ }
+
+ traits::push_back<Range>::apply(range, point);
+
+ // If a point is equal, or forming a spike, remove the pen-ultimate point
+ // because this one caused the spike.
+ // If so, the now-new-pen-ultimate point can again cause a spike
+ // (possibly at a corner). So keep doing this.
+ // Besides spikes it will also avoid adding duplicates.
+ while(boost::size(range) >= 3
+ && point_is_spike_or_equal(point,
+ *(boost::end(range) - 3),
+ *(boost::end(range) - 2),
+ robust_policy))
+ {
+ // Use the Concept/traits, so resize and append again
+ traits::resize<Range>::apply(range, boost::size(range) - 2);
+ traits::push_back<Range>::apply(range, point);
+ }
+}
+
+template <typename Range, typename RobustPolicy>
+inline void clean_closing_dups_and_spikes(Range& range,
+ RobustPolicy const& robust_policy)
+{
+ std::size_t const minsize
+ = core_detail::closure::minimum_ring_size
+ <
+ geometry::closure<Range>::value
+ >::value;
+
+ if (boost::size(range) <= minsize)
+ {
+ return;
+ }
+
+ typedef typename boost::range_iterator<Range>::type iterator_type;
+ static bool const closed = geometry::closure<Range>::value == geometry::closed;
+
+// TODO: the following algorithm could be rewritten to first look for spikes
+// and then erase some number of points from the beginning of the Range
+
+ bool found = false;
+ do
+ {
+ found = false;
+ iterator_type first = boost::begin(range);
+ iterator_type second = first + 1;
+ iterator_type ultimate = boost::end(range) - 1;
+ if (closed)
+ {
+ ultimate--;
+ }
+
+ // Check if closing point is a spike (this is so if the second point is
+ // considered as a spike w.r.t. the last segment)
+ if (point_is_spike_or_equal(*second, *ultimate, *first, robust_policy))
+ {
+ range::erase(range, first);
+ if (closed)
+ {
+ // Remove closing last point
+ range::resize(range, boost::size(range) - 1);
+ // Add new closing point
+ range::push_back(range, range::front(range));
+ }
+ found = true;
+ }
+ } while(found && boost::size(range) > minsize);
+}
+
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_APPEND_NO_DUPS_OR_SPIKES_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/assign_parents.hpp b/boost/geometry/algorithms/detail/overlay/assign_parents.hpp
index 5063f49eb4..67b48cc471 100644
--- a/boost/geometry/algorithms/detail/overlay/assign_parents.hpp
+++ b/boost/geometry/algorithms/detail/overlay/assign_parents.hpp
@@ -18,6 +18,10 @@
#include <boost/geometry/geometries/box.hpp>
+#ifdef BOOST_GEOMETRY_TIME_OVERLAY
+# include <boost/timer.hpp>
+#endif
+
namespace boost { namespace geometry
{
@@ -123,30 +127,30 @@ struct assign_visitor
template <typename Item>
inline void apply(Item const& outer, Item const& inner, bool first = true)
{
- if (first && outer.real_area < 0)
+ if (first && outer.abs_area < inner.abs_area)
{
- // Reverse arguments
+ // Apply with reversed arguments
apply(inner, outer, false);
return;
}
- if (math::larger(outer.real_area, 0))
+ if (m_check_for_orientation
+ || (math::larger(outer.real_area, 0)
+ && math::smaller(inner.real_area, 0)))
{
- if (inner.real_area < 0 || m_check_for_orientation)
- {
- ring_info_type& inner_in_map = m_ring_map[inner.id];
+ ring_info_type& inner_in_map = m_ring_map[inner.id];
- if (geometry::within(inner_in_map.point, outer.envelope)
- && within_selected_input(inner_in_map, outer.id, m_geometry1, m_geometry2, m_collection)
- )
+ if (geometry::within(inner_in_map.point, outer.envelope)
+ && within_selected_input(inner_in_map, outer.id, m_geometry1, m_geometry2, m_collection)
+ )
+ {
+ // Assign a parent if there was no earlier parent, or the newly
+ // found parent is smaller than the previous one
+ if (inner_in_map.parent.source_index == -1
+ || outer.abs_area < inner_in_map.parent_area)
{
- // Only assign parent if that parent is smaller (or if it is the first)
- if (inner_in_map.parent.source_index == -1
- || outer.abs_area < inner_in_map.parent_area)
- {
- inner_in_map.parent = outer.id;
- inner_in_map.parent_area = outer.abs_area;
- }
+ inner_in_map.parent = outer.id;
+ inner_in_map.parent_area = outer.abs_area;
}
}
}
@@ -243,7 +247,7 @@ inline void assign_parents(Geometry1 const& geometry1,
// a dramatic improvement (factor 5 for star_comb testcase)
ring_identifier id_of_positive = vector[index_positive].id;
ring_info_type& outer = ring_map[id_of_positive];
- std::size_t index = 0;
+ index = 0;
for (vector_iterator_type it = boost::begin(vector);
it != boost::end(vector); ++it, ++index)
{
@@ -284,13 +288,21 @@ inline void assign_parents(Geometry1 const& geometry1,
{
it->second.discarded = true;
}
- else if (it->second.parent.source_index >= 0 && it->second.get_area() > 0)
+ else if (it->second.parent.source_index >= 0
+ && math::larger(it->second.get_area(), 0))
{
- // Discard positive inner ring with parent
- it->second.discarded = true;
+ const ring_info_type& parent = ring_map[it->second.parent];
+
+ if (math::larger(parent.area, 0))
+ {
+ // Discard positive inner ring with positive parent
+ it->second.discarded = true;
+ }
+ // Remove parent ID from any positive inner ring
it->second.parent.source_index = -1;
}
- else if (it->second.parent.source_index < 0 && it->second.get_area() < 0)
+ else if (it->second.parent.source_index < 0
+ && math::smaller(it->second.get_area(), 0))
{
// Reverse negative ring without parent
it->second.reversed = true;
@@ -309,6 +321,8 @@ inline void assign_parents(Geometry1 const& geometry1,
}
}
+
+// Version for one geometry (called by buffer)
template
<
typename Geometry,
@@ -320,7 +334,7 @@ inline void assign_parents(Geometry const& geometry,
RingMap& ring_map,
bool check_for_orientation)
{
- // Call it with an empty geometry
+ // Call it with an empty geometry as second geometry (source_id == 1)
// (ring_map should be empty for source_id==1)
Geometry empty;
diff --git a/boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp b/boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp
index 012b3aca30..90901dee70 100644
--- a/boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp
+++ b/boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp
@@ -55,8 +55,8 @@ inline void clear_visit_info(Turns& turns)
struct backtrack_state
{
bool m_good;
-
- inline backtrack_state() : m_good(true) {}
+
+ inline backtrack_state() : m_good(true) {}
inline void reset() { m_good = true; }
inline bool good() const { return m_good; }
};
@@ -79,29 +79,30 @@ class backtrack_check_self_intersections
public :
typedef state state_type;
- template <typename Operation, typename Rings, typename Turns>
- static inline void apply(std::size_t size_at_start,
- Rings& rings, typename boost::range_value<Rings>::type& ring,
+ template <typename Operation, typename Rings, typename Ring, typename Turns, typename RobustPolicy>
+ static inline void apply(std::size_t size_at_start,
+ Rings& rings, Ring& ring,
Turns& turns, Operation& operation,
std::string const& ,
Geometry1 const& geometry1,
Geometry2 const& geometry2,
+ RobustPolicy const& robust_policy,
state_type& state
)
{
state.m_good = false;
-
+
// Check self-intersections and throw exception if appropriate
if (! state.m_checked)
{
state.m_checked = true;
- has_self_intersections(geometry1);
- has_self_intersections(geometry2);
+ has_self_intersections(geometry1, robust_policy);
+ has_self_intersections(geometry2, robust_policy);
}
// Make bad output clean
rings.resize(size_at_start);
- ring.clear();
+ geometry::traits::clear<typename boost::range_value<Rings>::type>::apply(ring);
// Reject this as a starting point
operation.visited.set_rejected();
@@ -123,7 +124,7 @@ public :
typedef backtrack_state state_type;
template <typename Operation, typename Rings, typename Turns>
- static inline void apply(std::size_t size_at_start,
+ static inline void apply(std::size_t size_at_start,
Rings& rings, typename boost::range_value<Rings>::type& ring,
Turns& turns, Operation& operation,
std::string const& reason,
@@ -133,7 +134,7 @@ public :
)
{
std::cout << " REJECT " << reason << std::endl;
-
+
state.m_good = false;
rings.resize(size_at_start);
diff --git a/boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp b/boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp
deleted file mode 100644
index 2003d2350d..0000000000
--- a/boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp
+++ /dev/null
@@ -1,64 +0,0 @@
-// Boost.Geometry (aka GGL, Generic Geometry Library)
-
-// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
-
-// Use, modification and distribution is subject to the Boost Software License,
-// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
-// http://www.boost.org/LICENSE_1_0.txt)
-
-#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CALCULATE_DISTANCE_POLICY_HPP
-#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CALCULATE_DISTANCE_POLICY_HPP
-
-
-#include <boost/geometry/algorithms/comparable_distance.hpp>
-
-
-namespace boost { namespace geometry
-{
-
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace overlay
-{
-
-
-/*!
- \brief Policy calculating distance
- \details get_turn_info has an optional policy to get some
- extra information.
- This policy calculates the distance (using default distance strategy)
- */
-struct calculate_distance_policy
-{
- static bool const include_no_turn = false;
- static bool const include_degenerate = false;
- static bool const include_opposite = false;
-
- template
- <
- typename Info,
- typename Point1,
- typename Point2,
- typename IntersectionInfo,
- typename DirInfo
- >
- static inline void apply(Info& info, Point1 const& p1, Point2 const& p2,
- IntersectionInfo const&, DirInfo const&)
- {
- info.operations[0].enriched.distance
- = geometry::comparable_distance(info.point, p1);
- info.operations[1].enriched.distance
- = geometry::comparable_distance(info.point, p2);
- }
-
-};
-
-
-}} // namespace detail::overlay
-#endif //DOXYGEN_NO_DETAIL
-
-
-}} // namespace boost::geometry
-
-
-#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CALCULATE_DISTANCE_POLICY_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/check_enrich.hpp b/boost/geometry/algorithms/detail/overlay/check_enrich.hpp
index b210fd04b1..03be18e07a 100644
--- a/boost/geometry/algorithms/detail/overlay/check_enrich.hpp
+++ b/boost/geometry/algorithms/detail/overlay/check_enrich.hpp
@@ -137,7 +137,7 @@ inline bool check_graph(TurnPoints& turn_points, operation_type for_operation)
it != boost::end(meta_turns);
++it)
{
- if (! (it->turn->blocked() || it->turn->is_discarded()))
+ if (! (it->turn->blocked() || it->turn->discarded))
{
for (int i = 0 ; i < 2; i++)
{
diff --git a/boost/geometry/algorithms/detail/overlay/convert_ring.hpp b/boost/geometry/algorithms/detail/overlay/convert_ring.hpp
index 05bd721e7f..51955b515d 100644
--- a/boost/geometry/algorithms/detail/overlay/convert_ring.hpp
+++ b/boost/geometry/algorithms/detail/overlay/convert_ring.hpp
@@ -77,12 +77,23 @@ struct convert_ring<polygon_tag>
}
else
{
- interior_rings(destination).resize(
- interior_rings(destination).size() + 1);
- geometry::convert(source, interior_rings(destination).back());
- if (reverse)
+ // Avoid adding interior rings which are invalid
+ // because of its number of points:
+ std::size_t const min_num_points
+ = core_detail::closure::minimum_ring_size
+ <
+ geometry::closure<Destination>::value
+ >::value;
+
+ if (geometry::num_points(source) >= min_num_points)
{
- boost::reverse(interior_rings(destination).back());
+ interior_rings(destination).resize(
+ interior_rings(destination).size() + 1);
+ geometry::convert(source, interior_rings(destination).back());
+ if (reverse)
+ {
+ boost::reverse(interior_rings(destination).back());
+ }
}
}
}
diff --git a/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp b/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp
index 5e18d0453a..20a6d7f48d 100644
--- a/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp
+++ b/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp
@@ -17,8 +17,10 @@
#include <boost/geometry/core/ring_type.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
+#include <boost/geometry/util/range.hpp>
#include <boost/geometry/views/closeable_view.hpp>
#include <boost/geometry/views/reversible_view.hpp>
@@ -51,7 +53,7 @@ struct copy_segment_point_range
SegmentIdentifier const& seg_id, bool second,
PointOut& point)
{
- int index = seg_id.segment_index;
+ signed_index_type index = seg_id.segment_index;
if (second)
{
index++;
@@ -94,8 +96,8 @@ struct copy_segment_point_polygon
>::apply
(
seg_id.ring_index < 0
- ? geometry::exterior_ring(polygon)
- : geometry::interior_rings(polygon)[seg_id.ring_index],
+ ? geometry::exterior_ring(polygon)
+ : range::at(geometry::interior_rings(polygon), seg_id.ring_index),
seg_id, second,
point
);
@@ -110,7 +112,7 @@ struct copy_segment_point_box
SegmentIdentifier const& seg_id, bool second,
PointOut& point)
{
- int index = seg_id.segment_index;
+ signed_index_type index = seg_id.segment_index;
if (second)
{
index++;
@@ -124,6 +126,30 @@ struct copy_segment_point_box
};
+template
+<
+ typename MultiGeometry,
+ typename SegmentIdentifier,
+ typename PointOut,
+ typename Policy
+>
+struct copy_segment_point_multi
+{
+ static inline bool apply(MultiGeometry const& multi,
+ SegmentIdentifier const& seg_id, bool second,
+ PointOut& point)
+ {
+
+ BOOST_ASSERT
+ (
+ seg_id.multi_index >= 0
+ && seg_id.multi_index < int(boost::size(multi))
+ );
+
+ // Call the single-version
+ return Policy::apply(range::at(multi, seg_id.multi_index), seg_id, second, point);
+ }
+};
}} // namespace detail::copy_segments
@@ -188,6 +214,66 @@ struct copy_segment_point<box_tag, Box, Reverse, SegmentIdentifier, PointOut>
{};
+template
+<
+ typename MultiGeometry,
+ bool Reverse,
+ typename SegmentIdentifier,
+ typename PointOut
+>
+struct copy_segment_point
+ <
+ multi_polygon_tag,
+ MultiGeometry,
+ Reverse,
+ SegmentIdentifier,
+ PointOut
+ >
+ : detail::copy_segments::copy_segment_point_multi
+ <
+ MultiGeometry,
+ SegmentIdentifier,
+ PointOut,
+ detail::copy_segments::copy_segment_point_polygon
+ <
+ typename boost::range_value<MultiGeometry>::type,
+ Reverse,
+ SegmentIdentifier,
+ PointOut
+ >
+ >
+{};
+
+template
+<
+ typename MultiGeometry,
+ bool Reverse,
+ typename SegmentIdentifier,
+ typename PointOut
+>
+struct copy_segment_point
+ <
+ multi_linestring_tag,
+ MultiGeometry,
+ Reverse,
+ SegmentIdentifier,
+ PointOut
+ >
+ : detail::copy_segments::copy_segment_point_multi
+ <
+ MultiGeometry,
+ SegmentIdentifier,
+ PointOut,
+ detail::copy_segments::copy_segment_point_range
+ <
+ typename boost::range_value<MultiGeometry>::type,
+ Reverse,
+ SegmentIdentifier,
+ PointOut
+ >
+ >
+{};
+
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
diff --git a/boost/geometry/algorithms/detail/overlay/copy_segments.hpp b/boost/geometry/algorithms/detail/overlay/copy_segments.hpp
index 805f3923e3..ceeb1a3b8b 100644
--- a/boost/geometry/algorithms/detail/overlay/copy_segments.hpp
+++ b/boost/geometry/algorithms/detail/overlay/copy_segments.hpp
@@ -1,6 +1,12 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -10,24 +16,32 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENTS_HPP
-#include <boost/array.hpp>
-#include <boost/mpl/assert.hpp>
#include <vector>
+#include <boost/array.hpp>
#include <boost/assert.hpp>
+#include <boost/mpl/assert.hpp>
#include <boost/range.hpp>
+#include <boost/type_traits/integral_constant.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/ring_type.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/core/ring_type.hpp>
+#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/iterators/ever_circling_iterator.hpp>
#include <boost/geometry/views/closeable_view.hpp>
#include <boost/geometry/views/reversible_view.hpp>
#include <boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp>
+#include <boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp>
+
+#include <boost/geometry/util/range.hpp>
+
namespace boost { namespace geometry
{
@@ -38,34 +52,38 @@ namespace detail { namespace copy_segments
{
-template
-<
- typename Ring,
- bool Reverse,
- typename SegmentIdentifier,
- typename RangeOut
->
+template <bool Reverse>
struct copy_segments_ring
{
- typedef typename closeable_view
+ template
+ <
+ typename Ring,
+ typename SegmentIdentifier,
+ typename RobustPolicy,
+ typename RangeOut
+ >
+ static inline void apply(Ring const& ring,
+ SegmentIdentifier const& seg_id,
+ signed_index_type to_index,
+ RobustPolicy const& robust_policy,
+ RangeOut& current_output)
+ {
+ typedef typename closeable_view
<
Ring const,
closure<Ring>::value
>::type cview_type;
- typedef typename reversible_view
+ typedef typename reversible_view
<
cview_type const,
Reverse ? iterate_reverse : iterate_forward
>::type rview_type;
- typedef typename boost::range_iterator<rview_type const>::type iterator;
- typedef geometry::ever_circling_iterator<iterator> ec_iterator;
+ typedef typename boost::range_iterator<rview_type const>::type iterator;
+ typedef geometry::ever_circling_iterator<iterator> ec_iterator;
+
- static inline void apply(Ring const& ring,
- SegmentIdentifier const& seg_id, int to_index,
- RangeOut& current_output)
- {
cview_type cview(ring);
rview_type view(cview);
@@ -75,10 +93,10 @@ struct copy_segments_ring
// So we use the ever-circling iterator and determine when to step out
- int const from_index = seg_id.segment_index + 1;
+ signed_index_type const from_index = seg_id.segment_index + 1;
// Sanity check
- BOOST_ASSERT(from_index < int(boost::size(view)));
+ BOOST_ASSERT(from_index < static_cast<signed_index_type>(boost::size(view)));
ec_iterator it(boost::begin(view), boost::end(view),
boost::begin(view) + from_index);
@@ -86,103 +104,130 @@ struct copy_segments_ring
// [2..4] -> 4 - 2 + 1 = 3 -> {2,3,4} -> OK
// [4..2],size=6 -> 6 - 4 + 2 + 1 = 5 -> {4,5,0,1,2} -> OK
// [1..1], travel the whole ring round
- typedef typename boost::range_difference<Ring>::type size_type;
- size_type const count = from_index <= to_index
+ signed_index_type const count = from_index <= to_index
? to_index - from_index + 1
- : int(boost::size(view)) - from_index + to_index + 1;
+ : static_cast<signed_index_type>(boost::size(view))
+ - from_index + to_index + 1;
- for (size_type i = 0; i < count; ++i, ++it)
+ for (signed_index_type i = 0; i < count; ++i, ++it)
{
- detail::overlay::append_no_duplicates(current_output, *it);
+ detail::overlay::append_no_dups_or_spikes(current_output, *it, robust_policy);
}
}
};
-template
-<
- typename LineString,
- bool Reverse,
- typename SegmentIdentifier,
- typename RangeOut
->
-struct copy_segments_linestring
+template <bool Reverse, bool RemoveSpikes = true>
+class copy_segments_linestring
{
+private:
+ // remove spikes
+ template <typename RangeOut, typename Point, typename RobustPolicy>
+ static inline void append_to_output(RangeOut& current_output,
+ Point const& point,
+ RobustPolicy const& robust_policy,
+ boost::true_type const&)
+ {
+ detail::overlay::append_no_dups_or_spikes(current_output, point,
+ robust_policy);
+ }
- typedef typename boost::range_iterator<LineString const>::type iterator;
+ // keep spikes
+ template <typename RangeOut, typename Point, typename RobustPolicy>
+ static inline void append_to_output(RangeOut& current_output,
+ Point const& point,
+ RobustPolicy const&,
+ boost::false_type const&)
+ {
+ detail::overlay::append_no_duplicates(current_output, point);
+ }
+public:
+ template
+ <
+ typename LineString,
+ typename SegmentIdentifier,
+ typename RobustPolicy,
+ typename RangeOut
+ >
static inline void apply(LineString const& ls,
- SegmentIdentifier const& seg_id, int to_index,
+ SegmentIdentifier const& seg_id,
+ signed_index_type to_index,
+ RobustPolicy const& robust_policy,
RangeOut& current_output)
{
- int const from_index = seg_id.segment_index + 1;
+ signed_index_type const from_index = seg_id.segment_index + 1;
// Sanity check
- if (from_index > to_index || from_index < 0 || to_index >= int(boost::size(ls)))
+ if ( from_index > to_index
+ || from_index < 0
+ || to_index >= static_cast<signed_index_type>(boost::size(ls)) )
{
return;
}
- typedef typename boost::range_difference<LineString>::type size_type;
- size_type const count = to_index - from_index + 1;
+ signed_index_type const count = to_index - from_index + 1;
- typename boost::range_iterator<LineString const>::type it = boost::begin(ls) + from_index;
+ typename boost::range_iterator<LineString const>::type
+ it = boost::begin(ls) + from_index;
- for (size_type i = 0; i < count; ++i, ++it)
+ for (signed_index_type i = 0; i < count; ++i, ++it)
{
- detail::overlay::append_no_duplicates(current_output, *it);
+ append_to_output(current_output, *it, robust_policy,
+ boost::integral_constant<bool, RemoveSpikes>());
}
}
};
-template
-<
- typename Polygon,
- bool Reverse,
- typename SegmentIdentifier,
- typename RangeOut
->
+template <bool Reverse>
struct copy_segments_polygon
{
+ template
+ <
+ typename Polygon,
+ typename SegmentIdentifier,
+ typename RobustPolicy,
+ typename RangeOut
+ >
static inline void apply(Polygon const& polygon,
- SegmentIdentifier const& seg_id, int to_index,
+ SegmentIdentifier const& seg_id,
+ signed_index_type to_index,
+ RobustPolicy const& robust_policy,
RangeOut& current_output)
{
// Call ring-version with the right ring
- copy_segments_ring
- <
- typename geometry::ring_type<Polygon>::type,
- Reverse,
- SegmentIdentifier,
- RangeOut
- >::apply
- (
- seg_id.ring_index < 0
+ copy_segments_ring<Reverse>::apply
+ (
+ seg_id.ring_index < 0
? geometry::exterior_ring(polygon)
- : geometry::interior_rings(polygon)[seg_id.ring_index],
- seg_id, to_index,
- current_output
- );
+ : range::at(geometry::interior_rings(polygon), seg_id.ring_index),
+ seg_id, to_index,
+ robust_policy,
+ current_output
+ );
}
};
-template
-<
- typename Box,
- bool Reverse,
- typename SegmentIdentifier,
- typename RangeOut
->
+template <bool Reverse>
struct copy_segments_box
{
+ template
+ <
+ typename Box,
+ typename SegmentIdentifier,
+ typename RobustPolicy,
+ typename RangeOut
+ >
static inline void apply(Box const& box,
- SegmentIdentifier const& seg_id, int to_index,
+ SegmentIdentifier const& seg_id,
+ signed_index_type to_index,
+ RobustPolicy const& robust_policy,
RangeOut& current_output)
{
- int index = seg_id.segment_index + 1;
+ signed_index_type index = seg_id.segment_index + 1;
BOOST_ASSERT(index < 5);
- int const count = index <= to_index
+ signed_index_type const count = index <= to_index
? to_index - index + 1
: 5 - index + to_index + 1;
@@ -193,15 +238,48 @@ struct copy_segments_box
// (possibly cyclic) copy to output
// (see comments in ring-version)
- for (int i = 0; i < count; i++, index++)
+ for (signed_index_type i = 0; i < count; i++, index++)
{
- detail::overlay::append_no_duplicates(current_output, bp[index % 5]);
+ detail::overlay::append_no_dups_or_spikes(current_output,
+ bp[index % 5], robust_policy);
}
}
};
+template<typename Policy>
+struct copy_segments_multi
+{
+ template
+ <
+ typename MultiGeometry,
+ typename SegmentIdentifier,
+ typename RobustPolicy,
+ typename RangeOut
+ >
+ static inline void apply(MultiGeometry const& multi_geometry,
+ SegmentIdentifier const& seg_id,
+ signed_index_type to_index,
+ RobustPolicy const& robust_policy,
+ RangeOut& current_output)
+ {
+
+ BOOST_ASSERT
+ (
+ seg_id.multi_index >= 0
+ && seg_id.multi_index < int(boost::size(multi_geometry))
+ );
+
+ // Call the single-version
+ Policy::apply(range::at(multi_geometry, seg_id.multi_index),
+ seg_id, to_index,
+ robust_policy,
+ current_output);
+ }
+};
+
+
}} // namespace detail::copy_segments
#endif // DOXYGEN_NO_DETAIL
@@ -213,82 +291,44 @@ namespace dispatch
template
<
typename Tag,
- typename GeometryIn,
- bool Reverse,
- typename SegmentIdentifier,
- typename RangeOut
+ bool Reverse
>
-struct copy_segments
-{
- BOOST_MPL_ASSERT_MSG
- (
- false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
- , (types<GeometryIn>)
- );
-};
+struct copy_segments : not_implemented<Tag>
+{};
-template
-<
- typename Ring,
- bool Reverse,
- typename SegmentIdentifier,
- typename RangeOut
->
-struct copy_segments<ring_tag, Ring, Reverse, SegmentIdentifier, RangeOut>
- : detail::copy_segments::copy_segments_ring
- <
- Ring, Reverse, SegmentIdentifier, RangeOut
- >
+template <bool Reverse>
+struct copy_segments<ring_tag, Reverse>
+ : detail::copy_segments::copy_segments_ring<Reverse>
{};
+template <bool Reverse>
+struct copy_segments<linestring_tag, Reverse>
+ : detail::copy_segments::copy_segments_linestring<Reverse>
+{};
-template
-<
- typename LineString,
- bool Reverse,
- typename SegmentIdentifier,
- typename RangeOut
->
-struct copy_segments<linestring_tag, LineString, Reverse, SegmentIdentifier, RangeOut>
- : detail::copy_segments::copy_segments_linestring
- <
- LineString, Reverse, SegmentIdentifier, RangeOut
- >
+template <bool Reverse>
+struct copy_segments<polygon_tag, Reverse>
+ : detail::copy_segments::copy_segments_polygon<Reverse>
{};
-template
-<
- typename Polygon,
- bool Reverse,
- typename SegmentIdentifier,
- typename RangeOut
->
-struct copy_segments<polygon_tag, Polygon, Reverse, SegmentIdentifier, RangeOut>
- : detail::copy_segments::copy_segments_polygon
- <
- Polygon, Reverse, SegmentIdentifier, RangeOut
- >
+
+template <bool Reverse>
+struct copy_segments<box_tag, Reverse>
+ : detail::copy_segments::copy_segments_box<Reverse>
{};
-template
-<
- typename Box,
- bool Reverse,
- typename SegmentIdentifier,
- typename RangeOut
->
-struct copy_segments<box_tag, Box, Reverse, SegmentIdentifier, RangeOut>
- : detail::copy_segments::copy_segments_box
+template<bool Reverse>
+struct copy_segments<multi_polygon_tag, Reverse>
+ : detail::copy_segments::copy_segments_multi
<
- Box, Reverse, SegmentIdentifier, RangeOut
+ detail::copy_segments::copy_segments_polygon<Reverse>
>
{};
-
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
@@ -303,10 +343,13 @@ template
bool Reverse,
typename Geometry,
typename SegmentIdentifier,
+ typename RobustPolicy,
typename RangeOut
>
inline void copy_segments(Geometry const& geometry,
- SegmentIdentifier const& seg_id, int to_index,
+ SegmentIdentifier const& seg_id,
+ signed_index_type to_index,
+ RobustPolicy const& robust_policy,
RangeOut& range_out)
{
concept::check<Geometry const>();
@@ -314,11 +357,8 @@ inline void copy_segments(Geometry const& geometry,
dispatch::copy_segments
<
typename tag<Geometry>::type,
- Geometry,
- Reverse,
- SegmentIdentifier,
- RangeOut
- >::apply(geometry, seg_id, to_index, range_out);
+ Reverse
+ >::apply(geometry, seg_id, to_index, robust_policy, range_out);
}
diff --git a/boost/geometry/algorithms/detail/overlay/do_reverse.hpp b/boost/geometry/algorithms/detail/overlay/do_reverse.hpp
new file mode 100644
index 0000000000..15100f8d0b
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/do_reverse.hpp
@@ -0,0 +1,47 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_DO_REVERSE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_DO_REVERSE_HPP
+
+#include <boost/geometry/core/point_order.hpp>
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+// Metafunction helper for intersection and union
+template <order_selector Selector, bool Reverse = false>
+struct do_reverse {};
+
+template <>
+struct do_reverse<clockwise, false> : boost::false_type {};
+
+template <>
+struct do_reverse<clockwise, true> : boost::true_type {};
+
+template <>
+struct do_reverse<counterclockwise, false> : boost::true_type {};
+
+template <>
+struct do_reverse<counterclockwise, true> : boost::false_type {};
+
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_DO_REVERSE_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp b/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp
index e4842d35f1..9484479b45 100644
--- a/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp
+++ b/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp
@@ -27,8 +27,9 @@
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
#include <boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp>
-#include <boost/geometry/algorithms/detail/overlay/get_relative_order.hpp>
#include <boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp>
+#include <boost/geometry/policies/robustness/robust_type.hpp>
+#include <boost/geometry/strategies/side.hpp>
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
# include <boost/geometry/algorithms/detail/overlay/check_enrich.hpp>
#endif
@@ -47,17 +48,23 @@ struct indexed_turn_operation
{
typedef TurnOperation type;
- int index;
- int operation_index;
+ std::size_t turn_index;
+ std::size_t operation_index;
bool discarded;
- TurnOperation subject;
-
- inline indexed_turn_operation(int i, int oi, TurnOperation const& s)
- : index(i)
+ // use pointers to avoid copies, const& is not possible because of usage in vector
+ segment_identifier const* other_seg_id; // segment id of other segment of intersection of two segments
+ TurnOperation const* subject;
+
+ inline indexed_turn_operation(std::size_t ti, std::size_t oi,
+ TurnOperation const& s,
+ segment_identifier const& oid)
+ : turn_index(ti)
, operation_index(oi)
, discarded(false)
- , subject(s)
+ , other_seg_id(&oid)
+ , subject(&s)
{}
+
};
template <typename IndexedTurnOperation>
@@ -75,19 +82,22 @@ template
typename TurnPoints,
typename Indexed,
typename Geometry1, typename Geometry2,
+ typename RobustPolicy,
bool Reverse1, bool Reverse2,
typename Strategy
>
-struct sort_on_segment_and_distance
+struct sort_on_segment_and_ratio
{
- inline sort_on_segment_and_distance(TurnPoints const& turn_points
+ inline sort_on_segment_and_ratio(TurnPoints const& turn_points
, Geometry1 const& geometry1
, Geometry2 const& geometry2
+ , RobustPolicy const& robust_policy
, Strategy const& strategy
, bool* clustered)
: m_turn_points(turn_points)
, m_geometry1(geometry1)
, m_geometry2(geometry2)
+ , m_robust_policy(robust_policy)
, m_strategy(strategy)
, m_clustered(clustered)
{
@@ -98,31 +108,47 @@ private :
TurnPoints const& m_turn_points;
Geometry1 const& m_geometry1;
Geometry2 const& m_geometry2;
+ RobustPolicy const& m_robust_policy;
Strategy const& m_strategy;
mutable bool* m_clustered;
+ typedef typename geometry::point_type<Geometry1>::type point_type;
+
inline bool consider_relative_order(Indexed const& left,
Indexed const& right) const
{
- typedef typename geometry::point_type<Geometry1>::type point_type;
point_type pi, pj, ri, rj, si, sj;
geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
- left.subject.seg_id,
+ left.subject->seg_id,
pi, pj);
geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
- left.subject.other_id,
+ *left.other_seg_id,
ri, rj);
geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
- right.subject.other_id,
+ *right.other_seg_id,
si, sj);
- int const order = get_relative_order
+ typedef typename strategy::side::services::default_strategy
<
- point_type
- >::apply(pi, pj,ri, rj, si, sj);
- //debug("r/o", order == -1);
- return order == -1;
+ typename cs_tag<point_type>::type
+ >::type strategy;
+
+ int const side_rj_p = strategy::apply(pi, pj, rj);
+ int const side_sj_p = strategy::apply(pi, pj, sj);
+
+ // Put the one turning left (1; right == -1) as last
+ if (side_rj_p != side_sj_p)
+ {
+ return side_rj_p < side_sj_p;
+ }
+
+ int const side_sj_r = strategy::apply(ri, rj, sj);
+ int const side_rj_s = strategy::apply(si, sj, rj);
+
+ // If they both turn left: the most left as last
+ // If they both turn right: this is not relevant, but take also here most left
+ return side_rj_s < side_sj_r;
}
public :
@@ -131,33 +157,30 @@ public :
// but to the "indexed_turn_operation"
inline bool operator()(Indexed const& left, Indexed const& right) const
{
- segment_identifier const& sl = left.subject.seg_id;
- segment_identifier const& sr = right.subject.seg_id;
+ segment_identifier const& sl = left.subject->seg_id;
+ segment_identifier const& sr = right.subject->seg_id;
- if (sl == sr
- && geometry::math::equals(left.subject.enriched.distance
- , right.subject.enriched.distance))
+ if (sl == sr)
{
// Both left and right are located on the SAME segment.
-
- // First check "real" intersection (crosses)
- // -> distance zero due to precision, solve it by sorting
- if (m_turn_points[left.index].method == method_crosses
- && m_turn_points[right.index].method == method_crosses)
+ if (left.subject->fraction == right.subject->fraction)
{
- return consider_relative_order(left, right);
- }
-
- // If that is not the case, cluster it later on.
- // Indicate that this is necessary.
- *m_clustered = true;
+ // First check "real" intersection (crosses)
+ // -> distance zero due to precision, solve it by sorting
+ if (m_turn_points[left.turn_index].method == method_crosses
+ && m_turn_points[right.turn_index].method == method_crosses)
+ {
+ return consider_relative_order(left, right);
+ }
- return left.index < right.index;
+ // If that is not the case, cluster it later on.
+ // Indicate that this is necessary.
+ *m_clustered = true;
+ }
}
return sl == sr
- ? left.subject.enriched.distance < right.subject.enriched.distance
+ ? left.subject->fraction < right.subject->fraction
: sl < sr;
-
}
};
@@ -171,13 +194,13 @@ inline void update_discarded(Turns& turn_points, Operations& operations)
it != boost::end(operations);
++it)
{
- if (turn_points[it->index].discarded)
+ if (turn_points[it->turn_index].discarded)
{
it->discarded = true;
}
else if (it->discarded)
{
- turn_points[it->index].discarded = true;
+ turn_points[it->turn_index].discarded = true;
}
}
}
@@ -195,12 +218,14 @@ template
typename Container,
typename TurnPoints,
typename Geometry1, typename Geometry2,
+ typename RobustPolicy,
typename Strategy
>
inline void enrich_sort(Container& operations,
TurnPoints& turn_points,
operation_type for_operation,
Geometry1 const& geometry1, Geometry2 const& geometry2,
+ RobustPolicy const& robust_policy,
Strategy const& strategy)
{
typedef typename IndexType::type operations_type;
@@ -208,14 +233,15 @@ inline void enrich_sort(Container& operations,
bool clustered = false;
std::sort(boost::begin(operations),
boost::end(operations),
- sort_on_segment_and_distance
+ sort_on_segment_and_ratio
<
TurnPoints,
IndexType,
Geometry1, Geometry2,
+ RobustPolicy,
Reverse1, Reverse2,
Strategy
- >(turn_points, geometry1, geometry2, strategy, &clustered));
+ >(turn_points, geometry1, geometry2, robust_policy, strategy, &clustered));
// DONT'T discard xx / (for union) ix / ii / (for intersection) ux / uu here
// It would give way to "lonely" ui turn points, traveling all
@@ -230,16 +256,15 @@ inline void enrich_sort(Container& operations,
it != boost::end(operations);
prev = it++)
{
- operations_type& prev_op = turn_points[prev->index]
+ operations_type& prev_op = turn_points[prev->turn_index]
.operations[prev->operation_index];
- operations_type& op = turn_points[it->index]
+ operations_type& op = turn_points[it->turn_index]
.operations[it->operation_index];
if (prev_op.seg_id == op.seg_id
- && (turn_points[prev->index].method != method_crosses
- || turn_points[it->index].method != method_crosses)
- && geometry::math::equals(prev_op.enriched.distance,
- op.enriched.distance))
+ && (turn_points[prev->turn_index].method != method_crosses
+ || turn_points[it->turn_index].method != method_crosses)
+ && prev_op.fraction == op.fraction)
{
if (begin_cluster == boost::end(operations))
{
@@ -249,14 +274,14 @@ inline void enrich_sort(Container& operations,
else if (begin_cluster != boost::end(operations))
{
handle_cluster<IndexType, Reverse1, Reverse2>(begin_cluster, it, turn_points,
- for_operation, geometry1, geometry2, strategy);
+ for_operation, geometry1, geometry2, robust_policy, strategy);
begin_cluster = boost::end(operations);
}
}
if (begin_cluster != boost::end(operations))
{
handle_cluster<IndexType, Reverse1, Reverse2>(begin_cluster, it, turn_points,
- for_operation, geometry1, geometry2, strategy);
+ for_operation, geometry1, geometry2, robust_policy, strategy);
}
}
@@ -315,19 +340,19 @@ inline void enrich_assign(Container& operations,
prev = it++)
{
operations_type& prev_op
- = turn_points[prev->index].operations[prev->operation_index];
+ = turn_points[prev->turn_index].operations[prev->operation_index];
operations_type& op
- = turn_points[it->index].operations[it->operation_index];
+ = turn_points[it->turn_index].operations[it->operation_index];
prev_op.enriched.travels_to_ip_index
- = it->index;
+ = static_cast<int>(it->turn_index);
prev_op.enriched.travels_to_vertex_index
- = it->subject.seg_id.segment_index;
+ = it->subject->seg_id.segment_index;
if (! first
&& prev_op.seg_id.segment_index == op.seg_id.segment_index)
{
- prev_op.enriched.next_ip_index = it->index;
+ prev_op.enriched.next_ip_index = static_cast<int>(it->turn_index);
}
first = false;
}
@@ -340,16 +365,16 @@ inline void enrich_assign(Container& operations,
it != boost::end(operations);
++it)
{
- operations_type& op = turn_points[it->index]
+ operations_type& op = turn_points[it->turn_index]
.operations[it->operation_index];
- std::cout << it->index
- << " meth: " << method_char(turn_points[it->index].method)
+ std::cout << it->turn_index
+ << " meth: " << method_char(turn_points[it->turn_index].method)
<< " seg: " << op.seg_id
- << " dst: " << boost::numeric_cast<double>(op.enriched.distance)
- << " op: " << operation_char(turn_points[it->index].operations[0].operation)
- << operation_char(turn_points[it->index].operations[1].operation)
- << " dsc: " << (turn_points[it->index].discarded ? "T" : "F")
+ << " dst: " << op.fraction // needs define
+ << " op: " << operation_char(turn_points[it->turn_index].operations[0].operation)
+ << operation_char(turn_points[it->turn_index].operations[1].operation)
+ << " dsc: " << (turn_points[it->turn_index].discarded ? "T" : "F")
<< " ->vtx " << op.enriched.travels_to_vertex_index
<< " ->ip " << op.enriched.travels_to_ip_index
<< " ->nxt ip " << op.enriched.next_ip_index
@@ -370,7 +395,7 @@ inline void create_map(TurnPoints const& turn_points, MappedVector& mapped_vecto
typedef typename boost::range_value<TurnPoints>::type turn_point_type;
typedef typename turn_point_type::container_type container_type;
- int index = 0;
+ std::size_t index = 0;
for (typename boost::range_iterator<TurnPoints const>::type
it = boost::begin(turn_points);
it != boost::end(turn_points);
@@ -379,7 +404,7 @@ inline void create_map(TurnPoints const& turn_points, MappedVector& mapped_vecto
// Add operations on this ring, but skip discarded ones
if (! it->discarded)
{
- int op_index = 0;
+ std::size_t op_index = 0;
for (typename boost::range_iterator<container_type const>::type
op_it = boost::begin(it->operations);
op_it != boost::end(it->operations);
@@ -397,7 +422,8 @@ inline void create_map(TurnPoints const& turn_points, MappedVector& mapped_vecto
);
mapped_vector[ring_id].push_back
(
- IndexedType(index, op_index, *op_it)
+ IndexedType(index, op_index, *op_it,
+ it->operations[1 - op_index].seg_id)
);
}
}
@@ -422,6 +448,7 @@ inline void create_map(TurnPoints const& turn_points, MappedVector& mapped_vecto
\param for_operation operation_type (union or intersection)
\param geometry1 \param_geometry
\param geometry2 \param_geometry
+\param robust_policy policy to handle robustness issues
\param strategy strategy
*/
template
@@ -429,11 +456,13 @@ template
bool Reverse1, bool Reverse2,
typename TurnPoints,
typename Geometry1, typename Geometry2,
+ typename RobustPolicy,
typename Strategy
>
inline void enrich_intersection_points(TurnPoints& turn_points,
detail::overlay::operation_type for_operation,
Geometry1 const& geometry1, Geometry2 const& geometry2,
+ RobustPolicy const& robust_policy,
Strategy const& strategy)
{
typedef typename boost::range_value<TurnPoints>::type turn_point_type;
@@ -462,6 +491,10 @@ inline void enrich_intersection_points(TurnPoints& turn_points,
{
it->discarded = true;
}
+ if (it->both(detail::overlay::operation_none))
+ {
+ it->discarded = true;
+ }
}
@@ -484,7 +517,7 @@ inline void enrich_intersection_points(TurnPoints& turn_points,
<< mit->first << std::endl;
#endif
detail::overlay::enrich_sort<indexed_turn_operation, Reverse1, Reverse2>(mit->second, turn_points, for_operation,
- geometry1, geometry2, strategy);
+ geometry1, geometry2, robust_policy, strategy);
}
for (typename mapped_vector_type::iterator mit
diff --git a/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp b/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp
index 8c8ed96189..ef32edeefa 100644
--- a/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp
+++ b/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp
@@ -10,9 +10,6 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ENRICHMENT_INFO_HPP
-#include <boost/geometry/strategies/distance.hpp>
-
-
namespace boost { namespace geometry
{
@@ -31,37 +28,22 @@ namespace detail { namespace overlay
template<typename P>
struct enrichment_info
{
- typedef typename strategy::distance::services::return_type
- <
- typename strategy::distance::services::comparable_type
- <
- typename strategy::distance::services::default_strategy
- <
- point_tag,
- P
- >::type
- >::type
- >::type distance_type;
-
inline enrichment_info()
: travels_to_vertex_index(-1)
, travels_to_ip_index(-1)
, next_ip_index(-1)
- , distance(distance_type())
{}
// vertex to which is free travel after this IP,
// so from "segment_index+1" to "travels_to_vertex_index", without IP-s,
// can be -1
- int travels_to_vertex_index;
+ signed_index_type travels_to_vertex_index;
// same but now IP index, so "next IP index" but not on THIS segment
int travels_to_ip_index;
// index of next IP on this segment, -1 if there is no one
int next_ip_index;
-
- distance_type distance; // distance-measurement from segment.first to IP
};
diff --git a/boost/geometry/algorithms/detail/overlay/follow.hpp b/boost/geometry/algorithms/detail/overlay/follow.hpp
index b110cc9602..acf38d09ab 100644
--- a/boost/geometry/algorithms/detail/overlay/follow.hpp
+++ b/boost/geometry/algorithms/detail/overlay/follow.hpp
@@ -1,6 +1,11 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -20,6 +25,7 @@
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
#include <boost/geometry/algorithms/covered_by.hpp>
+#include <boost/geometry/algorithms/clear.hpp>
namespace boost { namespace geometry
@@ -32,7 +38,7 @@ namespace detail { namespace overlay
namespace following
{
-
+
template <typename Turn, typename Operation>
static inline bool is_entering(Turn const& /* TODO remove this parameter */, Operation const& op)
{
@@ -44,43 +50,43 @@ static inline bool is_entering(Turn const& /* TODO remove this parameter */, Ope
;
}
-template
+template
<
- typename Turn,
- typename Operation,
- typename LineString,
+ typename Turn,
+ typename Operation,
+ typename LineString,
typename Polygon
>
-static inline bool last_covered_by(Turn const& turn, Operation const& op,
+static inline bool last_covered_by(Turn const& turn, Operation const& op,
LineString const& linestring, Polygon const& polygon)
{
- // Check any point between the this one and the first IP
+ // Check any point between the this one and the first IP
typedef typename geometry::point_type<LineString>::type point_type;
point_type point_in_between;
detail::point_on_border::midpoint_helper
<
point_type,
0, dimension<point_type>::value
- >::apply(point_in_between, linestring[op.seg_id.segment_index], turn.point);
+ >::apply(point_in_between, *(::boost::begin(linestring) + op.seg_id.segment_index), turn.point);
return geometry::covered_by(point_in_between, polygon);
}
-template
+template
<
- typename Turn,
- typename Operation,
- typename LineString,
+ typename Turn,
+ typename Operation,
+ typename LineString,
typename Polygon
>
-static inline bool is_leaving(Turn const& turn, Operation const& op,
- bool entered, bool first,
+static inline bool is_leaving(Turn const& turn, Operation const& op,
+ bool entered, bool first,
LineString const& linestring, Polygon const& polygon)
{
if (op.operation == operation_union)
{
- return entered
+ return entered
|| turn.method == method_crosses
|| (first && last_covered_by(turn, op, linestring, polygon))
;
@@ -89,20 +95,20 @@ static inline bool is_leaving(Turn const& turn, Operation const& op,
}
-template
+template
<
- typename Turn,
- typename Operation,
- typename LineString,
+ typename Turn,
+ typename Operation,
+ typename LineString,
typename Polygon
>
-static inline bool is_staying_inside(Turn const& turn, Operation const& op,
- bool entered, bool first,
+static inline bool is_staying_inside(Turn const& turn, Operation const& op,
+ bool entered, bool first,
LineString const& linestring, Polygon const& polygon)
{
if (turn.method == method_crosses)
{
- // The normal case, this is completely covered with entering/leaving
+ // The normal case, this is completely covered with entering/leaving
// so stay out of this time consuming "covered_by"
return false;
}
@@ -115,11 +121,11 @@ static inline bool is_staying_inside(Turn const& turn, Operation const& op,
return false;
}
-template
+template
<
- typename Turn,
- typename Operation,
- typename Linestring,
+ typename Turn,
+ typename Operation,
+ typename Linestring,
typename Polygon
>
static inline bool was_entered(Turn const& turn, Operation const& op, bool first,
@@ -134,7 +140,7 @@ static inline bool was_entered(Turn const& turn, Operation const& op, bool first
// Template specialization structure to call the right actions for the right type
-template<overlay_type OverlayType>
+template <overlay_type OverlayType, bool RemoveSpikes = true>
struct action_selector
{
// If you get here the overlay type is not intersection or difference
@@ -142,51 +148,86 @@ struct action_selector
};
// Specialization for intersection, containing the implementation
-template<>
-struct action_selector<overlay_intersection>
+template <bool RemoveSpikes>
+struct action_selector<overlay_intersection, RemoveSpikes>
{
template
<
- typename OutputIterator,
- typename LineStringOut,
- typename LineString,
- typename Point,
- typename Operation
+ typename OutputIterator,
+ typename LineStringOut,
+ typename LineString,
+ typename Point,
+ typename Operation,
+ typename RobustPolicy
>
static inline void enter(LineStringOut& current_piece,
- LineString const& ,
+ LineString const& ,
segment_identifier& segment_id,
- int , Point const& point,
- Operation const& operation, OutputIterator& )
+ signed_index_type , Point const& point,
+ Operation const& operation,
+ RobustPolicy const& ,
+ OutputIterator& )
{
// On enter, append the intersection point and remember starting point
+ // TODO: we don't check on spikes for linestrings (?). Consider this.
detail::overlay::append_no_duplicates(current_piece, point);
segment_id = operation.seg_id;
}
template
<
- typename OutputIterator,
- typename LineStringOut,
- typename LineString,
- typename Point,
- typename Operation
+ typename OutputIterator,
+ typename LineStringOut,
+ typename LineString,
+ typename Point,
+ typename Operation,
+ typename RobustPolicy
>
static inline void leave(LineStringOut& current_piece,
LineString const& linestring,
segment_identifier& segment_id,
- int index, Point const& point,
- Operation const& , OutputIterator& out)
+ signed_index_type index, Point const& point,
+ Operation const& ,
+ RobustPolicy const& robust_policy,
+ OutputIterator& out)
{
// On leave, copy all segments from starting point, append the intersection point
// and add the output piece
- geometry::copy_segments<false>(linestring, segment_id, index, current_piece);
+ detail::copy_segments::copy_segments_linestring
+ <
+ false, RemoveSpikes
+ >::apply(linestring, segment_id, index, robust_policy, current_piece);
detail::overlay::append_no_duplicates(current_piece, point);
- if (current_piece.size() > 1)
+ if (::boost::size(current_piece) > 1)
{
*out++ = current_piece;
}
- current_piece.clear();
+
+ geometry::clear(current_piece);
+ }
+
+ template
+ <
+ typename OutputIterator,
+ typename LineStringOut,
+ typename LineString,
+ typename Point,
+ typename Operation
+ >
+ static inline void isolated_point(LineStringOut&,
+ LineString const&,
+ segment_identifier&,
+ signed_index_type, Point const& point,
+ Operation const& , OutputIterator& out)
+ {
+ LineStringOut isolated_point_ls;
+ geometry::append(isolated_point_ls, point);
+
+#ifndef BOOST_GEOMETRY_ALLOW_ONE_POINT_LINESTRINGS
+ geometry::append(isolated_point_ls, point);
+#endif // BOOST_GEOMETRY_ALLOW_ONE_POINT_LINESTRINGS
+
+ *out++ = isolated_point_ls;
}
static inline bool is_entered(bool entered)
@@ -194,8 +235,15 @@ struct action_selector<overlay_intersection>
return entered;
}
- template <typename Point, typename Geometry>
- static inline bool included(Point const& point, Geometry const& geometry)
+ template
+ <
+ typename Point,
+ typename Geometry,
+ typename RobustPolicy
+ >
+ static inline bool included(Point const& point,
+ Geometry const& geometry,
+ RobustPolicy const& )
{
return geometry::covered_by(point, geometry);
}
@@ -203,45 +251,67 @@ struct action_selector<overlay_intersection>
};
// Specialization for difference, which reverses these actions
-template<>
-struct action_selector<overlay_difference>
+template <bool RemoveSpikes>
+struct action_selector<overlay_difference, RemoveSpikes>
{
- typedef action_selector<overlay_intersection> normal_action;
+ typedef action_selector<overlay_intersection, RemoveSpikes> normal_action;
template
<
- typename OutputIterator,
- typename LineStringOut,
- typename LineString,
- typename Point,
- typename Operation
+ typename OutputIterator,
+ typename LineStringOut,
+ typename LineString,
+ typename Point,
+ typename Operation,
+ typename RobustPolicy
>
- static inline void enter(LineStringOut& current_piece,
- LineString const& linestring,
- segment_identifier& segment_id,
- int index, Point const& point,
- Operation const& operation, OutputIterator& out)
+ static inline void enter(LineStringOut& current_piece,
+ LineString const& linestring,
+ segment_identifier& segment_id,
+ signed_index_type index, Point const& point,
+ Operation const& operation,
+ RobustPolicy const& robust_policy,
+ OutputIterator& out)
{
- normal_action::leave(current_piece, linestring, segment_id, index,
- point, operation, out);
+ normal_action::leave(current_piece, linestring, segment_id, index,
+ point, operation, robust_policy, out);
}
template
<
- typename OutputIterator,
- typename LineStringOut,
- typename LineString,
- typename Point,
- typename Operation
+ typename OutputIterator,
+ typename LineStringOut,
+ typename LineString,
+ typename Point,
+ typename Operation,
+ typename RobustPolicy
>
static inline void leave(LineStringOut& current_piece,
LineString const& linestring,
segment_identifier& segment_id,
- int index, Point const& point,
- Operation const& operation, OutputIterator& out)
+ signed_index_type index, Point const& point,
+ Operation const& operation,
+ RobustPolicy const& robust_policy,
+ OutputIterator& out)
{
normal_action::enter(current_piece, linestring, segment_id, index,
- point, operation, out);
+ point, operation, robust_policy, out);
+ }
+
+ template
+ <
+ typename OutputIterator,
+ typename LineStringOut,
+ typename LineString,
+ typename Point,
+ typename Operation
+ >
+ static inline void isolated_point(LineStringOut&,
+ LineString const&,
+ segment_identifier&,
+ signed_index_type, Point const&,
+ Operation const&, OutputIterator&)
+ {
}
static inline bool is_entered(bool entered)
@@ -249,10 +319,17 @@ struct action_selector<overlay_difference>
return ! normal_action::is_entered(entered);
}
- template <typename Point, typename Geometry>
- static inline bool included(Point const& point, Geometry const& geometry)
+ template
+ <
+ typename Point,
+ typename Geometry,
+ typename RobustPolicy
+ >
+ static inline bool included(Point const& point,
+ Geometry const& geometry,
+ RobustPolicy const& robust_policy)
{
- return ! normal_action::included(point, geometry);
+ return ! normal_action::included(point, geometry, robust_policy);
}
};
@@ -269,12 +346,13 @@ template
typename LineStringOut,
typename LineString,
typename Polygon,
- overlay_type OverlayType
+ overlay_type OverlayType,
+ bool RemoveSpikes = true
>
class follow
{
- template<typename Turn>
+ template <typename Turn>
struct sort_on_segment
{
// In case of turn point at the same location, we want to have continue/blocked LAST
@@ -296,15 +374,15 @@ class follow
inline bool use_operation(Turn const& left, Turn const& right) const
{
- // If they are the same, OK.
+ // If they are the same, OK.
return operation_order(left) < operation_order(right);
}
inline bool use_distance(Turn const& left, Turn const& right) const
{
- return geometry::math::equals(left.operations[0].enriched.distance, right.operations[0].enriched.distance)
+ return left.operations[0].fraction == right.operations[0].fraction
? use_operation(left, right)
- : left.operations[0].enriched.distance < right.operations[0].enriched.distance
+ : left.operations[0].fraction < right.operations[0].fraction
;
}
@@ -325,16 +403,33 @@ class follow
public :
- template <typename Point, typename Geometry>
- static inline bool included(Point const& point, Geometry const& geometry)
+ template
+ <
+ typename Point,
+ typename Geometry,
+ typename RobustPolicy
+ >
+ static inline bool included(Point const& point,
+ Geometry const& geometry,
+ RobustPolicy const& robust_policy)
{
- return following::action_selector<OverlayType>::included(point, geometry);
+ return following::action_selector
+ <
+ OverlayType, RemoveSpikes
+ >::included(point, geometry, robust_policy);
}
- template<typename Turns, typename OutputIterator>
+ template
+ <
+ typename Turns,
+ typename OutputIterator,
+ typename RobustPolicy
+ >
static inline OutputIterator apply(LineString const& linestring, Polygon const& polygon,
detail::overlay::operation_type , // TODO: this parameter might be redundant
- Turns& turns, OutputIterator out)
+ Turns& turns,
+ RobustPolicy const& robust_policy,
+ OutputIterator out)
{
typedef typename boost::range_iterator<Turns>::type turn_iterator;
typedef typename boost::range_value<Turns>::type turn_type;
@@ -343,7 +438,7 @@ public :
typename turn_type::container_type
>::type turn_operation_iterator_type;
- typedef following::action_selector<OverlayType> action;
+ typedef following::action_selector<OverlayType, RemoveSpikes> action;
// Sort intersection points on segments-along-linestring, and distance
// (like in enrich is done for poly/poly)
@@ -376,27 +471,38 @@ public :
debug_traverse(*it, *iit, "-> Entering");
entered = true;
- action::enter(current_piece, linestring, current_segment_id, iit->seg_id.segment_index, it->point, *iit, out);
+ action::enter(current_piece, linestring, current_segment_id,
+ iit->seg_id.segment_index, it->point, *iit,
+ robust_policy,
+ out);
}
else if (following::is_leaving(*it, *iit, entered, first, linestring, polygon))
{
debug_traverse(*it, *iit, "-> Leaving");
entered = false;
- action::leave(current_piece, linestring, current_segment_id, iit->seg_id.segment_index, it->point, *iit, out);
+ action::leave(current_piece, linestring, current_segment_id,
+ iit->seg_id.segment_index, it->point, *iit,
+ robust_policy,
+ out);
}
first = false;
}
if (action::is_entered(entered))
{
- geometry::copy_segments<false>(linestring, current_segment_id,
- boost::size(linestring) - 1,
- current_piece);
+ detail::copy_segments::copy_segments_linestring
+ <
+ false, RemoveSpikes
+ >::apply(linestring,
+ current_segment_id,
+ static_cast<signed_index_type>(boost::size(linestring) - 1),
+ robust_policy,
+ current_piece);
}
// Output the last one, if applicable
- if (current_piece.size() > 1)
+ if (::boost::size(current_piece) > 1)
{
*out++ = current_piece;
}
diff --git a/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp b/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp
new file mode 100644
index 0000000000..85378e08b0
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp
@@ -0,0 +1,536 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_LINEAR_LINEAR_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_LINEAR_LINEAR_HPP
+
+#include <cstddef>
+#include <algorithm>
+#include <iterator>
+
+#include <boost/assert.hpp>
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp>
+#include <boost/geometry/algorithms/detail/overlay/follow.hpp>
+#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
+#include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
+#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+
+#include <boost/geometry/algorithms/detail/turns/debug_turn.hpp>
+
+#include <boost/geometry/algorithms/convert.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+namespace following { namespace linear
+{
+
+
+
+
+// follower for linear/linear geometries set operations
+
+template <typename Turn, typename Operation>
+static inline bool is_entering(Turn const& turn,
+ Operation const& operation)
+{
+ if ( turn.method != method_touch && turn.method != method_touch_interior )
+ {
+ return false;
+ }
+ return operation.operation == operation_intersection;
+}
+
+
+
+template <typename Turn, typename Operation>
+static inline bool is_staying_inside(Turn const& turn,
+ Operation const& operation,
+ bool entered)
+{
+ if ( !entered )
+ {
+ return false;
+ }
+
+ if ( turn.method != method_equal && turn.method != method_collinear )
+ {
+ return false;
+ }
+ return operation.operation == operation_continue;
+}
+
+
+
+template <typename Turn, typename Operation>
+static inline bool is_leaving(Turn const& turn,
+ Operation const& operation,
+ bool entered)
+{
+ if ( !entered )
+ {
+ return false;
+ }
+
+ if ( turn.method != method_touch
+ && turn.method != method_touch_interior
+ && turn.method != method_equal
+ && turn.method != method_collinear )
+ {
+ return false;
+ }
+
+ if ( operation.operation == operation_blocked )
+ {
+ return true;
+ }
+
+ if ( operation.operation != operation_union )
+ {
+ return false;
+ }
+
+ return operation.is_collinear;
+}
+
+
+
+template <typename Turn, typename Operation>
+static inline bool is_isolated_point(Turn const& turn,
+ Operation const& operation,
+ bool entered)
+{
+ if ( entered )
+ {
+ return false;
+ }
+
+ if ( turn.method == method_none )
+ {
+ BOOST_ASSERT( operation.operation == operation_continue );
+ return true;
+ }
+
+ if ( turn.method == method_crosses )
+ {
+ return true;
+ }
+
+ if ( turn.method != method_touch && turn.method != method_touch_interior )
+ {
+ return false;
+ }
+
+ if ( operation.operation == operation_blocked )
+ {
+ return true;
+ }
+
+ if ( operation.operation != operation_union )
+ {
+ return false;
+ }
+
+ return !operation.is_collinear;
+}
+
+
+
+
+
+
+
+
+
+template
+<
+ typename LinestringOut,
+ typename Linestring,
+ typename Linear,
+ overlay_type OverlayType,
+ bool FollowIsolatedPoints,
+ bool FollowContinueTurns
+>
+class follow_linestring_linear_linestring
+{
+protected:
+ // allow spikes (false indicates: do not remove spikes)
+ typedef following::action_selector<OverlayType, false> action;
+
+ template
+ <
+ typename TurnIterator,
+ typename TurnOperationIterator,
+ typename SegmentIdentifier,
+ typename OutputIterator
+ >
+ static inline OutputIterator
+ process_turn(TurnIterator it,
+ TurnOperationIterator op_it,
+ bool& entered,
+ std::size_t& enter_count,
+ Linestring const& linestring,
+ LinestringOut& current_piece,
+ SegmentIdentifier& current_segment_id,
+ OutputIterator oit)
+ {
+ // We don't rescale linear/linear
+ detail::no_rescale_policy robust_policy;
+
+ if ( is_entering(*it, *op_it) )
+ {
+ detail::turns::debug_turn(*it, *op_it, "-> Entering");
+
+ entered = true;
+ if ( enter_count == 0 )
+ {
+ action::enter(current_piece, linestring,
+ current_segment_id,
+ op_it->seg_id.segment_index,
+ it->point, *op_it, robust_policy, oit);
+ }
+ ++enter_count;
+ }
+ else if ( is_leaving(*it, *op_it, entered) )
+ {
+ detail::turns::debug_turn(*it, *op_it, "-> Leaving");
+
+ --enter_count;
+ if ( enter_count == 0 )
+ {
+ entered = false;
+ action::leave(current_piece, linestring,
+ current_segment_id,
+ op_it->seg_id.segment_index,
+ it->point, *op_it, robust_policy, oit);
+ }
+ }
+ else if ( FollowIsolatedPoints
+ && is_isolated_point(*it, *op_it, entered) )
+ {
+ detail::turns::debug_turn(*it, *op_it, "-> Isolated point");
+
+ action::isolated_point(current_piece, linestring,
+ current_segment_id,
+ op_it->seg_id.segment_index,
+ it->point, *op_it, oit);
+ }
+ else if ( FollowContinueTurns
+ && is_staying_inside(*it, *op_it, entered) )
+ {
+ detail::turns::debug_turn(*it, *op_it, "-> Staying inside");
+
+ entered = true;
+ }
+ return oit;
+ }
+
+ template
+ <
+ typename SegmentIdentifier,
+ typename OutputIterator
+ >
+ static inline OutputIterator
+ process_end(bool entered,
+ Linestring const& linestring,
+ SegmentIdentifier const& current_segment_id,
+ LinestringOut& current_piece,
+ OutputIterator oit)
+ {
+ if ( action::is_entered(entered) )
+ {
+ // We don't rescale linear/linear
+ detail::no_rescale_policy robust_policy;
+
+ detail::copy_segments::copy_segments_linestring
+ <
+ false, false // do not reverse; do not remove spikes
+ >::apply(linestring,
+ current_segment_id,
+ static_cast<signed_index_type>(boost::size(linestring) - 1),
+ robust_policy,
+ current_piece);
+ }
+
+ // Output the last one, if applicable
+ if (::boost::size(current_piece) > 1)
+ {
+ *oit++ = current_piece;
+ }
+
+ return oit;
+ }
+
+public:
+ template <typename TurnIterator, typename OutputIterator>
+ static inline OutputIterator
+ apply(Linestring const& linestring, Linear const&,
+ TurnIterator first, TurnIterator beyond,
+ OutputIterator oit)
+ {
+ // Iterate through all intersection points (they are
+ // ordered along the each line)
+
+ LinestringOut current_piece;
+ geometry::segment_identifier current_segment_id(0, -1, -1, -1);
+
+ bool entered = false;
+ std::size_t enter_count = 0;
+
+ for (TurnIterator it = first; it != beyond; ++it)
+ {
+ oit = process_turn(it, boost::begin(it->operations),
+ entered, enter_count,
+ linestring,
+ current_piece, current_segment_id,
+ oit);
+ }
+
+ BOOST_ASSERT( enter_count == 0 );
+
+ return process_end(entered, linestring,
+ current_segment_id, current_piece,
+ oit);
+ }
+};
+
+
+
+
+template
+<
+ typename LinestringOut,
+ typename MultiLinestring,
+ typename Linear,
+ overlay_type OverlayType,
+ bool FollowIsolatedPoints,
+ bool FollowContinueTurns
+>
+class follow_multilinestring_linear_linestring
+ : follow_linestring_linear_linestring
+ <
+ LinestringOut,
+ typename boost::range_value<MultiLinestring>::type,
+ Linear,
+ OverlayType,
+ FollowIsolatedPoints,
+ FollowContinueTurns
+ >
+{
+protected:
+ typedef typename boost::range_value<MultiLinestring>::type Linestring;
+
+ typedef follow_linestring_linear_linestring
+ <
+ LinestringOut, Linestring, Linear,
+ OverlayType, FollowIsolatedPoints, FollowContinueTurns
+ > Base;
+
+ typedef following::action_selector<OverlayType> action;
+
+ typedef typename boost::range_iterator
+ <
+ MultiLinestring const
+ >::type linestring_iterator;
+
+
+ template <typename OutputIt, overlay_type OT>
+ struct copy_linestrings_in_range
+ {
+ static inline OutputIt
+ apply(linestring_iterator, linestring_iterator, OutputIt oit)
+ {
+ return oit;
+ }
+ };
+
+ template <typename OutputIt>
+ struct copy_linestrings_in_range<OutputIt, overlay_difference>
+ {
+ static inline OutputIt
+ apply(linestring_iterator first, linestring_iterator beyond,
+ OutputIt oit)
+ {
+ for (linestring_iterator ls_it = first; ls_it != beyond; ++ls_it)
+ {
+ LinestringOut line_out;
+ geometry::convert(*ls_it, line_out);
+ *oit++ = line_out;
+ }
+ return oit;
+ }
+ };
+
+ template <typename TurnIterator>
+ static inline signed_index_type get_multi_index(TurnIterator it)
+ {
+ return boost::begin(it->operations)->seg_id.multi_index;
+ }
+
+ class has_other_multi_id
+ {
+ private:
+ signed_index_type m_multi_id;
+
+ public:
+ has_other_multi_id(signed_index_type multi_id)
+ : m_multi_id(multi_id) {}
+
+ template <typename Turn>
+ bool operator()(Turn const& turn) const
+ {
+ return boost::begin(turn.operations)->seg_id.multi_index
+ != m_multi_id;
+ }
+ };
+
+public:
+ template <typename TurnIterator, typename OutputIterator>
+ static inline OutputIterator
+ apply(MultiLinestring const& multilinestring, Linear const& linear,
+ TurnIterator first, TurnIterator beyond,
+ OutputIterator oit)
+ {
+ BOOST_ASSERT( first != beyond );
+
+ typedef copy_linestrings_in_range
+ <
+ OutputIterator, OverlayType
+ > copy_linestrings;
+
+ linestring_iterator ls_first = boost::begin(multilinestring);
+ linestring_iterator ls_beyond = boost::end(multilinestring);
+
+ // Iterate through all intersection points (they are
+ // ordered along the each linestring)
+
+ signed_index_type current_multi_id = get_multi_index(first);
+
+ oit = copy_linestrings::apply(ls_first,
+ ls_first + current_multi_id,
+ oit);
+
+ TurnIterator per_ls_next = first;
+ do {
+ TurnIterator per_ls_current = per_ls_next;
+
+ // find turn with different multi-index
+ per_ls_next = std::find_if(per_ls_current, beyond,
+ has_other_multi_id(current_multi_id));
+
+ oit = Base::apply(*(ls_first + current_multi_id),
+ linear, per_ls_current, per_ls_next, oit);
+
+ signed_index_type next_multi_id(-1);
+ linestring_iterator ls_next = ls_beyond;
+ if ( per_ls_next != beyond )
+ {
+ next_multi_id = get_multi_index(per_ls_next);
+ ls_next = ls_first + next_multi_id;
+ }
+ oit = copy_linestrings::apply(ls_first + current_multi_id + 1,
+ ls_next,
+ oit);
+
+ current_multi_id = next_multi_id;
+ }
+ while ( per_ls_next != beyond );
+
+ return oit;
+ }
+};
+
+
+
+
+
+
+template
+<
+ typename LinestringOut,
+ typename Geometry1,
+ typename Geometry2,
+ overlay_type OverlayType,
+ bool FollowIsolatedPoints,
+ bool FollowContinueTurns,
+ typename TagOut = typename tag<LinestringOut>::type,
+ typename TagIn1 = typename tag<Geometry1>::type
+>
+struct follow
+ : not_implemented<LinestringOut, Geometry1>
+{};
+
+
+
+template
+<
+ typename LinestringOut,
+ typename Linestring,
+ typename Linear,
+ overlay_type OverlayType,
+ bool FollowIsolatedPoints,
+ bool FollowContinueTurns
+>
+struct follow
+ <
+ LinestringOut, Linestring, Linear,
+ OverlayType, FollowIsolatedPoints, FollowContinueTurns,
+ linestring_tag, linestring_tag
+ > : follow_linestring_linear_linestring
+ <
+ LinestringOut, Linestring, Linear,
+ OverlayType, FollowIsolatedPoints, FollowContinueTurns
+ >
+{};
+
+
+template
+<
+ typename LinestringOut,
+ typename MultiLinestring,
+ typename Linear,
+ overlay_type OverlayType,
+ bool FollowIsolatedPoints,
+ bool FollowContinueTurns
+>
+struct follow
+ <
+ LinestringOut, MultiLinestring, Linear,
+ OverlayType, FollowIsolatedPoints, FollowContinueTurns,
+ linestring_tag, multi_linestring_tag
+ > : follow_multilinestring_linear_linestring
+ <
+ LinestringOut, MultiLinestring, Linear,
+ OverlayType, FollowIsolatedPoints, FollowContinueTurns
+ >
+{};
+
+
+
+}} // namespace following::linear
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_LINEAR_LINEAR_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp b/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp
index 019c3ba3f9..63011c7d48 100644
--- a/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp
+++ b/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp
@@ -17,6 +17,7 @@
#include <boost/geometry/geometries/segment.hpp>
+#include <boost/geometry/policies/robustness/robust_point_type.hpp>
namespace boost { namespace geometry
{
@@ -35,32 +36,45 @@ template
>
struct get_turn_without_info
{
- typedef strategy_intersection
- <
- typename cs_tag<typename TurnInfo::point_type>::type,
- Point1,
- Point2,
- typename TurnInfo::point_type
- > si;
-
- typedef typename si::segment_intersection_strategy_type strategy;
-
-
-
- template <typename OutputIterator>
+ template <typename RobustPolicy, typename OutputIterator>
static inline OutputIterator apply(
- Point1 const& pi, Point1 const& pj, Point1 const& pk,
- Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ Point1 const& pi, Point1 const& pj, Point1 const& /*pk*/,
+ Point2 const& qi, Point2 const& qj, Point2 const& /*qk*/,
+ bool /*is_p_first*/, bool /*is_p_last*/,
+ bool /*is_q_first*/, bool /*is_q_last*/,
TurnInfo const& ,
+ RobustPolicy const& robust_policy,
OutputIterator out)
{
+ typedef strategy_intersection
+ <
+ typename cs_tag<typename TurnInfo::point_type>::type,
+ Point1,
+ Point2,
+ typename TurnInfo::point_type,
+ RobustPolicy
+ > si;
+
+ typedef typename si::segment_intersection_strategy_type strategy;
+
typedef model::referring_segment<Point1 const> segment_type1;
typedef model::referring_segment<Point1 const> segment_type2;
- segment_type1 p1(pi, pj), p2(pj, pk);
- segment_type2 q1(qi, qj), q2(qj, qk);
+ segment_type1 p1(pi, pj);
+ segment_type2 q1(qi, qj);
- //
- typename strategy::return_type result = strategy::apply(p1, q1);
+ typedef typename geometry::robust_point_type
+ <
+ Point1, RobustPolicy
+ >::type robust_point_type;
+
+ robust_point_type pi_rob, pj_rob, qi_rob, qj_rob;
+ geometry::recalculate(pi_rob, pi, robust_policy);
+ geometry::recalculate(pj_rob, pj, robust_policy);
+ geometry::recalculate(qi_rob, qi, robust_policy);
+ geometry::recalculate(qj_rob, qj, robust_policy);
+ typename strategy::return_type result
+ = strategy::apply(p1, q1, robust_policy,
+ pi_rob, pj_rob, qi_rob, qj_rob);
for (std::size_t i = 0; i < result.template get<0>().count; i++)
{
@@ -84,10 +98,12 @@ template
<
typename Geometry1,
typename Geometry2,
+ typename RobustPolicy,
typename Turns
>
inline void get_intersection_points(Geometry1 const& geometry1,
Geometry2 const& geometry2,
+ RobustPolicy const& robust_policy,
Turns& turns)
{
concept::check_concepts_and_equal_dimensions<Geometry1 const, Geometry2 const>();
@@ -99,14 +115,6 @@ inline void get_intersection_points(Geometry1 const& geometry1,
typename boost::range_value<Turns>::type
> TurnPolicy;
- typedef typename strategy_intersection
- <
- typename cs_tag<Geometry1>::type,
- Geometry1,
- Geometry2,
- typename boost::range_value<Turns>::type
- >::segment_intersection_strategy_type segment_intersection_strategy_type;
-
detail::get_turns::no_interrupt_policy interrupt_policy;
boost::mpl::if_c
@@ -118,9 +126,7 @@ inline void get_intersection_points(Geometry1 const& geometry1,
typename tag<Geometry2>::type,
Geometry1, Geometry2,
false, false,
- Turns, TurnPolicy,
- //segment_intersection_strategy_type,
- detail::get_turns::no_interrupt_policy
+ TurnPolicy
>,
dispatch::get_turns
<
@@ -128,13 +134,12 @@ inline void get_intersection_points(Geometry1 const& geometry1,
typename tag<Geometry2>::type,
Geometry1, Geometry2,
false, false,
- Turns, TurnPolicy,
- //segment_intersection_strategy_type,
- detail::get_turns::no_interrupt_policy
+ TurnPolicy
>
>::type::apply(
0, geometry1,
1, geometry2,
+ robust_policy,
turns, interrupt_policy);
}
diff --git a/boost/geometry/algorithms/detail/overlay/get_relative_order.hpp b/boost/geometry/algorithms/detail/overlay/get_relative_order.hpp
index 522ef68382..d71f4ad51f 100644
--- a/boost/geometry/algorithms/detail/overlay/get_relative_order.hpp
+++ b/boost/geometry/algorithms/detail/overlay/get_relative_order.hpp
@@ -10,8 +10,6 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_RELATIVE_ORDER_HPP
-#include <boost/geometry/algorithms/distance.hpp>
-
#include <boost/geometry/strategies/intersection.hpp>
@@ -36,15 +34,10 @@ namespace detail { namespace overlay
template <typename Point1>
struct get_relative_order
{
- typedef strategy_intersection
+ typedef typename strategy::side::services::default_strategy
<
- typename cs_tag<Point1>::type,
- Point1,
- Point1,
- Point1
- > si;
-
- typedef typename si::side_strategy_type strategy;
+ typename cs_tag<Point1>::type
+ >::type strategy;
template <typename Point>
static inline int value_via_product(Point const& ti, Point const& tj,
diff --git a/boost/geometry/algorithms/detail/overlay/get_ring.hpp b/boost/geometry/algorithms/detail/overlay/get_ring.hpp
index c2c6980577..131d58d582 100644
--- a/boost/geometry/algorithms/detail/overlay/get_ring.hpp
+++ b/boost/geometry/algorithms/detail/overlay/get_ring.hpp
@@ -13,11 +13,13 @@
#include <boost/assert.hpp>
#include <boost/range.hpp>
-
-#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/core/ring_type.hpp>
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
+#include <boost/geometry/geometries/concepts/check.hpp>
+#include <boost/geometry/util/range.hpp>
namespace boost { namespace geometry
@@ -33,16 +35,16 @@ template<typename Tag>
struct get_ring
{};
-// A container of rings (multi-ring but that does not exist)
+// A range of rings (multi-ring but that does not exist)
// gets the "void" tag and is dispatched here.
template<>
struct get_ring<void>
{
- template<typename Container>
- static inline typename boost::range_value<Container>::type const&
- apply(ring_identifier const& id, Container const& container)
+ template<typename Range>
+ static inline typename boost::range_value<Range>::type const&
+ apply(ring_identifier const& id, Range const& container)
{
- return container[id.multi_index];
+ return range::at(container, id.multi_index);
}
};
@@ -87,7 +89,26 @@ struct get_ring<polygon_tag>
);
return id.ring_index < 0
? exterior_ring(polygon)
- : interior_rings(polygon)[id.ring_index];
+ : range::at(interior_rings(polygon), id.ring_index);
+ }
+};
+
+
+template<>
+struct get_ring<multi_polygon_tag>
+{
+ template<typename MultiPolygon>
+ static inline typename ring_type<MultiPolygon>::type const& apply(
+ ring_identifier const& id,
+ MultiPolygon const& multi_polygon)
+ {
+ BOOST_ASSERT
+ (
+ id.multi_index >= 0
+ && id.multi_index < int(boost::size(multi_polygon))
+ );
+ return get_ring<polygon_tag>::apply(id,
+ range::at(multi_polygon, id.multi_index));
}
};
diff --git a/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp
index b8320d9b7b..240b6de036 100644
--- a/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp
+++ b/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp
@@ -16,9 +16,19 @@
#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+#include <boost/geometry/algorithms/detail/recalculate.hpp>
#include <boost/geometry/geometries/segment.hpp>
+#include <boost/geometry/policies/robustness/robust_point_type.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp>
+
+// Silence warning C4127: conditional expression is constant
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4127)
+#endif
+
namespace boost { namespace geometry
{
@@ -30,7 +40,7 @@ class turn_info_exception : public geometry::exception
public:
// NOTE: "char" will be replaced by enum in future version
- inline turn_info_exception(char const method)
+ inline turn_info_exception(char const method)
{
message = "Boost.Geometry Turn exception: ";
message += method;
@@ -50,7 +60,6 @@ public:
namespace detail { namespace overlay
{
-
struct base_turn_handler
{
// Returns true if both sides are opposite
@@ -91,13 +100,32 @@ struct base_turn_handler
{
both(ti, condition ? operation_union : operation_intersection);
}
+
+ template <typename TurnInfo, typename IntersectionInfo>
+ static inline void assign_point(TurnInfo& ti,
+ method_type method,
+ IntersectionInfo const& info, int index)
+ {
+ ti.method = method;
+ BOOST_ASSERT(index >= 0 && unsigned(index) < info.count); // TODO remove this
+ geometry::convert(info.intersections[index], ti.point);
+ ti.operations[0].fraction = info.fractions[index].robust_ra;
+ ti.operations[1].fraction = info.fractions[index].robust_rb;
+ }
+
+ template <typename IntersectionInfo>
+ static inline int non_opposite_to_index(IntersectionInfo const& info)
+ {
+ return info.fractions[0].robust_rb < info.fractions[1].robust_rb
+ ? 1 : 0;
+ }
+
};
template
<
- typename TurnInfo,
- typename SideStrategy
+ typename TurnInfo
>
struct touch_interior : public base_turn_handler
{
@@ -108,17 +136,18 @@ struct touch_interior : public base_turn_handler
typename Point1,
typename Point2,
typename IntersectionInfo,
- typename DirInfo
+ typename DirInfo,
+ typename SidePolicy
>
static inline void apply(
- Point1 const& pi, Point1 const& pj, Point1 const& ,
- Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ Point1 const& , Point1 const& , Point1 const& ,
+ Point2 const& , Point2 const& , Point2 const& ,
TurnInfo& ti,
IntersectionInfo const& intersection_info,
- DirInfo const& dir_info)
+ DirInfo const& dir_info,
+ SidePolicy const& side)
{
- ti.method = method_touch_interior;
- geometry::convert(intersection_info.intersections[0], ti.point);
+ assign_point(ti, method_touch_interior, intersection_info, 0);
// Both segments of q touch segment p somewhere in its interior
// 1) We know: if q comes from LEFT or RIGHT
@@ -130,7 +159,7 @@ struct touch_interior : public base_turn_handler
static int const index_q = 1 - Index;
int const side_qi_p = dir_info.sides.template get<index_q, 0>();
- int const side_qk_p = SideStrategy::apply(pi, pj, qk);
+ int const side_qk_p = side.qk_wrt_p1();
if (side_qi_p == -side_qk_p)
{
@@ -143,7 +172,7 @@ struct touch_interior : public base_turn_handler
return;
}
- int const side_qk_q = SideStrategy::apply(qi, qj, qk);
+ int const side_qk_q = side.qk_wrt_q1();
if (side_qi_p == -1 && side_qk_p == -1 && side_qk_q == 1)
{
@@ -203,8 +232,7 @@ struct touch_interior : public base_turn_handler
template
<
- typename TurnInfo,
- typename SideStrategy
+ typename TurnInfo
>
struct touch : public base_turn_handler
{
@@ -227,37 +255,34 @@ struct touch : public base_turn_handler
typename Point1,
typename Point2,
typename IntersectionInfo,
- typename DirInfo
+ typename DirInfo,
+ typename SidePolicy
>
static inline void apply(
- Point1 const& pi, Point1 const& pj, Point1 const& pk,
- Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ Point1 const& , Point1 const& , Point1 const& ,
+ Point2 const& , Point2 const& , Point2 const& ,
TurnInfo& ti,
IntersectionInfo const& intersection_info,
- DirInfo const& dir_info)
+ DirInfo const& dir_info,
+ SidePolicy const& side)
{
- ti.method = method_touch;
- geometry::convert(intersection_info.intersections[0], ti.point);
+ assign_point(ti, method_touch, intersection_info, 0);
int const side_qi_p1 = dir_info.sides.template get<1, 0>();
- int const side_qk_p1 = SideStrategy::apply(pi, pj, qk);
+ int const side_qk_p1 = side.qk_wrt_p1();
// If Qi and Qk are both at same side of Pi-Pj,
// or collinear (so: not opposite sides)
if (! opposite(side_qi_p1, side_qk_p1))
{
- int const side_pk_q2 = SideStrategy::apply(qj, qk, pk);
- int const side_pk_p = SideStrategy::apply(pi, pj, pk);
- int const side_qk_q = SideStrategy::apply(qi, qj, qk);
-
- bool const both_continue = side_pk_p == 0 && side_qk_q == 0;
- bool const robustness_issue_in_continue = both_continue && side_pk_q2 != 0;
+ int const side_pk_q2 = side.pk_wrt_q2();
+ int const side_pk_p = side.pk_wrt_p1();
+ int const side_qk_q = side.qk_wrt_q1();
bool const q_turns_left = side_qk_q == 1;
bool const block_q = side_qk_p1 == 0
&& ! same(side_qi_p1, side_qk_q)
- && ! robustness_issue_in_continue
;
// If Pk at same side as Qi/Qk
@@ -276,7 +301,7 @@ struct touch : public base_turn_handler
return;
}
- int const side_pk_q1 = SideStrategy::apply(qi, qj, pk);
+ int const side_pk_q1 = side.pk_wrt_q1();
// Collinear opposite case -> block P
@@ -329,9 +354,6 @@ struct touch : public base_turn_handler
else
{
// Pk at other side than Qi/Pk
- int const side_qk_q = SideStrategy::apply(qi, qj, qk);
- bool const q_turns_left = side_qk_q == 1;
-
ti.operations[0].operation = q_turns_left
? operation_intersection
: operation_union;
@@ -347,13 +369,13 @@ struct touch : public base_turn_handler
else
{
// From left to right or from right to left
- int const side_pk_p = SideStrategy::apply(pi, pj, pk);
+ int const side_pk_p = side.pk_wrt_p1();
bool const right_to_left = side_qk_p1 == 1;
// If p turns into direction of qi (1,2)
if (side_pk_p == side_qi_p1)
{
- int const side_pk_q1 = SideStrategy::apply(qi, qj, pk);
+ int const side_pk_q1 = side.pk_wrt_q1();
// Collinear opposite case -> block P
if (side_pk_q1 == 0)
@@ -374,7 +396,7 @@ struct touch : public base_turn_handler
// If p turns into direction of qk (4,5)
if (side_pk_p == side_qk_p1)
{
- int const side_pk_q2 = SideStrategy::apply(qj, qk, pk);
+ int const side_pk_q2 = side.pk_wrt_q2();
// Collinear case -> lines join, continue
if (side_pk_q2 == 0)
@@ -413,8 +435,7 @@ struct touch : public base_turn_handler
template
<
- typename TurnInfo,
- typename SideStrategy
+ typename TurnInfo
>
struct equal : public base_turn_handler
{
@@ -423,22 +444,24 @@ struct equal : public base_turn_handler
typename Point1,
typename Point2,
typename IntersectionInfo,
- typename DirInfo
+ typename DirInfo,
+ typename SidePolicy
>
static inline void apply(
- Point1 const& pi, Point1 const& pj, Point1 const& pk,
- Point2 const& , Point2 const& qj, Point2 const& qk,
+ Point1 const& , Point1 const& , Point1 const& ,
+ Point2 const& , Point2 const& , Point2 const& ,
TurnInfo& ti,
- IntersectionInfo const& intersection_info,
- DirInfo const& )
+ IntersectionInfo const& info,
+ DirInfo const& ,
+ SidePolicy const& side)
{
- ti.method = method_equal;
- // Copy the SECOND intersection point
- geometry::convert(intersection_info.intersections[1], ti.point);
+ // Copy the intersection point in TO direction
+ assign_point(ti, method_equal, info, non_opposite_to_index(info));
+
+ int const side_pk_q2 = side.pk_wrt_q2();
+ int const side_pk_p = side.pk_wrt_p1();
+ int const side_qk_p = side.qk_wrt_p1();
- int const side_pk_q2 = SideStrategy::apply(qj, qk, pk);
- int const side_pk_p = SideStrategy::apply(pi, pj, pk);
- int const side_qk_p = SideStrategy::apply(pi, pj, qk);
// If pk is collinear with qj-qk, they continue collinearly.
// This can be on either side of p1 (== q1), or collinear
@@ -447,6 +470,7 @@ struct equal : public base_turn_handler
if (side_pk_q2 == 0 && side_pk_p == side_qk_p)
{
both(ti, operation_continue);
+
return;
}
@@ -454,8 +478,6 @@ struct equal : public base_turn_handler
// If they turn to same side (not opposite sides)
if (! opposite(side_pk_p, side_qk_p))
{
- int const side_pk_q2 = SideStrategy::apply(qj, qk, pk);
-
// If pk is left of q2 or collinear: p: union, q: intersection
ui_else_iu(side_pk_q2 != -1, ti);
}
@@ -485,33 +507,32 @@ struct equal_opposite : public base_turn_handler
typename DirInfo
>
static inline void apply(Point1 const& pi, Point2 const& qi,
- /* by value: */ TurnInfo tp,
+ /* by value: */ TurnInfo tp,
OutputIterator& out,
IntersectionInfo const& intersection_info,
DirInfo const& dir_info)
{
// For equal-opposite segments, normally don't do anything.
- if (AssignPolicy::include_opposite)
- {
- tp.method = method_equal;
- for (int i = 0; i < 2; i++)
- {
- tp.operations[i].operation = operation_opposite;
- }
- for (unsigned int i = 0; i < intersection_info.count; i++)
- {
- geometry::convert(intersection_info.intersections[i], tp.point);
- AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info);
- *out++ = tp;
- }
- }
+ if (AssignPolicy::include_opposite)
+ {
+ tp.method = method_equal;
+ for (int i = 0; i < 2; i++)
+ {
+ tp.operations[i].operation = operation_opposite;
+ }
+ for (unsigned int i = 0; i < intersection_info.count; i++)
+ {
+ assign_point(tp, method_none, intersection_info, i);
+ AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info);
+ *out++ = tp;
+ }
+ }
}
};
template
<
- typename TurnInfo,
- typename SideStrategy
+ typename TurnInfo
>
struct collinear : public base_turn_handler
{
@@ -543,7 +564,7 @@ struct collinear : public base_turn_handler
ROBUSTNESS: p and q are collinear, so you would expect
that side qk//p1 == pk//q1. But that is not always the case
in near-epsilon ranges. Then decision logic is different.
- If p arrives, q is further, so the angle qk//p1 is (normally)
+ If p arrives, q is further, so the angle qk//p1 is (normally)
more precise than pk//p1
*/
@@ -552,24 +573,26 @@ struct collinear : public base_turn_handler
typename Point1,
typename Point2,
typename IntersectionInfo,
- typename DirInfo
+ typename DirInfo,
+ typename SidePolicy
>
static inline void apply(
- Point1 const& pi, Point1 const& pj, Point1 const& pk,
- Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ Point1 const& , Point1 const& , Point1 const& ,
+ Point2 const& , Point2 const& , Point2 const& ,
TurnInfo& ti,
- IntersectionInfo const& intersection_info,
- DirInfo const& dir_info)
+ IntersectionInfo const& info,
+ DirInfo const& dir_info,
+ SidePolicy const& side)
{
- ti.method = method_collinear;
- geometry::convert(intersection_info.intersections[1], ti.point);
+ // Copy the intersection point in TO direction
+ assign_point(ti, method_collinear, info, non_opposite_to_index(info));
int const arrival = dir_info.arrival[0];
// Should not be 0, this is checked before
BOOST_ASSERT(arrival != 0);
- int const side_p = SideStrategy::apply(pi, pj, pk);
- int const side_q = SideStrategy::apply(qi, qj, qk);
+ int const side_p = side.pk_wrt_p1();
+ int const side_q = side.qk_wrt_q1();
// If p arrives, use p, else use q
int const side_p_or_q = arrival == 1
@@ -577,9 +600,6 @@ struct collinear : public base_turn_handler
: side_q
;
- int const side_pk = SideStrategy::apply(qi, qj, pk);
- int const side_qk = SideStrategy::apply(pi, pj, qk);
-
// See comments above,
// resulting in a strange sort of mathematic rule here:
// The arrival-info multiplied by the relevant side
@@ -587,15 +607,7 @@ struct collinear : public base_turn_handler
int const product = arrival * side_p_or_q;
- // Robustness: side_p is supposed to be equal to side_pk (because p/q are collinear)
- // and side_q to side_qk
- bool const robustness_issue = side_pk != side_p || side_qk != side_q;
-
- if (robustness_issue)
- {
- handle_robustness(ti, arrival, side_p, side_q, side_pk, side_qk);
- }
- else if(product == 0)
+ if(product == 0)
{
both(ti, operation_continue);
}
@@ -605,43 +617,11 @@ struct collinear : public base_turn_handler
}
}
- static inline void handle_robustness(TurnInfo& ti, int arrival,
- int side_p, int side_q, int side_pk, int side_qk)
- {
- // We take the longer one, i.e. if q arrives in p (arrival == -1),
- // then p exceeds q and we should take p for a union...
-
- bool use_p_for_union = arrival == -1;
-
- // ... unless one of the sides consistently directs to the other side
- int const consistent_side_p = side_p == side_pk ? side_p : 0;
- int const consistent_side_q = side_q == side_qk ? side_q : 0;
- if (arrival == -1 && (consistent_side_p == -1 || consistent_side_q == 1))
- {
- use_p_for_union = false;
- }
- if (arrival == 1 && (consistent_side_p == 1 || consistent_side_q == -1))
- {
- use_p_for_union = true;
- }
-
- //std::cout << "ROBUSTNESS -> Collinear "
- // << " arr: " << arrival
- // << " dir: " << side_p << " " << side_q
- // << " rev: " << side_pk << " " << side_qk
- // << " cst: " << cside_p << " " << cside_q
- // << std::boolalpha << " " << use_p_for_union
- // << std::endl;
-
- ui_else_iu(use_p_for_union, ti);
- }
-
};
template
<
typename TurnInfo,
- typename SideStrategy,
typename AssignPolicy
>
struct collinear_opposite : public base_turn_handler
@@ -674,14 +654,19 @@ private :
template
<
int Index,
- typename Point,
+ typename Point1,
+ typename Point2,
typename IntersectionInfo
>
- static inline bool set_tp(Point const& ri, Point const& rj, Point const& rk,
+ static inline bool set_tp(Point1 const& , Point1 const& , Point1 const& , int side_rk_r,
+ bool const handle_robustness,
+ Point2 const& , Point2 const& , int side_rk_s,
TurnInfo& tp, IntersectionInfo const& intersection_info)
{
- int const side_rk_r = SideStrategy::apply(ri, rj, rk);
- operation_type blocked = operation_blocked;
+ boost::ignore_unused_variable_warning(handle_robustness);
+ boost::ignore_unused_variable_warning(side_rk_s);
+
+ operation_type blocked = operation_blocked;
switch(side_rk_r)
{
@@ -699,16 +684,16 @@ private :
// two operations blocked, so the whole point does not need
// to be generated.
// So return false to indicate nothing is to be done.
- if (AssignPolicy::include_opposite)
- {
- tp.operations[Index].operation = operation_opposite;
- blocked = operation_opposite;
- }
- else
- {
- return false;
- }
- break;
+ if (AssignPolicy::include_opposite)
+ {
+ tp.operations[Index].operation = operation_opposite;
+ blocked = operation_opposite;
+ }
+ else
+ {
+ return false;
+ }
+ break;
}
// The other direction is always blocked when collinear opposite
@@ -717,18 +702,21 @@ private :
// If P arrives within Q, set info on P (which is done above, index=0),
// this turn-info belongs to the second intersection point, index=1
// (see e.g. figure CLO1)
- geometry::convert(intersection_info.intersections[1 - Index], tp.point);
+ assign_point(tp, method_collinear, intersection_info, 1 - Index);
return true;
}
public:
+ static inline void empty_transformer(TurnInfo &) {}
+
template
<
typename Point1,
typename Point2,
typename OutputIterator,
typename IntersectionInfo,
- typename DirInfo
+ typename DirInfo,
+ typename SidePolicy
>
static inline void apply(
Point1 const& pi, Point1 const& pj, Point1 const& pk,
@@ -739,46 +727,79 @@ public:
OutputIterator& out,
IntersectionInfo const& intersection_info,
- DirInfo const& dir_info)
+ DirInfo const& dir_info,
+ SidePolicy const& side)
{
- TurnInfo tp = tp_model;
+ apply(pi, pj, pk, qi, qj, qk, tp_model, out, intersection_info, dir_info, side, empty_transformer);
+ }
- tp.method = method_collinear;
+public:
+ template
+ <
+ typename Point1,
+ typename Point2,
+ typename OutputIterator,
+ typename IntersectionInfo,
+ typename DirInfo,
+ typename SidePolicy,
+ typename TurnTransformer
+ >
+ static inline void apply(
+ Point1 const& pi, Point1 const& pj, Point1 const& pk,
+ Point2 const& qi, Point2 const& qj, Point2 const& qk,
+
+ // Opposite collinear can deliver 2 intersection points,
+ TurnInfo const& tp_model,
+ OutputIterator& out,
+
+ IntersectionInfo const& intersection_info,
+ DirInfo const& dir_info,
+ SidePolicy const& side,
+ TurnTransformer turn_transformer,
+ bool const is_pk_valid = true, bool const is_qk_valid = true)
+ {
+ TurnInfo tp = tp_model;
// If P arrives within Q, there is a turn dependent on P
- if (dir_info.arrival[0] == 1
- && set_tp<0>(pi, pj, pk, tp, intersection_info))
+ if ( dir_info.arrival[0] == 1
+ && is_pk_valid
+ && set_tp<0>(pi, pj, pk, side.pk_wrt_p1(), true, qi, qj, side.pk_wrt_q1(), tp, intersection_info) )
{
+ turn_transformer(tp);
+
AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info);
*out++ = tp;
}
// If Q arrives within P, there is a turn dependent on Q
- if (dir_info.arrival[1] == 1
- && set_tp<1>(qi, qj, qk, tp, intersection_info))
+ if ( dir_info.arrival[1] == 1
+ && is_qk_valid
+ && set_tp<1>(qi, qj, qk, side.qk_wrt_q1(), false, pi, pj, side.qk_wrt_p1(), tp, intersection_info) )
{
+ turn_transformer(tp);
+
AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info);
*out++ = tp;
}
- if (AssignPolicy::include_opposite)
- {
- // Handle cases not yet handled above
- if ((dir_info.arrival[1] == -1 && dir_info.arrival[0] == 0)
- || (dir_info.arrival[0] == -1 && dir_info.arrival[1] == 0))
- {
- for (int i = 0; i < 2; i++)
- {
- tp.operations[i].operation = operation_opposite;
- }
- for (unsigned int i = 0; i < intersection_info.count; i++)
- {
- geometry::convert(intersection_info.intersections[i], tp.point);
- AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info);
- *out++ = tp;
- }
- }
- }
+ if (AssignPolicy::include_opposite)
+ {
+ // Handle cases not yet handled above
+ if ((dir_info.arrival[1] == -1 && dir_info.arrival[0] == 0)
+ || (dir_info.arrival[0] == -1 && dir_info.arrival[1] == 0))
+ {
+ for (int i = 0; i < 2; i++)
+ {
+ tp.operations[i].operation = operation_opposite;
+ }
+ for (unsigned int i = 0; i < intersection_info.count; i++)
+ {
+ assign_point(tp, method_collinear, intersection_info, i);
+ AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info);
+ *out++ = tp;
+ }
+ }
+ }
}
};
@@ -786,8 +807,7 @@ public:
template
<
- typename TurnInfo,
- typename SideStrategy
+ typename TurnInfo
>
struct crosses : public base_turn_handler
{
@@ -805,8 +825,7 @@ struct crosses : public base_turn_handler
IntersectionInfo const& intersection_info,
DirInfo const& dir_info)
{
- ti.method = method_crosses;
- geometry::convert(intersection_info.intersections[0], ti.point);
+ assign_point(ti, method_crosses, intersection_info, 0);
// In all casees:
// If Q crosses P from left to right
@@ -820,14 +839,12 @@ struct crosses : public base_turn_handler
}
};
-template<typename TurnInfo>
-struct only_convert
+struct only_convert : public base_turn_handler
{
- template<typename IntersectionInfo>
+ template<typename TurnInfo, typename IntersectionInfo>
static inline void apply(TurnInfo& ti, IntersectionInfo const& intersection_info)
{
- ti.method = method_collinear;
- geometry::convert(intersection_info.intersections[0], ti.point);
+ assign_point(ti, method_none, intersection_info, 0); // was collinear
ti.operations[0].operation = operation_continue;
ti.operations[1].operation = operation_continue;
}
@@ -845,14 +862,14 @@ struct assign_null_policy
static bool const include_degenerate = false;
static bool const include_opposite = false;
- template
- <
- typename Info,
- typename Point1,
- typename Point2,
- typename IntersectionInfo,
- typename DirInfo
- >
+ template
+ <
+ typename Info,
+ typename Point1,
+ typename Point2,
+ typename IntersectionInfo,
+ typename DirInfo
+ >
static inline void apply(Info& , Point1 const& , Point2 const&, IntersectionInfo const&, DirInfo const&)
{}
@@ -873,48 +890,39 @@ struct assign_null_policy
It also defines if a certain class of points
(degenerate, non-turns) should be included.
*/
-template
-<
- typename Point1,
- typename Point2,
- typename TurnInfo,
- typename AssignPolicy
->
+template<typename AssignPolicy>
struct get_turn_info
{
- typedef strategy_intersection
- <
- typename cs_tag<typename TurnInfo::point_type>::type,
- Point1,
- Point2,
- typename TurnInfo::point_type
- > si;
-
- typedef typename si::segment_intersection_strategy_type strategy;
-
// Intersect pi-pj with qi-qj
- // The points pk and qk are only used do determine more information
- // about the turn.
- template <typename OutputIterator>
+ // The points pk and qk are used do determine more information
+ // about the turn (turn left/right)
+ template
+ <
+ typename Point1,
+ typename Point2,
+ typename TurnInfo,
+ typename RobustPolicy,
+ typename OutputIterator
+ >
static inline OutputIterator apply(
Point1 const& pi, Point1 const& pj, Point1 const& pk,
Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ bool /*is_p_first*/, bool /*is_p_last*/,
+ bool /*is_q_first*/, bool /*is_q_last*/,
TurnInfo const& tp_model,
+ RobustPolicy const& robust_policy,
OutputIterator out)
{
- typedef model::referring_segment<Point1 const> segment_type1;
- typedef model::referring_segment<Point1 const> segment_type2;
- segment_type1 p1(pi, pj), p2(pj, pk);
- segment_type2 q1(qi, qj), q2(qj, qk);
+ typedef intersection_info<Point1, Point2, typename TurnInfo::point_type, RobustPolicy>
+ inters_info;
- typename strategy::return_type result = strategy::apply(p1, q1);
+ inters_info inters(pi, pj, pk, qi, qj, qk, robust_policy);
- char const method = result.template get<1>().how;
+ char const method = inters.d_info().how;
// Copy, to copy possibly extended fields
TurnInfo tp = tp_model;
-
// Select method and apply
switch(method)
{
@@ -922,11 +930,10 @@ struct get_turn_info
case 'f' : // collinear, "from"
case 's' : // starts from the middle
if (AssignPolicy::include_no_turn
- && result.template get<0>().count > 0)
+ && inters.i_info().count > 0)
{
- only_convert<TurnInfo>::apply(tp,
- result.template get<0>());
- AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
+ only_convert::apply(tp, inters.i_info());
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
*out++ = tp;
}
break;
@@ -938,113 +945,94 @@ struct get_turn_info
{
typedef touch_interior
<
- TurnInfo,
- typename si::side_strategy_type
+ TurnInfo
> policy;
// If Q (1) arrives (1)
- if (result.template get<1>().arrival[1] == 1)
+ if ( inters.d_info().arrival[1] == 1 )
{
policy::template apply<0>(pi, pj, pk, qi, qj, qk,
- tp, result.template get<0>(), result.template get<1>());
+ tp, inters.i_info(), inters.d_info(),
+ inters.sides());
}
else
{
// Swap p/q
+ side_calculator
+ <
+ typename inters_info::robust_point2_type,
+ typename inters_info::robust_point1_type
+ > swapped_side_calc(inters.rqi(), inters.rqj(), inters.rqk(),
+ inters.rpi(), inters.rpj(), inters.rpk());
policy::template apply<1>(qi, qj, qk, pi, pj, pk,
- tp, result.template get<0>(), result.template get<1>());
+ tp, inters.i_info(), inters.d_info(),
+ swapped_side_calc);
}
- AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
*out++ = tp;
}
break;
case 'i' :
{
- typedef crosses
- <
- TurnInfo,
- typename si::side_strategy_type
- > policy;
-
- policy::apply(pi, pj, pk, qi, qj, qk,
- tp, result.template get<0>(), result.template get<1>());
- AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
+ crosses<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info());
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
*out++ = tp;
}
break;
case 't' :
{
// Both touch (both arrive there)
- typedef touch
- <
- TurnInfo,
- typename si::side_strategy_type
- > policy;
-
- policy::apply(pi, pj, pk, qi, qj, qk,
- tp, result.template get<0>(), result.template get<1>());
- AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
+ touch<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(), inters.sides());
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
*out++ = tp;
}
break;
case 'e':
{
- if (! result.template get<1>().opposite)
+ if ( ! inters.d_info().opposite )
{
// Both equal
// or collinear-and-ending at intersection point
- typedef equal
- <
- TurnInfo,
- typename si::side_strategy_type
- > policy;
-
- policy::apply(pi, pj, pk, qi, qj, qk,
- tp, result.template get<0>(), result.template get<1>());
- AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
+ equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(), inters.sides());
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
*out++ = tp;
}
- else
- {
+ else
+ {
equal_opposite
<
TurnInfo,
AssignPolicy
>::apply(pi, qi,
- tp, out, result.template get<0>(), result.template get<1>());
- }
+ tp, out, inters.i_info(), inters.d_info());
+ }
}
break;
case 'c' :
{
// Collinear
- if (! result.template get<1>().opposite)
+ if ( ! inters.d_info().opposite )
{
- if (result.template get<1>().arrival[0] == 0)
+ if ( inters.d_info().arrival[0] == 0 )
{
// Collinear, but similar thus handled as equal
- equal
- <
- TurnInfo,
- typename si::side_strategy_type
- >::apply(pi, pj, pk, qi, qj, qk,
- tp, result.template get<0>(), result.template get<1>());
+ equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(), inters.sides());
// override assigned method
tp.method = method_collinear;
}
else
{
- collinear
- <
- TurnInfo,
- typename si::side_strategy_type
- >::apply(pi, pj, pk, qi, qj, qk,
- tp, result.template get<0>(), result.template get<1>());
+ collinear<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(), inters.sides());
}
- AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
*out++ = tp;
}
else
@@ -1052,10 +1040,9 @@ struct get_turn_info
collinear_opposite
<
TurnInfo,
- typename si::side_strategy_type,
AssignPolicy
>::apply(pi, pj, pk, qi, qj, qk,
- tp, out, result.template get<0>(), result.template get<1>());
+ tp, out, inters.i_info(), inters.d_info(), inters.sides());
}
}
break;
@@ -1064,14 +1051,17 @@ struct get_turn_info
// degenerate points
if (AssignPolicy::include_degenerate)
{
- only_convert<TurnInfo>::apply(tp, result.template get<0>());
- AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
+ only_convert::apply(tp, inters.i_info());
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
*out++ = tp;
}
}
break;
default :
{
+#if defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS)
+ std::cout << "TURN: Unknown method: " << method << std::endl;
+#endif
#if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW)
throw turn_info_exception(method);
#endif
@@ -1091,4 +1081,8 @@ struct get_turn_info
}} // namespace boost::geometry
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp
new file mode 100644
index 0000000000..ca1b9d9d0c
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp
@@ -0,0 +1,657 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates.
+
+// 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)
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_FOR_ENDPOINT_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_FOR_ENDPOINT_HPP
+
+#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
+#include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
+
+namespace boost { namespace geometry {
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay {
+
+// SEGMENT_INTERSECTION RESULT
+
+// C H0 H1 A0 A1 O IP1 IP2
+
+// D0 and D1 == 0
+
+// |--------> 2 0 0 0 0 F i/i x/x
+// |-------->
+//
+// |--------> 2 0 0 0 0 T i/x x/i
+// <--------|
+//
+// |-----> 1 0 0 0 0 T x/x
+// <-----|
+//
+
+// |---------> 2 0 0 0 1 T i/x x/i
+// <----|
+//
+// |---------> 2 0 0 0 0 F i/i x/x
+// |---->
+//
+// |---------> 2 0 0 -1 1 F i/i u/x
+// |---->
+//
+// |---------> 2 0 0 -1 0 T i/x u/i
+// <----|
+
+// |-------> 2 0 0 1 -1 F and i/i x/u
+// |-------> 2 0 0 -1 1 F symetric i/i u/x
+// |------->
+//
+// |-------> 2 0 0 -1 -1 T i/u u/i
+// <-------|
+//
+// |-------> 2 0 0 1 1 T i/x x/i
+// <-------|
+//
+// |--------> 2 0 0 -1 1 F i/i u/x
+// |---->
+//
+// |--------> 2 0 0 -1 1 T i/x u/i
+// <----|
+
+// |-----> 1 -1 -1 -1 -1 T u/u
+// <-----|
+//
+// |-----> 1 -1 0 -1 0 F and u/x
+// |-----> 1 0 -1 0 -1 F symetric x/u
+// |----->
+
+// D0 or D1 != 0
+
+// ^
+// |
+// + 1 -1 1 -1 1 F and u/x (P is vertical)
+// |--------> 1 1 -1 1 -1 F symetric x/u (P is horizontal)
+// ^
+// |
+// +
+//
+// +
+// |
+// v
+// |--------> 1 1 1 1 1 F x/x (P is vertical)
+//
+// ^
+// |
+// +
+// |--------> 1 -1 -1 -1 -1 F u/u (P is vertical)
+//
+// ^
+// |
+// +
+// |--------> 1 0 -1 0 -1 F u/u (P is vertical)
+//
+// +
+// |
+// v
+// |--------> 1 0 1 0 1 F u/x (P is vertical)
+//
+
+class linear_intersections
+{
+public:
+ template <typename Point1, typename Point2, typename IntersectionResult>
+ linear_intersections(Point1 const& pi,
+ Point2 const& qi,
+ IntersectionResult const& result,
+ bool is_p_last, bool is_q_last)
+ {
+ int arrival_a = result.template get<1>().arrival[0];
+ int arrival_b = result.template get<1>().arrival[1];
+ bool same_dirs = result.template get<1>().dir_a == 0
+ && result.template get<1>().dir_b == 0;
+
+ if ( same_dirs )
+ {
+ if ( result.template get<0>().count == 2 )
+ {
+ if ( ! result.template get<1>().opposite )
+ {
+ ips[0].p_operation = operation_intersection;
+ ips[0].q_operation = operation_intersection;
+ ips[1].p_operation = union_or_blocked_same_dirs(arrival_a, is_p_last);
+ ips[1].q_operation = union_or_blocked_same_dirs(arrival_b, is_q_last);
+
+ ips[0].is_pi
+ = equals::equals_point_point(
+ pi, result.template get<0>().intersections[0]);
+ ips[0].is_qi
+ = equals::equals_point_point(
+ qi, result.template get<0>().intersections[0]);
+ ips[1].is_pj = arrival_a != -1;
+ ips[1].is_qj = arrival_b != -1;
+ }
+ else
+ {
+ ips[0].p_operation = operation_intersection;
+ ips[0].q_operation = union_or_blocked_same_dirs(arrival_b, is_q_last);
+ ips[1].p_operation = union_or_blocked_same_dirs(arrival_a, is_p_last);
+ ips[1].q_operation = operation_intersection;
+
+ ips[0].is_pi = arrival_b != 1;
+ ips[0].is_qj = arrival_b != -1;
+ ips[1].is_pj = arrival_a != -1;
+ ips[1].is_qi = arrival_a != 1;
+ }
+ }
+ else
+ {
+ BOOST_ASSERT(result.template get<0>().count == 1);
+ ips[0].p_operation = union_or_blocked_same_dirs(arrival_a, is_p_last);
+ ips[0].q_operation = union_or_blocked_same_dirs(arrival_b, is_q_last);
+
+ ips[0].is_pi = arrival_a == -1;
+ ips[0].is_qi = arrival_b == -1;
+ ips[0].is_pj = arrival_a == 0;
+ ips[0].is_qj = arrival_b == 0;
+ }
+ }
+ else
+ {
+ ips[0].p_operation = union_or_blocked_different_dirs(arrival_a, is_p_last);
+ ips[0].q_operation = union_or_blocked_different_dirs(arrival_b, is_q_last);
+
+ ips[0].is_pi = arrival_a == -1;
+ ips[0].is_qi = arrival_b == -1;
+ ips[0].is_pj = arrival_a == 1;
+ ips[0].is_qj = arrival_b == 1;
+ }
+ }
+
+ struct ip_info
+ {
+ inline ip_info()
+ : p_operation(operation_none), q_operation(operation_none)
+ , is_pi(false), is_pj(false), is_qi(false), is_qj(false)
+ {}
+
+ operation_type p_operation, q_operation;
+ bool is_pi, is_pj, is_qi, is_qj;
+ };
+
+ template <std::size_t I>
+ ip_info const& get() const
+ {
+ BOOST_STATIC_ASSERT(I < 2);
+ return ips[I];
+ }
+
+private:
+
+ // only if collinear (same_dirs)
+ static inline operation_type union_or_blocked_same_dirs(int arrival, bool is_last)
+ {
+ if ( arrival == 1 )
+ return operation_blocked;
+ else if ( arrival == -1 )
+ return operation_union;
+ else
+ return is_last ? operation_blocked : operation_union;
+ //return operation_blocked;
+ }
+
+ // only if not collinear (!same_dirs)
+ static inline operation_type union_or_blocked_different_dirs(int arrival, bool is_last)
+ {
+ if ( arrival == 1 )
+ //return operation_blocked;
+ return is_last ? operation_blocked : operation_union;
+ else
+ return operation_union;
+ }
+
+ ip_info ips[2];
+};
+
+template <typename AssignPolicy, bool EnableFirst, bool EnableLast>
+struct get_turn_info_for_endpoint
+{
+ BOOST_STATIC_ASSERT(EnableFirst || EnableLast);
+
+ template<typename Point1,
+ typename Point2,
+ typename TurnInfo,
+ typename IntersectionInfo,
+ typename OutputIterator
+ >
+ static inline bool apply(Point1 const& pi, Point1 const& pj, Point1 const& pk,
+ Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ bool is_p_first, bool is_p_last,
+ bool is_q_first, bool is_q_last,
+ TurnInfo const& tp_model,
+ IntersectionInfo const& inters,
+ method_type /*method*/,
+ OutputIterator out)
+ {
+ std::size_t ip_count = inters.i_info().count;
+ // no intersection points
+ if ( ip_count == 0 )
+ return false;
+
+ if ( !is_p_first && !is_p_last && !is_q_first && !is_q_last )
+ return false;
+
+ linear_intersections intersections(pi, qi, inters.result(), is_p_last, is_q_last);
+
+ bool append0_last
+ = analyse_segment_and_assign_ip(pi, pj, pk, qi, qj, qk,
+ is_p_first, is_p_last, is_q_first, is_q_last,
+ intersections.template get<0>(),
+ tp_model, inters, 0, out);
+
+ // NOTE: opposite && ip_count == 1 may be true!
+ bool opposite = inters.d_info().opposite;
+
+ // don't ignore only for collinear opposite
+ bool result_ignore_ip0 = append0_last && ( ip_count == 1 || !opposite );
+
+ if ( intersections.template get<1>().p_operation == operation_none )
+ return result_ignore_ip0;
+
+ bool append1_last
+ = analyse_segment_and_assign_ip(pi, pj, pk, qi, qj, qk,
+ is_p_first, is_p_last, is_q_first, is_q_last,
+ intersections.template get<1>(),
+ tp_model, inters, 1, out);
+
+ // don't ignore only for collinear opposite
+ bool result_ignore_ip1 = append1_last && !opposite /*&& ip_count == 2*/;
+
+ return result_ignore_ip0 || result_ignore_ip1;
+ }
+
+ template <typename Point1,
+ typename Point2,
+ typename TurnInfo,
+ typename IntersectionInfo,
+ typename OutputIterator>
+ static inline
+ bool analyse_segment_and_assign_ip(Point1 const& pi, Point1 const& pj, Point1 const& pk,
+ Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ bool is_p_first, bool is_p_last,
+ bool is_q_first, bool is_q_last,
+ linear_intersections::ip_info const& ip_info,
+ TurnInfo const& tp_model,
+ IntersectionInfo const& inters,
+ int ip_index,
+ OutputIterator out)
+ {
+#ifdef BOOST_GEOMETRY_DEBUG_GET_TURNS_LINEAR_LINEAR
+ // may this give false positives for INTs?
+ typename IntersectionResult::point_type const&
+ inters_pt = result.template get<0>().intersections[ip_index];
+ BOOST_ASSERT(ip_info.is_pi == equals::equals_point_point(pi, inters_pt));
+ BOOST_ASSERT(ip_info.is_qi == equals::equals_point_point(qi, inters_pt));
+ BOOST_ASSERT(ip_info.is_pj == equals::equals_point_point(pj, inters_pt));
+ BOOST_ASSERT(ip_info.is_qj == equals::equals_point_point(qj, inters_pt));
+#endif
+
+ // TODO - calculate first/last only if needed
+ bool is_p_first_ip = is_p_first && ip_info.is_pi;
+ bool is_p_last_ip = is_p_last && ip_info.is_pj;
+ bool is_q_first_ip = is_q_first && ip_info.is_qi;
+ bool is_q_last_ip = is_q_last && ip_info.is_qj;
+ bool append_first = EnableFirst && (is_p_first_ip || is_q_first_ip);
+ bool append_last = EnableLast && (is_p_last_ip || is_q_last_ip);
+
+ operation_type p_operation = ip_info.p_operation;
+ operation_type q_operation = ip_info.q_operation;
+
+ if ( append_first || append_last )
+ {
+ bool handled = handle_internal<0>(pi, pj, pk, qi, qj, qk,
+ inters.rpi(), inters.rpj(), inters.rpk(),
+ inters.rqi(), inters.rqj(), inters.rqk(),
+ is_p_first_ip, is_p_last_ip,
+ is_q_first_ip, is_q_last_ip,
+ ip_info.is_qi, ip_info.is_qj,
+ tp_model, inters, ip_index,
+ p_operation, q_operation);
+ if ( !handled )
+ {
+ handle_internal<1>(qi, qj, qk, pi, pj, pk,
+ inters.rqi(), inters.rqj(), inters.rqk(),
+ inters.rpi(), inters.rpj(), inters.rpk(),
+ is_q_first_ip, is_q_last_ip,
+ is_p_first_ip, is_p_last_ip,
+ ip_info.is_pi, ip_info.is_pj,
+ tp_model, inters, ip_index,
+ q_operation, p_operation);
+ }
+
+ if ( p_operation != operation_none )
+ {
+ method_type method = endpoint_ip_method(ip_info.is_pi, ip_info.is_pj,
+ ip_info.is_qi, ip_info.is_qj);
+ turn_position p_pos = ip_position(is_p_first_ip, is_p_last_ip);
+ turn_position q_pos = ip_position(is_q_first_ip, is_q_last_ip);
+
+ // handle spikes
+
+ // P is spike and should be handled
+ if ( !is_p_last
+ && ip_info.is_pj // this check is redundant (also in is_spike_p) but faster
+ && inters.i_info().count == 2
+ && inters.is_spike_p() )
+ {
+ assign(pi, qi, inters.result(), ip_index, method, operation_blocked, q_operation,
+ p_pos, q_pos, is_p_first_ip, is_q_first_ip, true, false, tp_model, out);
+ assign(pi, qi, inters.result(), ip_index, method, operation_intersection, q_operation,
+ p_pos, q_pos, is_p_first_ip, is_q_first_ip, true, false, tp_model, out);
+ }
+ // Q is spike and should be handled
+ else if ( !is_q_last
+ && ip_info.is_qj // this check is redundant (also in is_spike_q) but faster
+ && inters.i_info().count == 2
+ && inters.is_spike_q() )
+ {
+ assign(pi, qi, inters.result(), ip_index, method, p_operation, operation_blocked,
+ p_pos, q_pos, is_p_first_ip, is_q_first_ip, false, true, tp_model, out);
+ assign(pi, qi, inters.result(), ip_index, method, p_operation, operation_intersection,
+ p_pos, q_pos, is_p_first_ip, is_q_first_ip, false, true, tp_model, out);
+ }
+ // no spikes
+ else
+ {
+ assign(pi, qi, inters.result(), ip_index, method, p_operation, q_operation,
+ p_pos, q_pos, is_p_first_ip, is_q_first_ip, false, false, tp_model, out);
+ }
+ }
+ }
+
+ return append_last;
+ }
+
+ // TODO: IT'S ALSO PROBABLE THAT ALL THIS FUNCTION COULD BE INTEGRATED WITH handle_segment
+ // however now it's lazily calculated and then it would be always calculated
+
+ template<std::size_t G1Index,
+ typename Point1,
+ typename Point2,
+ typename RobustPoint1,
+ typename RobustPoint2,
+ typename TurnInfo,
+ typename IntersectionInfo
+ >
+ static inline bool handle_internal(Point1 const& /*i1*/, Point1 const& /*j1*/, Point1 const& /*k1*/,
+ Point2 const& i2, Point2 const& j2, Point2 const& /*k2*/,
+ RobustPoint1 const& ri1, RobustPoint1 const& rj1, RobustPoint1 const& /*rk1*/,
+ RobustPoint2 const& ri2, RobustPoint2 const& rj2, RobustPoint2 const& rk2,
+ bool first1, bool last1, bool first2, bool last2,
+ bool ip_i2, bool ip_j2, TurnInfo const& tp_model,
+ IntersectionInfo const& inters, int ip_index,
+ operation_type & op1, operation_type & op2)
+ {
+ boost::ignore_unused_variable_warning(i2);
+ boost::ignore_unused_variable_warning(j2);
+ boost::ignore_unused_variable_warning(ip_index);
+ boost::ignore_unused_variable_warning(tp_model);
+
+ if ( !first2 && !last2 )
+ {
+ if ( first1 )
+ {
+#ifdef BOOST_GEOMETRY_DEBUG_GET_TURNS_LINEAR_LINEAR
+ // may this give false positives for INTs?
+ typename IntersectionResult::point_type const&
+ inters_pt = inters.i_info().intersections[ip_index];
+ BOOST_ASSERT(ip_i2 == equals::equals_point_point(i2, inters_pt));
+ BOOST_ASSERT(ip_j2 == equals::equals_point_point(j2, inters_pt));
+#endif
+ if ( ip_i2 )
+ {
+ // don't output this IP - for the first point of other geometry segment
+ op1 = operation_none;
+ op2 = operation_none;
+ return true;
+ }
+ else if ( ip_j2 )
+ {
+ side_calculator<RobustPoint1, RobustPoint2, RobustPoint2>
+ side_calc(ri2, ri1, rj1, ri2, rj2, rk2);
+
+ std::pair<operation_type, operation_type>
+ operations = operations_of_equal(side_calc);
+
+// TODO: must the above be calculated?
+// wouldn't it be enough to check if segments are collinear?
+
+ if ( operations_both(operations, operation_continue) )
+ {
+ if ( op1 != operation_union
+ || op2 != operation_union
+ || ! ( G1Index == 0 ? inters.is_spike_q() : inters.is_spike_p() ) )
+ {
+ // THIS IS WRT THE ORIGINAL SEGMENTS! NOT THE ONES ABOVE!
+ bool opposite = inters.d_info().opposite;
+
+ op1 = operation_intersection;
+ op2 = opposite ? operation_union : operation_intersection;
+ }
+ }
+ else
+ {
+ BOOST_ASSERT(operations_combination(operations, operation_intersection, operation_union));
+ //op1 = operation_union;
+ //op2 = operation_union;
+ }
+
+ return true;
+ }
+ // else do nothing - shouldn't be handled this way
+ }
+ else if ( last1 )
+ {
+#ifdef BOOST_GEOMETRY_DEBUG_GET_TURNS_LINEAR_LINEAR
+ // may this give false positives for INTs?
+ typename IntersectionResult::point_type const&
+ inters_pt = inters.i_info().intersections[ip_index];
+ BOOST_ASSERT(ip_i2 == equals::equals_point_point(i2, inters_pt));
+ BOOST_ASSERT(ip_j2 == equals::equals_point_point(j2, inters_pt));
+#endif
+ if ( ip_i2 )
+ {
+ // don't output this IP - for the first point of other geometry segment
+ op1 = operation_none;
+ op2 = operation_none;
+ return true;
+ }
+ else if ( ip_j2 )
+ {
+ side_calculator<RobustPoint1, RobustPoint2, RobustPoint2>
+ side_calc(ri2, rj1, ri1, ri2, rj2, rk2);
+
+ std::pair<operation_type, operation_type>
+ operations = operations_of_equal(side_calc);
+
+// TODO: must the above be calculated?
+// wouldn't it be enough to check if segments are collinear?
+
+ if ( operations_both(operations, operation_continue) )
+ {
+ if ( op1 != operation_blocked
+ || op2 != operation_union
+ || ! ( G1Index == 0 ? inters.is_spike_q() : inters.is_spike_p() ) )
+ {
+ // THIS IS WRT THE ORIGINAL SEGMENTS! NOT THE ONES ABOVE!
+ bool second_going_out = inters.i_info().count > 1;
+
+ op1 = operation_blocked;
+ op2 = second_going_out ? operation_union : operation_intersection;
+ }
+ }
+ else
+ {
+ BOOST_ASSERT(operations_combination(operations, operation_intersection, operation_union));
+ //op1 = operation_blocked;
+ //op2 = operation_union;
+ }
+
+ return true;
+ }
+ // else do nothing - shouldn't be handled this way
+ }
+ // else do nothing - shouldn't be handled this way
+ }
+
+ return false;
+ }
+
+ static inline method_type endpoint_ip_method(bool ip_pi, bool ip_pj, bool ip_qi, bool ip_qj)
+ {
+ if ( (ip_pi || ip_pj) && (ip_qi || ip_qj) )
+ return method_touch;
+ else
+ return method_touch_interior;
+ }
+
+ static inline turn_position ip_position(bool is_ip_first_i, bool is_ip_last_j)
+ {
+ return is_ip_first_i ? position_front :
+ ( is_ip_last_j ? position_back : position_middle );
+ }
+
+ template <typename Point1,
+ typename Point2,
+ typename IntersectionResult,
+ typename TurnInfo,
+ typename OutputIterator>
+ static inline void assign(Point1 const& pi, Point2 const& qi,
+ IntersectionResult const& result,
+ int ip_index,
+ method_type method,
+ operation_type op0, operation_type op1,
+ turn_position pos0, turn_position pos1,
+ bool is_p_first_ip, bool is_q_first_ip,
+ bool is_p_spike, bool is_q_spike,
+ TurnInfo const& tp_model,
+ OutputIterator out)
+ {
+ TurnInfo tp = tp_model;
+
+ //geometry::convert(ip, tp.point);
+ //tp.method = method;
+ base_turn_handler::assign_point(tp, method, result.template get<0>(), ip_index);
+
+ tp.operations[0].operation = op0;
+ tp.operations[1].operation = op1;
+ tp.operations[0].position = pos0;
+ tp.operations[1].position = pos1;
+
+ if ( result.template get<0>().count > 1 )
+ {
+ // NOTE: is_collinear is NOT set for the first endpoint
+ // for which there is no preceding segment
+
+ //BOOST_ASSERT( result.template get<1>().dir_a == 0 && result.template get<1>().dir_b == 0 );
+ if ( ! is_p_first_ip )
+ {
+ tp.operations[0].is_collinear = op0 != operation_intersection
+ || is_p_spike;
+ }
+
+ if ( ! is_q_first_ip )
+ {
+ tp.operations[1].is_collinear = op1 != operation_intersection
+ || is_q_spike;
+ }
+ }
+ else //if ( result.template get<0>().count == 1 )
+ {
+ if ( op0 == operation_blocked && op1 == operation_intersection )
+ {
+ tp.operations[0].is_collinear = true;
+ }
+ else if ( op0 == operation_intersection && op1 == operation_blocked )
+ {
+ tp.operations[1].is_collinear = true;
+ }
+ }
+
+ AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
+ *out++ = tp;
+ }
+
+ template <typename SidePolicy>
+ static inline std::pair<operation_type, operation_type> operations_of_equal(SidePolicy const& side)
+ {
+ int const side_pk_q2 = side.pk_wrt_q2();
+ int const side_pk_p = side.pk_wrt_p1();
+ int const side_qk_p = side.qk_wrt_p1();
+
+ // If pk is collinear with qj-qk, they continue collinearly.
+ // This can be on either side of p1 (== q1), or collinear
+ // The second condition checks if they do not continue
+ // oppositely
+ if ( side_pk_q2 == 0 && side_pk_p == side_qk_p )
+ {
+ return std::make_pair(operation_continue, operation_continue);
+ }
+
+ // If they turn to same side (not opposite sides)
+ if ( ! base_turn_handler::opposite(side_pk_p, side_qk_p) )
+ {
+ // If pk is left of q2 or collinear: p: union, q: intersection
+ if ( side_pk_q2 != -1 )
+ {
+ return std::make_pair(operation_union, operation_intersection);
+ }
+ else
+ {
+ return std::make_pair(operation_intersection, operation_union);
+ }
+ }
+ else
+ {
+ // They turn opposite sides. If p turns left (or collinear),
+ // p: union, q: intersection
+ if ( side_pk_p != -1 )
+ {
+ return std::make_pair(operation_union, operation_intersection);
+ }
+ else
+ {
+ return std::make_pair(operation_intersection, operation_union);
+ }
+ }
+ }
+
+ static inline bool operations_both(
+ std::pair<operation_type, operation_type> const& operations,
+ operation_type const op)
+ {
+ return operations.first == op && operations.second == op;
+ }
+
+ static inline bool operations_combination(
+ std::pair<operation_type, operation_type> const& operations,
+ operation_type const op1, operation_type const op2)
+ {
+ return ( operations.first == op1 && operations.second == op2 )
+ || ( operations.first == op2 && operations.second == op1 );
+ }
+};
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_FOR_ENDPOINT_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp
new file mode 100644
index 0000000000..eead0d719b
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp
@@ -0,0 +1,329 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates.
+
+// 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)
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HELPERS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HELPERS_HPP
+
+#include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
+
+namespace boost { namespace geometry {
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay {
+
+enum turn_position { position_middle, position_front, position_back };
+
+template <typename SegmentRatio>
+struct turn_operation_linear
+ : public turn_operation<SegmentRatio>
+{
+ turn_operation_linear()
+ : position(position_middle)
+ , is_collinear(false)
+ {}
+
+ turn_position position;
+ bool is_collinear; // valid only for Linear geometry
+};
+
+template <typename PointP, typename PointQ,
+ typename Pi = PointP, typename Pj = PointP, typename Pk = PointP,
+ typename Qi = PointQ, typename Qj = PointQ, typename Qk = PointQ
+>
+struct side_calculator
+{
+ typedef boost::geometry::strategy::side::side_by_triangle<> side; // todo: get from coordinate system
+
+ inline side_calculator(Pi const& pi, Pj const& pj, Pk const& pk,
+ Qi const& qi, Qj const& qj, Qk const& qk)
+ : m_pi(pi), m_pj(pj), m_pk(pk)
+ , m_qi(qi), m_qj(qj), m_qk(qk)
+ {}
+
+ inline int pk_wrt_p1() const { return side::apply(m_pi, m_pj, m_pk); }
+ inline int pk_wrt_q1() const { return side::apply(m_qi, m_qj, m_pk); }
+ inline int qk_wrt_p1() const { return side::apply(m_pi, m_pj, m_qk); }
+ inline int qk_wrt_q1() const { return side::apply(m_qi, m_qj, m_qk); }
+
+ inline int pk_wrt_q2() const { return side::apply(m_qj, m_qk, m_pk); }
+ inline int qk_wrt_p2() const { return side::apply(m_pj, m_pk, m_qk); }
+
+ Pi const& m_pi;
+ Pj const& m_pj;
+ Pk const& m_pk;
+ Qi const& m_qi;
+ Qj const& m_qj;
+ Qk const& m_qk;
+};
+
+template <typename Point1, typename Point2, typename RobustPolicy>
+struct robust_points
+{
+ typedef typename geometry::robust_point_type
+ <
+ Point1, RobustPolicy
+ >::type robust_point1_type;
+ // TODO: define robust_point2_type using Point2?
+ typedef robust_point1_type robust_point2_type;
+
+ inline robust_points(Point1 const& pi, Point1 const& pj, Point1 const& pk,
+ Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ RobustPolicy const& robust_policy)
+ {
+ geometry::recalculate(m_rpi, pi, robust_policy);
+ geometry::recalculate(m_rpj, pj, robust_policy);
+ geometry::recalculate(m_rpk, pk, robust_policy);
+ geometry::recalculate(m_rqi, qi, robust_policy);
+ geometry::recalculate(m_rqj, qj, robust_policy);
+ geometry::recalculate(m_rqk, qk, robust_policy);
+ }
+
+ robust_point1_type m_rpi, m_rpj, m_rpk;
+ robust_point2_type m_rqi, m_rqj, m_rqk;
+};
+
+template <typename Point1, typename Point2, typename RobustPolicy>
+class intersection_info_base
+ : private robust_points<Point1, Point2, RobustPolicy>
+{
+ typedef robust_points<Point1, Point2, RobustPolicy> base_t;
+
+public:
+ typedef Point1 point1_type;
+ typedef Point2 point2_type;
+
+ typedef typename base_t::robust_point1_type robust_point1_type;
+ typedef typename base_t::robust_point2_type robust_point2_type;
+
+ typedef side_calculator<robust_point1_type, robust_point2_type> side_calculator_type;
+
+ intersection_info_base(Point1 const& pi, Point1 const& pj, Point1 const& pk,
+ Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ RobustPolicy const& robust_policy)
+ : base_t(pi, pj, pk, qi, qj, qk, robust_policy)
+ , m_side_calc(base_t::m_rpi, base_t::m_rpj, base_t::m_rpk,
+ base_t::m_rqi, base_t::m_rqj, base_t::m_rqk)
+ , m_pi(pi), m_pj(pj), m_pk(pk)
+ , m_qi(qi), m_qj(qj), m_qk(qk)
+ {}
+
+ inline Point1 const& pi() const { return m_pi; }
+ inline Point1 const& pj() const { return m_pj; }
+ inline Point1 const& pk() const { return m_pk; }
+
+ inline Point2 const& qi() const { return m_qi; }
+ inline Point2 const& qj() const { return m_qj; }
+ inline Point2 const& qk() const { return m_qk; }
+
+ inline robust_point1_type const& rpi() const { return base_t::m_rpi; }
+ inline robust_point1_type const& rpj() const { return base_t::m_rpj; }
+ inline robust_point1_type const& rpk() const { return base_t::m_rpk; }
+
+ inline robust_point2_type const& rqi() const { return base_t::m_rqi; }
+ inline robust_point2_type const& rqj() const { return base_t::m_rqj; }
+ inline robust_point2_type const& rqk() const { return base_t::m_rqk; }
+
+ inline side_calculator_type const& sides() const { return m_side_calc; }
+
+private:
+ side_calculator_type m_side_calc;
+
+ point1_type const& m_pi;
+ point1_type const& m_pj;
+ point1_type const& m_pk;
+ point2_type const& m_qi;
+ point2_type const& m_qj;
+ point2_type const& m_qk;
+};
+
+template <typename Point1, typename Point2>
+class intersection_info_base<Point1, Point2, detail::no_rescale_policy>
+{
+public:
+ typedef Point1 point1_type;
+ typedef Point2 point2_type;
+
+ typedef Point1 robust_point1_type;
+ typedef Point2 robust_point2_type;
+
+ typedef side_calculator<Point1, Point2> side_calculator_type;
+
+ intersection_info_base(Point1 const& pi, Point1 const& pj, Point1 const& pk,
+ Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ no_rescale_policy const& /*robust_policy*/)
+ : m_side_calc(pi, pj, pk, qi, qj, qk)
+ {}
+
+ inline Point1 const& pi() const { return m_side_calc.m_pi; }
+ inline Point1 const& pj() const { return m_side_calc.m_pj; }
+ inline Point1 const& pk() const { return m_side_calc.m_pk; }
+
+ inline Point2 const& qi() const { return m_side_calc.m_qi; }
+ inline Point2 const& qj() const { return m_side_calc.m_qj; }
+ inline Point2 const& qk() const { return m_side_calc.m_qk; }
+
+ inline Point1 const& rpi() const { return pi(); }
+ inline Point1 const& rpj() const { return pj(); }
+ inline Point1 const& rpk() const { return pk(); }
+
+ inline Point2 const& rqi() const { return qi(); }
+ inline Point2 const& rqj() const { return qj(); }
+ inline Point2 const& rqk() const { return qk(); }
+
+ inline side_calculator_type const& sides() const { return m_side_calc; }
+
+private:
+ side_calculator_type m_side_calc;
+};
+
+
+template <typename Point1, typename Point2, typename TurnPoint, typename RobustPolicy>
+class intersection_info
+ : public intersection_info_base<Point1, Point2, RobustPolicy>
+{
+ typedef intersection_info_base<Point1, Point2, RobustPolicy> base_t;
+
+ typedef typename strategy_intersection
+ <
+ typename cs_tag<TurnPoint>::type,
+ Point1,
+ Point2,
+ TurnPoint,
+ RobustPolicy
+ >::segment_intersection_strategy_type strategy;
+
+public:
+ typedef model::referring_segment<Point1 const> segment_type1;
+ typedef model::referring_segment<Point2 const> segment_type2;
+ typedef typename base_t::side_calculator_type side_calculator_type;
+
+ typedef typename strategy::return_type result_type;
+ typedef typename boost::tuples::element<0, result_type>::type i_info_type; // intersection_info
+ typedef typename boost::tuples::element<1, result_type>::type d_info_type; // dir_info
+
+ intersection_info(Point1 const& pi, Point1 const& pj, Point1 const& pk,
+ Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ RobustPolicy const& robust_policy)
+ : base_t(pi, pj, pk, qi, qj, qk, robust_policy)
+ , m_result(strategy::apply(segment_type1(pi, pj),
+ segment_type2(qi, qj),
+ robust_policy))
+ , m_robust_policy(robust_policy)
+ {}
+
+ inline result_type const& result() const { return m_result; }
+ inline i_info_type const& i_info() const { return m_result.template get<0>(); }
+ inline d_info_type const& d_info() const { return m_result.template get<1>(); }
+
+ // TODO: it's more like is_spike_ip_p
+ inline bool is_spike_p() const
+ {
+ if ( base_t::sides().pk_wrt_p1() == 0 )
+ {
+ if ( ! is_ip_j<0>() )
+ return false;
+
+ int const qk_p1 = base_t::sides().qk_wrt_p1();
+ int const qk_p2 = base_t::sides().qk_wrt_p2();
+
+ if ( qk_p1 == -qk_p2 )
+ {
+ if ( qk_p1 == 0 )
+ {
+ return is_spike_of_collinear(base_t::pi(), base_t::pj(), base_t::pk());
+ }
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ // TODO: it's more like is_spike_ip_q
+ inline bool is_spike_q() const
+ {
+ if ( base_t::sides().qk_wrt_q1() == 0 )
+ {
+ if ( ! is_ip_j<1>() )
+ return false;
+
+ int const pk_q1 = base_t::sides().pk_wrt_q1();
+ int const pk_q2 = base_t::sides().pk_wrt_q2();
+
+ if ( pk_q1 == -pk_q2 )
+ {
+ if ( pk_q1 == 0 )
+ {
+ return is_spike_of_collinear(base_t::qi(), base_t::qj(), base_t::qk());
+ }
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+private:
+ template <typename Point>
+ inline bool is_spike_of_collinear(Point const& i, Point const& j, Point const& k) const
+ {
+ typedef model::referring_segment<Point const> seg_t;
+
+ typedef strategy_intersection
+ <
+ typename cs_tag<Point>::type, Point, Point, Point, RobustPolicy
+ > si;
+
+ typedef typename si::segment_intersection_strategy_type strategy;
+
+ typename strategy::return_type result
+ = strategy::apply(seg_t(i, j), seg_t(j, k), m_robust_policy);
+
+ return result.template get<0>().count == 2;
+ }
+
+ template <std::size_t OpId>
+ bool is_ip_j() const
+ {
+ int arrival = d_info().arrival[OpId];
+ bool same_dirs = d_info().dir_a == 0 && d_info().dir_b == 0;
+
+ if ( same_dirs )
+ {
+ if ( i_info().count == 2 )
+ {
+ return arrival != -1;
+ }
+ else
+ {
+ return arrival == 0;
+ }
+ }
+ else
+ {
+ return arrival == 1;
+ }
+ }
+
+ result_type m_result;
+ RobustPolicy const& m_robust_policy;
+};
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HELPERS_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp
new file mode 100644
index 0000000000..873567bbf5
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp
@@ -0,0 +1,805 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates.
+
+// 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)
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_LA_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_LA_HPP
+
+#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp>
+
+// TEMP, for spikes detector
+//#include <boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp>
+
+namespace boost { namespace geometry {
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay {
+
+template<typename AssignPolicy>
+struct get_turn_info_linear_areal
+{
+ static const bool handle_spikes = true;
+
+ template
+ <
+ typename Point1,
+ typename Point2,
+ typename TurnInfo,
+ typename RobustPolicy,
+ typename OutputIterator
+ >
+ static inline OutputIterator apply(
+ Point1 const& pi, Point1 const& pj, Point1 const& pk,
+ Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ bool is_p_first, bool is_p_last,
+ bool is_q_first, bool is_q_last,
+ TurnInfo const& tp_model,
+ RobustPolicy const& robust_policy,
+ OutputIterator out)
+ {
+ typedef intersection_info<Point1, Point2, typename TurnInfo::point_type, RobustPolicy>
+ inters_info;
+
+ inters_info inters(pi, pj, pk, qi, qj, qk, robust_policy);
+
+ char const method = inters.d_info().how;
+
+ // Copy, to copy possibly extended fields
+ TurnInfo tp = tp_model;
+
+ // Select method and apply
+ switch(method)
+ {
+ case 'a' : // collinear, "at"
+ case 'f' : // collinear, "from"
+ case 's' : // starts from the middle
+ get_turn_info_for_endpoint<true, true>(
+ pi, pj, pk, qi, qj, qk,
+ is_p_first, is_p_last, is_q_first, is_q_last,
+ tp_model, inters, method_none, out);
+ break;
+
+ case 'd' : // disjoint: never do anything
+ break;
+
+ case 'm' :
+ {
+ if ( get_turn_info_for_endpoint<false, true>(
+ pi, pj, pk, qi, qj, qk,
+ is_p_first, is_p_last, is_q_first, is_q_last,
+ tp_model, inters, method_touch_interior, out) )
+ {
+ // do nothing
+ }
+ else
+ {
+ typedef touch_interior
+ <
+ TurnInfo
+ > policy;
+
+ // If Q (1) arrives (1)
+ if ( inters.d_info().arrival[1] == 1 )
+ {
+ policy::template apply<0>(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(),
+ inters.sides());
+ }
+ else
+ {
+ // Swap p/q
+ side_calculator
+ <
+ typename inters_info::robust_point2_type,
+ typename inters_info::robust_point1_type
+ > swapped_side_calc(inters.rqi(), inters.rqj(), inters.rqk(),
+ inters.rpi(), inters.rpj(), inters.rpk());
+ policy::template apply<1>(qi, qj, qk, pi, pj, pk,
+ tp, inters.i_info(), inters.d_info(),
+ swapped_side_calc);
+ }
+
+ if ( tp.operations[1].operation == operation_blocked )
+ {
+ tp.operations[0].is_collinear = true;
+ }
+
+ replace_method_and_operations_tm(tp.method,
+ tp.operations[0].operation,
+ tp.operations[1].operation);
+
+ // this function assumes that 'u' must be set for a spike
+ calculate_spike_operation(tp.operations[0].operation,
+ inters, is_p_last);
+
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+
+ *out++ = tp;
+ }
+ }
+ break;
+ case 'i' :
+ {
+ crosses<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info());
+
+ replace_operations_i(tp.operations[0].operation, tp.operations[1].operation);
+
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+ *out++ = tp;
+ }
+ break;
+ case 't' :
+ {
+ // Both touch (both arrive there)
+ if ( get_turn_info_for_endpoint<false, true>(
+ pi, pj, pk, qi, qj, qk,
+ is_p_first, is_p_last, is_q_first, is_q_last,
+ tp_model, inters, method_touch, out) )
+ {
+ // do nothing
+ }
+ else
+ {
+ touch<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(), inters.sides());
+
+ if ( tp.operations[1].operation == operation_blocked )
+ {
+ tp.operations[0].is_collinear = true;
+ }
+
+ // workarounds for touch<> not taking spikes into account starts here
+ // those was discovered empirically
+ // touch<> is not symmetrical!
+ // P spikes and Q spikes may produce various operations!
+ // Only P spikes are valid for L/A
+ // TODO: this is not optimal solution - think about rewriting touch<>
+
+ if ( tp.operations[0].operation == operation_blocked )
+ {
+ // a spike on P on the same line with Q1
+ if ( inters.is_spike_p() )
+ {
+ if ( inters.sides().qk_wrt_p1() == 0 )
+ {
+ tp.operations[0].is_collinear = true;
+ }
+ else
+ {
+ tp.operations[0].operation = operation_union;
+ }
+ }
+ }
+ else if ( tp.operations[0].operation == operation_continue
+ && tp.operations[1].operation == operation_continue )
+ {
+ // P spike on the same line with Q2 (opposite)
+ if ( inters.sides().pk_wrt_q1() == -inters.sides().qk_wrt_q1()
+ && inters.is_spike_p() )
+ {
+ tp.operations[0].operation = operation_union;
+ tp.operations[1].operation = operation_union;
+ }
+ }
+ else if ( tp.operations[0].operation == operation_none
+ && tp.operations[1].operation == operation_none )
+ {
+ // spike not handled by touch<>
+ if ( inters.is_spike_p() )
+ {
+ tp.operations[0].operation = operation_intersection;
+ tp.operations[1].operation = operation_union;
+
+ if ( inters.sides().pk_wrt_q2() == 0 )
+ {
+ tp.operations[0].operation = operation_continue; // will be converted to i
+ tp.operations[0].is_collinear = true;
+ }
+ }
+ }
+
+ // workarounds for touch<> not taking spikes into account ends here
+
+ replace_method_and_operations_tm(tp.method,
+ tp.operations[0].operation,
+ tp.operations[1].operation);
+
+ bool ignore_spike
+ = calculate_spike_operation(tp.operations[0].operation,
+ inters, is_p_last);
+
+// TODO: move this into the append_xxx and call for each turn?
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+
+ if ( ! handle_spikes
+ || ignore_spike
+ || ! append_opposite_spikes<append_touches>( // for 'i' or 'c' i???
+ tp, inters, is_p_last, is_q_last, out) )
+ {
+ *out++ = tp;
+ }
+ }
+ }
+ break;
+ case 'e':
+ {
+ if ( get_turn_info_for_endpoint<true, true>(
+ pi, pj, pk, qi, qj, qk,
+ is_p_first, is_p_last, is_q_first, is_q_last,
+ tp_model, inters, method_equal, out) )
+ {
+ // do nothing
+ }
+ else
+ {
+ tp.operations[0].is_collinear = true;
+
+ if ( ! inters.d_info().opposite )
+ {
+ // Both equal
+ // or collinear-and-ending at intersection point
+ equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(), inters.sides());
+
+ turn_transformer_ec<false> transformer(method_touch);
+ transformer(tp);
+
+// TODO: move this into the append_xxx and call for each turn?
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+
+ // conditionally handle spikes
+ if ( ! handle_spikes
+ || ! append_collinear_spikes(tp, inters, is_p_last, is_q_last,
+ method_touch, append_equal, out) )
+ {
+ *out++ = tp; // no spikes
+ }
+ }
+ else
+ {
+ equal_opposite
+ <
+ TurnInfo,
+ AssignPolicy
+ >::apply(pi, qi,
+ tp, out, inters.i_info(), inters.d_info());
+ }
+ }
+ }
+ break;
+ case 'c' :
+ {
+ // Collinear
+ if ( get_turn_info_for_endpoint<true, true>(
+ pi, pj, pk, qi, qj, qk,
+ is_p_first, is_p_last, is_q_first, is_q_last,
+ tp_model, inters, method_collinear, out) )
+ {
+ // do nothing
+ }
+ else
+ {
+ tp.operations[0].is_collinear = true;
+
+ if ( ! inters.d_info().opposite )
+ {
+ method_type method_replace = method_touch_interior;
+ append_version_c version = append_collinear;
+
+ if ( inters.d_info().arrival[0] == 0 )
+ {
+ // Collinear, but similar thus handled as equal
+ equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(), inters.sides());
+
+ method_replace = method_touch;
+ version = append_equal;
+ }
+ else
+ {
+ collinear<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(), inters.sides());
+
+ //method_replace = method_touch_interior;
+ //version = append_collinear;
+ }
+
+ turn_transformer_ec<false> transformer(method_replace);
+ transformer(tp);
+
+// TODO: move this into the append_xxx and call for each turn?
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+
+ // conditionally handle spikes
+ if ( ! handle_spikes
+ || ! append_collinear_spikes(tp, inters, is_p_last, is_q_last,
+ method_replace, version, out) )
+ {
+ // no spikes
+ *out++ = tp;
+ }
+ }
+ else
+ {
+ // Is this always 'm' ?
+ turn_transformer_ec<false> transformer(method_touch_interior);
+
+ // conditionally handle spikes
+ if ( handle_spikes )
+ {
+ append_opposite_spikes<append_collinear_opposite>(
+ tp, inters, is_p_last, is_q_last, out);
+ }
+
+ // TODO: ignore for spikes?
+ // E.g. pass is_p_valid = !is_p_last && !is_pj_spike,
+ // the same with is_q_valid
+
+ collinear_opposite
+ <
+ TurnInfo,
+ AssignPolicy
+ >::apply(pi, pj, pk, qi, qj, qk,
+ tp, out, inters.i_info(), inters.d_info(),
+ inters.sides(), transformer);
+ }
+ }
+ }
+ break;
+ case '0' :
+ {
+ // degenerate points
+ if (AssignPolicy::include_degenerate)
+ {
+ only_convert::apply(tp, inters.i_info());
+
+ if ( is_p_first
+ && equals::equals_point_point(pi, tp.point) )
+ {
+ tp.operations[0].position = position_front;
+ }
+ else if ( is_p_last
+ && equals::equals_point_point(pj, tp.point) )
+ {
+ tp.operations[0].position = position_back;
+ }
+ // tp.operations[1].position = position_middle;
+
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+ *out++ = tp;
+ }
+ }
+ break;
+ default :
+ {
+#if defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS)
+ std::cout << "TURN: Unknown method: " << method << std::endl;
+#endif
+#if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW)
+ throw turn_info_exception(method);
+#endif
+ }
+ break;
+ }
+
+ return out;
+ }
+
+ template <typename Operation,
+ typename IntersectionInfo>
+ static inline bool calculate_spike_operation(Operation & op,
+ IntersectionInfo const& inters,
+ bool is_p_last)
+ {
+ bool is_p_spike = ( op == operation_union || op == operation_intersection )
+ && ! is_p_last
+ && inters.is_spike_p();
+
+ if ( is_p_spike )
+ {
+ bool going_in = false, going_out = false;
+
+ int const pk_q1 = inters.sides().pk_wrt_q1();
+ int const pk_q2 = inters.sides().pk_wrt_q2();
+
+ if ( inters.sides().qk_wrt_q1() <= 0 ) // Q turning R or C
+ {
+ going_in = pk_q1 < 0 && pk_q2 < 0; // Pk on the right of both
+ going_out = pk_q1 > 0 || pk_q2 > 0; // Pk on the left of one of them
+ }
+ else
+ {
+ going_in = pk_q1 < 0 || pk_q2 < 0; // Pk on the right of one of them
+ going_out = pk_q1 > 0 && pk_q2 > 0; // Pk on the left of both
+ }
+
+ if ( going_in )
+ {
+ op = operation_intersection;
+ return true;
+ }
+ else if ( going_out )
+ {
+ op = operation_union;
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ enum append_version_c { append_equal, append_collinear };
+
+ template <typename TurnInfo,
+ typename IntersectionInfo,
+ typename OutIt>
+ static inline bool append_collinear_spikes(TurnInfo & tp,
+ IntersectionInfo const& inters,
+ bool is_p_last, bool /*is_q_last*/,
+ method_type method, append_version_c version,
+ OutIt out)
+ {
+ // method == touch || touch_interior
+ // both position == middle
+
+ bool is_p_spike = ( version == append_equal ?
+ ( tp.operations[0].operation == operation_union
+ || tp.operations[0].operation == operation_intersection ) :
+ tp.operations[0].operation == operation_continue )
+ && ! is_p_last
+ && inters.is_spike_p();
+
+ // TODO: throw an exception for spike in Areal?
+ /*bool is_q_spike = tp.operations[1].operation == spike_op
+ && ! is_q_last
+ && inters.is_spike_q();*/
+
+ if ( is_p_spike )
+ {
+ tp.method = method;
+ tp.operations[0].operation = operation_blocked;
+ tp.operations[1].operation = operation_union;
+ *out++ = tp;
+ tp.operations[0].operation = operation_continue; // boundary
+ //tp.operations[1].operation = operation_union;
+ *out++ = tp;
+
+ return true;
+ }
+
+ return false;
+ }
+
+ enum append_version_o { append_touches, append_collinear_opposite };
+
+ template <append_version_o Version,
+ typename TurnInfo,
+ typename IntersectionInfo,
+ typename OutIt>
+ static inline bool append_opposite_spikes(TurnInfo & tp,
+ IntersectionInfo const& inters,
+ bool is_p_last, bool /*is_q_last*/,
+ OutIt out)
+ {
+ bool is_p_spike = ( Version == append_touches ?
+ ( tp.operations[0].operation == operation_continue
+ || tp.operations[0].operation == operation_intersection ) : // i ???
+ true )
+ && ! is_p_last
+ && inters.is_spike_p();
+ // TODO: throw an exception for spike in Areal?
+ /*bool is_q_spike = ( Version == append_touches ?
+ ( tp.operations[1].operation == operation_continue
+ || tp.operations[1].operation == operation_intersection ) :
+ true )
+ && ! is_q_last
+ && inters.is_spike_q();*/
+
+ if ( is_p_spike && ( Version == append_touches || inters.d_info().arrival[0] == 1 ) )
+ {
+ if ( Version == append_touches )
+ {
+ tp.operations[0].is_collinear = true;
+ //tp.operations[1].is_collinear = false;
+ tp.method = method_touch;
+ }
+ else
+ {
+ tp.operations[0].is_collinear = true;
+ //tp.operations[1].is_collinear = false;
+
+ BOOST_ASSERT(inters.i_info().count > 1);
+ base_turn_handler::assign_point(tp, method_touch_interior, inters.i_info(), 1);
+
+ AssignPolicy::apply(tp, inters.pi(), inters.qi(), inters.i_info(), inters.d_info());
+ }
+
+ tp.operations[0].operation = operation_blocked;
+ tp.operations[1].operation = operation_continue; // boundary
+ *out++ = tp;
+ tp.operations[0].operation = operation_continue; // boundary
+ //tp.operations[1].operation = operation_continue; // boundary
+ *out++ = tp;
+
+ return true;
+ }
+
+ return false;
+ }
+
+ static inline void replace_method_and_operations_tm(method_type & method,
+ operation_type & op0,
+ operation_type & op1)
+ {
+ if ( op0 == operation_blocked && op1 == operation_blocked )
+ {
+ // NOTE: probably only if methods are WRT IPs, not segments!
+ method = (method == method_touch ? method_equal : method_collinear);
+ }
+
+ // Assuming G1 is always Linear
+ if ( op0 == operation_blocked )
+ {
+ op0 = operation_continue;
+ }
+
+ if ( op1 == operation_blocked )
+ {
+ op1 = operation_continue;
+ }
+ else if ( op1 == operation_intersection )
+ {
+ op1 = operation_union;
+ }
+
+ // spikes in 'm'
+ if ( method == method_error )
+ {
+ method = method_touch_interior;
+ op0 = operation_union;
+ op1 = operation_union;
+ }
+ }
+
+ template <bool IsFront>
+ class turn_transformer_ec
+ {
+ public:
+ explicit turn_transformer_ec(method_type method_t_or_m)
+ : m_method(method_t_or_m)
+ {}
+
+ template <typename Turn>
+ void operator()(Turn & turn) const
+ {
+ operation_type & op0 = turn.operations[0].operation;
+ operation_type & op1 = turn.operations[1].operation;
+
+ // NOTE: probably only if methods are WRT IPs, not segments!
+ if ( IsFront
+ || op0 == operation_intersection || op0 == operation_union
+ || op1 == operation_intersection || op1 == operation_union )
+ {
+ turn.method = m_method;
+ }
+
+ turn.operations[0].is_collinear = op0 != operation_blocked;
+
+ // Assuming G1 is always Linear
+ if ( op0 == operation_blocked )
+ {
+ op0 = operation_continue;
+ }
+
+ if ( op1 == operation_blocked )
+ {
+ op1 = operation_continue;
+ }
+ else if ( op1 == operation_intersection )
+ {
+ op1 = operation_union;
+ }
+ }
+
+ private:
+ method_type m_method;
+ };
+
+ static inline void replace_operations_i(operation_type & /*op0*/, operation_type & op1)
+ {
+ // assuming Linear is always the first one
+ op1 = operation_union;
+ }
+
+ // NOTE: Spikes may NOT be handled for Linear endpoints because it's not
+ // possible to define a spike on an endpoint. Areal geometries must
+ // NOT have spikes at all. One thing that could be done is to throw
+ // an exception when spike is detected in Areal geometry.
+
+ template <bool EnableFirst,
+ bool EnableLast,
+ typename Point1,
+ typename Point2,
+ typename TurnInfo,
+ typename IntersectionInfo,
+ typename OutputIterator>
+ static inline bool get_turn_info_for_endpoint(
+ Point1 const& pi, Point1 const& /*pj*/, Point1 const& /*pk*/,
+ Point2 const& qi, Point2 const& /*qj*/, Point2 const& /*qk*/,
+ bool is_p_first, bool is_p_last,
+ bool /*is_q_first*/, bool is_q_last,
+ TurnInfo const& tp_model,
+ IntersectionInfo const& inters,
+ method_type /*method*/,
+ OutputIterator out)
+ {
+ namespace ov = overlay;
+ typedef ov::get_turn_info_for_endpoint<AssignPolicy, EnableFirst, EnableLast> get_info_e;
+
+ const std::size_t ip_count = inters.i_info().count;
+ // no intersection points
+ if ( ip_count == 0 )
+ return false;
+
+ if ( !is_p_first && !is_p_last )
+ return false;
+
+// TODO: is_q_last could probably be replaced by false and removed from parameters
+
+ linear_intersections intersections(pi, qi, inters.result(), is_p_last, is_q_last);
+ linear_intersections::ip_info const& ip0 = intersections.template get<0>();
+ linear_intersections::ip_info const& ip1 = intersections.template get<1>();
+
+ const bool opposite = inters.d_info().opposite;
+
+ // ANALYSE AND ASSIGN FIRST
+
+ // IP on the first point of Linear Geometry
+ if ( EnableFirst && is_p_first && ip0.is_pi && !ip0.is_qi ) // !q0i prevents duplication
+ {
+ TurnInfo tp = tp_model;
+ tp.operations[0].position = position_front;
+ tp.operations[1].position = position_middle;
+
+ if ( opposite ) // opposite -> collinear
+ {
+ tp.operations[0].operation = operation_continue;
+ tp.operations[1].operation = operation_union;
+ tp.method = ip0.is_qj ? method_touch : method_touch_interior;
+ }
+ else
+ {
+ method_type replaced_method = method_touch_interior;
+
+ if ( ip0.is_qj )
+ {
+ side_calculator
+ <
+ typename IntersectionInfo::robust_point1_type,
+ typename IntersectionInfo::robust_point2_type,
+ typename IntersectionInfo::robust_point2_type
+ > side_calc(inters.rqi(), inters.rpi(), inters.rpj(),
+ inters.rqi(), inters.rqj(), inters.rqk());
+
+ std::pair<operation_type, operation_type>
+ operations = get_info_e::operations_of_equal(side_calc);
+
+ tp.operations[0].operation = operations.first;
+ tp.operations[1].operation = operations.second;
+
+ replaced_method = method_touch;
+ }
+ else
+ {
+ side_calculator
+ <
+ typename IntersectionInfo::robust_point1_type,
+ typename IntersectionInfo::robust_point2_type,
+ typename IntersectionInfo::robust_point2_type,
+ typename IntersectionInfo::robust_point1_type,
+ typename IntersectionInfo::robust_point1_type,
+ typename IntersectionInfo::robust_point2_type,
+ typename IntersectionInfo::robust_point1_type,
+ typename IntersectionInfo::robust_point2_type
+ > side_calc(inters.rqi(), inters.rpi(), inters.rpj(),
+ inters.rqi(), inters.rpi(), inters.rqj());
+
+ std::pair<operation_type, operation_type>
+ operations = get_info_e::operations_of_equal(side_calc);
+
+ tp.operations[0].operation = operations.first;
+ tp.operations[1].operation = operations.second;
+ }
+
+ turn_transformer_ec<true> transformer(replaced_method);
+ transformer(tp);
+ }
+
+ // equals<> or collinear<> will assign the second point,
+ // we'd like to assign the first one
+ base_turn_handler::assign_point(tp, tp.method, inters.i_info(), 0);
+
+ // NOTE: is_collinear is not set for the first endpoint of L
+ // for which there is no preceding segment
+ // here is_p_first_ip == true
+ tp.operations[0].is_collinear = false;
+
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+ *out++ = tp;
+ }
+
+ // ANALYSE AND ASSIGN LAST
+
+ // IP on the last point of Linear Geometry
+ if ( EnableLast
+ && is_p_last
+ && ( ip_count > 1 ? (ip1.is_pj && !ip1.is_qi) : (ip0.is_pj && !ip0.is_qi) ) ) // prevents duplication
+ {
+ TurnInfo tp = tp_model;
+
+ if ( inters.i_info().count > 1 )
+ {
+ //BOOST_ASSERT( result.template get<1>().dir_a == 0 && result.template get<1>().dir_b == 0 );
+ tp.operations[0].is_collinear = true;
+ tp.operations[1].operation = opposite ? operation_continue : operation_union;
+ }
+ else //if ( result.template get<0>().count == 1 )
+ {
+ side_calculator
+ <
+ typename IntersectionInfo::robust_point1_type,
+ typename IntersectionInfo::robust_point2_type,
+ typename IntersectionInfo::robust_point2_type
+ > side_calc(inters.rqi(), inters.rpj(), inters.rpi(),
+ inters.rqi(), inters.rqj(), inters.rqk());
+
+ std::pair<operation_type, operation_type>
+ operations = get_info_e::operations_of_equal(side_calc);
+
+ tp.operations[0].operation = operations.first;
+ tp.operations[1].operation = operations.second;
+
+ turn_transformer_ec<false> transformer(method_none);
+ transformer(tp);
+
+ tp.operations[0].is_collinear = tp.both(operation_continue);
+ }
+
+ tp.method = ( ip_count > 1 ? ip1.is_qj : ip0.is_qj ) ? method_touch : method_touch_interior;
+ tp.operations[0].operation = operation_blocked;
+ tp.operations[0].position = position_back;
+ tp.operations[1].position = position_middle;
+
+ // equals<> or collinear<> will assign the second point,
+ // we'd like to assign the first one
+ int ip_index = ip_count > 1 ? 1 : 0;
+ base_turn_handler::assign_point(tp, tp.method, inters.i_info(), ip_index);
+
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+ *out++ = tp;
+
+ return true;
+ }
+
+ // don't ignore anything for now
+ return false;
+ }
+};
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_LA_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp
new file mode 100644
index 0000000000..4f0384877f
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp
@@ -0,0 +1,720 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2013, 2014.
+// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates.
+
+// 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)
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_LL_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_LL_HPP
+
+#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp>
+
+namespace boost { namespace geometry {
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay {
+
+template<typename AssignPolicy>
+struct get_turn_info_linear_linear
+{
+ static const bool handle_spikes = true;
+
+ template
+ <
+ typename Point1,
+ typename Point2,
+ typename TurnInfo,
+ typename RobustPolicy,
+ typename OutputIterator
+ >
+ static inline OutputIterator apply(
+ Point1 const& pi, Point1 const& pj, Point1 const& pk,
+ Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ bool is_p_first, bool is_p_last,
+ bool is_q_first, bool is_q_last,
+ TurnInfo const& tp_model,
+ RobustPolicy const& robust_policy,
+ OutputIterator out)
+ {
+ typedef intersection_info<Point1, Point2, typename TurnInfo::point_type, RobustPolicy>
+ inters_info;
+
+ inters_info inters(pi, pj, pk, qi, qj, qk, robust_policy);
+
+ char const method = inters.d_info().how;
+
+ // Copy, to copy possibly extended fields
+ TurnInfo tp = tp_model;
+
+ // Select method and apply
+ switch(method)
+ {
+ case 'a' : // collinear, "at"
+ case 'f' : // collinear, "from"
+ case 's' : // starts from the middle
+ get_turn_info_for_endpoint<AssignPolicy, true, true>
+ ::apply(pi, pj, pk, qi, qj, qk,
+ is_p_first, is_p_last, is_q_first, is_q_last,
+ tp_model, inters, method_none, out);
+ break;
+
+ case 'd' : // disjoint: never do anything
+ break;
+
+ case 'm' :
+ {
+ if ( get_turn_info_for_endpoint<AssignPolicy, false, true>
+ ::apply(pi, pj, pk, qi, qj, qk,
+ is_p_first, is_p_last, is_q_first, is_q_last,
+ tp_model, inters, method_touch_interior, out) )
+ {
+ // do nothing
+ }
+ else
+ {
+ typedef touch_interior
+ <
+ TurnInfo
+ > policy;
+
+ // If Q (1) arrives (1)
+ if ( inters.d_info().arrival[1] == 1)
+ {
+ policy::template apply<0>(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(),
+ inters.sides());
+ }
+ else
+ {
+ // Swap p/q
+ side_calculator
+ <
+ typename inters_info::robust_point2_type,
+ typename inters_info::robust_point1_type
+ > swapped_side_calc(inters.rqi(), inters.rqj(), inters.rqk(),
+ inters.rpi(), inters.rpj(), inters.rpk());
+
+ policy::template apply<1>(qi, qj, qk, pi, pj, pk,
+ tp, inters.i_info(), inters.d_info(),
+ swapped_side_calc);
+ }
+
+ if ( tp.operations[0].operation == operation_blocked )
+ {
+ tp.operations[1].is_collinear = true;
+ }
+ if ( tp.operations[1].operation == operation_blocked )
+ {
+ tp.operations[0].is_collinear = true;
+ }
+
+ replace_method_and_operations_tm(tp.method,
+ tp.operations[0].operation,
+ tp.operations[1].operation);
+
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+ *out++ = tp;
+ }
+ }
+ break;
+ case 'i' :
+ {
+ crosses<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info());
+
+ replace_operations_i(tp.operations[0].operation, tp.operations[1].operation);
+
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+ *out++ = tp;
+ }
+ break;
+ case 't' :
+ {
+ // Both touch (both arrive there)
+ if ( get_turn_info_for_endpoint<AssignPolicy, false, true>
+ ::apply(pi, pj, pk, qi, qj, qk,
+ is_p_first, is_p_last, is_q_first, is_q_last,
+ tp_model, inters, method_touch, out) )
+ {
+ // do nothing
+ }
+ else
+ {
+ touch<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(), inters.sides());
+
+ // workarounds for touch<> not taking spikes into account starts here
+ // those was discovered empirically
+ // touch<> is not symmetrical!
+ // P spikes and Q spikes may produce various operations!
+ // TODO: this is not optimal solution - think about rewriting touch<>
+
+ if ( tp.operations[0].operation == operation_blocked
+ && tp.operations[1].operation == operation_blocked )
+ {
+ // two touching spikes on the same line
+ if ( inters.is_spike_p() && inters.is_spike_q() )
+ {
+ tp.operations[0].operation = operation_union;
+ tp.operations[1].operation = operation_union;
+ }
+ else
+ {
+ tp.operations[0].is_collinear = true;
+ tp.operations[1].is_collinear = true;
+ }
+ }
+ else if ( tp.operations[0].operation == operation_blocked )
+ {
+ // a spike on P on the same line with Q1
+ if ( inters.is_spike_p() )
+ {
+ if ( inters.sides().qk_wrt_p1() == 0 )
+ {
+ tp.operations[0].is_collinear = true;
+ }
+ else
+ {
+ tp.operations[0].operation = operation_union;
+ }
+ }
+ else
+ {
+ tp.operations[1].is_collinear = true;
+ }
+ }
+ else if ( tp.operations[1].operation == operation_blocked )
+ {
+ // a spike on Q on the same line with P1
+ if ( inters.is_spike_q() )
+ {
+ if ( inters.sides().pk_wrt_q1() == 0 )
+ {
+ tp.operations[1].is_collinear = true;
+ }
+ else
+ {
+ tp.operations[1].operation = operation_union;
+ }
+ }
+ else
+ {
+ tp.operations[0].is_collinear = true;
+ }
+ }
+ else if ( tp.operations[0].operation == operation_continue
+ && tp.operations[1].operation == operation_continue )
+ {
+ // P spike on the same line with Q2 (opposite)
+ if ( inters.sides().pk_wrt_q1() == -inters.sides().qk_wrt_q1()
+ && inters.is_spike_p() )
+ {
+ tp.operations[0].operation = operation_union;
+ tp.operations[1].operation = operation_union;
+ }
+ }
+ else if ( tp.operations[0].operation == operation_none
+ && tp.operations[1].operation == operation_none )
+ {
+ // spike not handled by touch<>
+ bool const is_p = inters.is_spike_p();
+ bool const is_q = inters.is_spike_q();
+
+ if ( is_p || is_q )
+ {
+ tp.operations[0].operation = operation_union;
+ tp.operations[1].operation = operation_union;
+
+ if ( inters.sides().pk_wrt_q2() == 0 )
+ {
+ tp.operations[0].operation = operation_continue; // will be converted to i
+ if ( is_p )
+ {
+ tp.operations[0].is_collinear = true;
+ }
+ }
+
+ if ( inters.sides().qk_wrt_p2() == 0 )
+ {
+ tp.operations[1].operation = operation_continue; // will be converted to i
+ if ( is_q )
+ {
+ tp.operations[1].is_collinear = true;
+ }
+ }
+ }
+ }
+
+ // workarounds for touch<> not taking spikes into account ends here
+
+ replace_method_and_operations_tm(tp.method,
+ tp.operations[0].operation,
+ tp.operations[1].operation);
+
+// TODO: move this into the append_xxx and call for each turn?
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+
+ if ( ! handle_spikes
+ || ! append_opposite_spikes<append_touches>(tp, inters,
+ is_p_last, is_q_last,
+ out) )
+ {
+ *out++ = tp;
+ }
+ }
+ }
+ break;
+ case 'e':
+ {
+ if ( get_turn_info_for_endpoint<AssignPolicy, true, true>
+ ::apply(pi, pj, pk, qi, qj, qk,
+ is_p_first, is_p_last, is_q_first, is_q_last,
+ tp_model, inters, method_equal, out) )
+ {
+ // do nothing
+ }
+ else
+ {
+ tp.operations[0].is_collinear = true;
+ tp.operations[1].is_collinear = true;
+
+ if ( ! inters.d_info().opposite )
+ {
+ // Both equal
+ // or collinear-and-ending at intersection point
+ equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(), inters.sides());
+
+ // transform turn
+ turn_transformer_ec transformer(method_touch);
+ transformer(tp);
+
+// TODO: move this into the append_xxx and call for each turn?
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+
+ // conditionally handle spikes
+ if ( ! handle_spikes
+ || ! append_collinear_spikes(tp, inters,
+ is_p_last, is_q_last,
+ method_touch, operation_union,
+ out) )
+ {
+ *out++ = tp; // no spikes
+ }
+ }
+ else
+ {
+ // TODO: ignore for spikes or generate something else than opposite?
+
+ equal_opposite
+ <
+ TurnInfo,
+ AssignPolicy
+ >::apply(pi, qi, tp, out, inters.i_info(), inters.d_info());
+ }
+ }
+ }
+ break;
+ case 'c' :
+ {
+ // Collinear
+ if ( get_turn_info_for_endpoint<AssignPolicy, true, true>
+ ::apply(pi, pj, pk, qi, qj, qk,
+ is_p_first, is_p_last, is_q_first, is_q_last,
+ tp_model, inters, method_collinear, out) )
+ {
+ // do nothing
+ }
+ else
+ {
+ // NOTE: this is for spikes since those are set in the turn_transformer_ec
+ tp.operations[0].is_collinear = true;
+ tp.operations[1].is_collinear = true;
+
+ if ( ! inters.d_info().opposite )
+ {
+ method_type method_replace = method_touch_interior;
+ operation_type spike_op = operation_continue;
+
+ if ( inters.d_info().arrival[0] == 0 )
+ {
+ // Collinear, but similar thus handled as equal
+ equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(), inters.sides());
+
+ method_replace = method_touch;
+ spike_op = operation_union;
+ }
+ else
+ {
+ collinear<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
+ tp, inters.i_info(), inters.d_info(), inters.sides());
+
+ //method_replace = method_touch_interior;
+ //spike_op = operation_continue;
+ }
+
+ // transform turn
+ turn_transformer_ec transformer(method_replace);
+ transformer(tp);
+
+// TODO: move this into the append_xxx and call for each turn?
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+
+ // conditionally handle spikes
+ if ( ! handle_spikes
+ || ! append_collinear_spikes(tp, inters,
+ is_p_last, is_q_last,
+ method_replace, spike_op,
+ out) )
+ {
+ // no spikes
+ *out++ = tp;
+ }
+ }
+ else
+ {
+ // If this always 'm' ?
+ turn_transformer_ec transformer(method_touch_interior);
+
+ // conditionally handle spikes
+ if ( handle_spikes )
+ {
+ append_opposite_spikes<append_collinear_opposite>(tp, inters,
+ is_p_last, is_q_last,
+ out);
+ }
+
+ // TODO: ignore for spikes?
+ // E.g. pass is_p_valid = !is_p_last && !is_pj_spike,
+ // the same with is_q_valid
+
+ collinear_opposite
+ <
+ TurnInfo,
+ AssignPolicy
+ >::apply(pi, pj, pk, qi, qj, qk,
+ tp, out, inters.i_info(), inters.d_info(), inters.sides(),
+ transformer, !is_p_last, !is_q_last);
+ }
+ }
+ }
+ break;
+ case '0' :
+ {
+ // degenerate points
+ if (AssignPolicy::include_degenerate)
+ {
+ only_convert::apply(tp, inters.i_info());
+
+ // if any, only one of those should be true
+ if ( is_p_first
+ && equals::equals_point_point(pi, tp.point) )
+ {
+ tp.operations[0].position = position_front;
+ }
+ else if ( is_p_last
+ && equals::equals_point_point(pj, tp.point) )
+ {
+ tp.operations[0].position = position_back;
+ }
+ else if ( is_q_first
+ && equals::equals_point_point(qi, tp.point) )
+ {
+ tp.operations[1].position = position_front;
+ }
+ else if ( is_q_last
+ && equals::equals_point_point(qj, tp.point) )
+ {
+ tp.operations[1].position = position_back;
+ }
+
+ AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+ *out++ = tp;
+ }
+ }
+ break;
+ default :
+ {
+#if defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS)
+ std::cout << "TURN: Unknown method: " << method << std::endl;
+#endif
+#if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW)
+ throw turn_info_exception(method);
+#endif
+ }
+ break;
+ }
+
+ return out;
+ }
+
+ template <typename TurnInfo,
+ typename IntersectionInfo,
+ typename OutIt>
+ static inline bool append_collinear_spikes(TurnInfo & tp,
+ IntersectionInfo const& inters_info,
+ bool is_p_last, bool is_q_last,
+ method_type method, operation_type spike_op,
+ OutIt out)
+ {
+ // method == touch || touch_interior
+ // both position == middle
+
+ bool is_p_spike = tp.operations[0].operation == spike_op
+ && ! is_p_last
+ && inters_info.is_spike_p();
+ bool is_q_spike = tp.operations[1].operation == spike_op
+ && ! is_q_last
+ && inters_info.is_spike_q();
+
+ if ( is_p_spike && is_q_spike )
+ {
+ tp.method = method;
+ tp.operations[0].operation = operation_blocked;
+ tp.operations[1].operation = operation_blocked;
+ *out++ = tp;
+ tp.operations[0].operation = operation_intersection;
+ tp.operations[1].operation = operation_intersection;
+ *out++ = tp;
+
+ return true;
+ }
+ else if ( is_p_spike )
+ {
+ tp.method = method;
+ tp.operations[0].operation = operation_blocked;
+ tp.operations[1].operation = operation_union;
+ *out++ = tp;
+ tp.operations[0].operation = operation_intersection;
+ //tp.operations[1].operation = operation_union;
+ *out++ = tp;
+
+ return true;
+ }
+ else if ( is_q_spike )
+ {
+ tp.method = method;
+ tp.operations[0].operation = operation_union;
+ tp.operations[1].operation = operation_blocked;
+ *out++ = tp;
+ //tp.operations[0].operation = operation_union;
+ tp.operations[1].operation = operation_intersection;
+ *out++ = tp;
+
+ return true;
+ }
+
+ return false;
+ }
+
+ enum append_version { append_touches, append_collinear_opposite };
+
+ template <append_version Version,
+ typename TurnInfo,
+ typename IntersectionInfo,
+ typename OutIt>
+ static inline bool append_opposite_spikes(TurnInfo & tp,
+ IntersectionInfo const& inters,
+ bool is_p_last, bool is_q_last,
+ OutIt out)
+ {
+ bool is_p_spike = ( Version == append_touches ?
+ ( tp.operations[0].operation == operation_continue
+ || tp.operations[0].operation == operation_intersection ) :
+ true )
+ && ! is_p_last
+ && inters.is_spike_p();
+ bool is_q_spike = ( Version == append_touches ?
+ ( tp.operations[1].operation == operation_continue
+ || tp.operations[1].operation == operation_intersection ) :
+ true )
+ && ! is_q_last
+ && inters.is_spike_q();
+
+ bool res = false;
+
+ if ( is_p_spike && ( Version == append_touches || inters.d_info().arrival[0] == 1 ) )
+ {
+ if ( Version == append_touches )
+ {
+ tp.operations[0].is_collinear = true;
+ tp.operations[1].is_collinear = false;
+ tp.method = method_touch;
+ }
+ else // Version == append_collinear_opposite
+ {
+ tp.operations[0].is_collinear = true;
+ tp.operations[1].is_collinear = false;
+
+ BOOST_ASSERT(inters.i_info().count > 1);
+
+ base_turn_handler::assign_point(tp, method_touch_interior,
+ inters.i_info(), 1);
+
+ AssignPolicy::apply(tp, inters.pi(), inters.qi(),
+ inters.i_info(), inters.d_info());
+ }
+
+ tp.operations[0].operation = operation_blocked;
+ tp.operations[1].operation = operation_intersection;
+ *out++ = tp;
+ tp.operations[0].operation = operation_intersection;
+ //tp.operations[1].operation = operation_intersection;
+ *out++ = tp;
+
+ res = true;
+ }
+
+ if ( is_q_spike && ( Version == append_touches || inters.d_info().arrival[1] == 1 ) )
+ {
+ if ( Version == append_touches )
+ {
+ tp.operations[0].is_collinear = false;
+ tp.operations[1].is_collinear = true;
+ tp.method = method_touch;
+ }
+ else // Version == append_collinear_opposite
+ {
+ tp.operations[0].is_collinear = false;
+ tp.operations[1].is_collinear = true;
+
+ BOOST_ASSERT(inters.i_info().count > 0);
+
+ base_turn_handler::assign_point(tp, method_touch_interior, inters.i_info(), 0);
+
+ AssignPolicy::apply(tp, inters.pi(), inters.qi(),
+ inters.i_info(), inters.d_info());
+ }
+
+ tp.operations[0].operation = operation_intersection;
+ tp.operations[1].operation = operation_blocked;
+ *out++ = tp;
+ //tp.operations[0].operation = operation_intersection;
+ tp.operations[1].operation = operation_intersection;
+ *out++ = tp;
+
+ res = true;
+ }
+
+ return res;
+ }
+
+ static inline void replace_method_and_operations_tm(method_type & method,
+ operation_type & op0,
+ operation_type & op1)
+ {
+ if ( op0 == operation_blocked && op1 == operation_blocked )
+ {
+ // NOTE: probably only if methods are WRT IPs, not segments!
+ method = (method == method_touch ? method_equal : method_collinear);
+ op0 = operation_continue;
+ op1 = operation_continue;
+ }
+ else
+ {
+ if ( op0 == operation_continue || op0 == operation_blocked )
+ {
+ op0 = operation_intersection;
+ }
+ else if ( op0 == operation_intersection )
+ {
+ op0 = operation_union;
+ }
+
+ if ( op1 == operation_continue || op1 == operation_blocked )
+ {
+ op1 = operation_intersection;
+ }
+ else if ( op1 == operation_intersection )
+ {
+ op1 = operation_union;
+ }
+
+ // spikes in 'm'
+ if ( method == method_error )
+ {
+ method = method_touch_interior;
+ op0 = operation_union;
+ op1 = operation_union;
+ }
+ }
+ }
+
+ class turn_transformer_ec
+ {
+ public:
+ explicit turn_transformer_ec(method_type method_t_or_m)
+ : m_method(method_t_or_m)
+ {}
+
+ template <typename Turn>
+ void operator()(Turn & turn) const
+ {
+ operation_type & op0 = turn.operations[0].operation;
+ operation_type & op1 = turn.operations[1].operation;
+
+ BOOST_ASSERT(op0 != operation_blocked || op1 != operation_blocked );
+
+ if ( op0 == operation_blocked )
+ {
+ op0 = operation_intersection;
+ }
+ else if ( op0 == operation_intersection )
+ {
+ op0 = operation_union;
+ }
+
+ if ( op1 == operation_blocked )
+ {
+ op1 = operation_intersection;
+ }
+ else if ( op1 == operation_intersection )
+ {
+ op1 = operation_union;
+ }
+
+ if ( op0 == operation_intersection || op0 == operation_union
+ || op1 == operation_intersection || op1 == operation_union )
+ {
+ turn.method = m_method;
+ }
+
+// TODO: is this correct?
+// it's equivalent to comparing to operation_blocked at the beginning of the function
+ turn.operations[0].is_collinear = op0 != operation_intersection;
+ turn.operations[1].is_collinear = op1 != operation_intersection;
+ }
+
+ private:
+ method_type m_method;
+ };
+
+ static inline void replace_operations_i(operation_type & op0, operation_type & op1)
+ {
+ if ( op0 == operation_intersection )
+ {
+ op0 = operation_union;
+ }
+
+ if ( op1 == operation_intersection )
+ {
+ op1 = operation_union;
+ }
+ }
+};
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_LL_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/get_turns.hpp b/boost/geometry/algorithms/detail/overlay/get_turns.hpp
index 26629043cb..a96538c43a 100644
--- a/boost/geometry/algorithms/detail/overlay/get_turns.hpp
+++ b/boost/geometry/algorithms/detail/overlay/get_turns.hpp
@@ -1,11 +1,17 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014 Oracle and/or its affiliates.
// 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)
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURNS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURNS_HPP
@@ -14,19 +20,17 @@
#include <map>
#include <boost/array.hpp>
+#include <boost/concept_check.hpp>
#include <boost/mpl/if.hpp>
#include <boost/range.hpp>
-#include <boost/typeof/typeof.hpp>
-
-#include <boost/tuple/tuple.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
-#include <boost/geometry/core/reverse_dispatch.hpp>
-
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/core/reverse_dispatch.hpp>
#include <boost/geometry/core/ring_type.hpp>
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
@@ -44,17 +48,22 @@
#include <boost/geometry/strategies/intersection.hpp>
#include <boost/geometry/strategies/intersection_result.hpp>
-#include <boost/geometry/algorithms/detail/disjoint.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/point_point.hpp>
+
+#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
#include <boost/geometry/algorithms/detail/partition.hpp>
-#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
+#include <boost/geometry/algorithms/detail/recalculate.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp>
#include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
-
#include <boost/geometry/algorithms/detail/sections/range_by_section.hpp>
+#include <boost/geometry/algorithms/detail/sections/sectionalize.hpp>
#include <boost/geometry/algorithms/expand.hpp>
-#include <boost/geometry/algorithms/detail/sections/sectionalize.hpp>
#ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION
# include <sstream>
@@ -65,6 +74,12 @@
namespace boost { namespace geometry
{
+// Silence warning C4127: conditional expression is constant
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4127)
+#endif
+
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace get_turns
@@ -88,9 +103,7 @@ template
typename Geometry1, typename Geometry2,
bool Reverse1, bool Reverse2,
typename Section1, typename Section2,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
+ typename TurnPolicy
>
class get_turns_in_sections
{
@@ -138,16 +151,21 @@ class get_turns_in_sections
// About first condition: will be optimized by compiler (static)
// It checks if it is areal (box,ring,(multi)polygon
int const n = int(section.range_count);
+
+ boost::ignore_unused_variable_warning(n);
+ boost::ignore_unused_variable_warning(index1);
+ boost::ignore_unused_variable_warning(index2);
+
return boost::is_same
<
typename tag_cast
<
- typename geometry::point_type<Geometry1>::type,
+ typename geometry::tag<Geometry>::type,
areal_tag
- >::type,
+ >::type,
areal_tag
>::value
- && index1 == 0
+ && index1 == 0
&& index2 >= n - 2
;
}
@@ -155,13 +173,27 @@ class get_turns_in_sections
public :
// Returns true if terminated, false if interrupted
+ template <typename Turns, typename RobustPolicy, typename InterruptPolicy>
static inline bool apply(
int source_id1, Geometry1 const& geometry1, Section1 const& sec1,
int source_id2, Geometry2 const& geometry2, Section2 const& sec2,
bool skip_larger,
+ RobustPolicy const& robust_policy,
Turns& turns,
InterruptPolicy& interrupt_policy)
{
+ boost::ignore_unused_variable_warning(interrupt_policy);
+
+ if ((sec1.duplicate && (sec1.count + 1) < sec1.range_count)
+ || (sec2.duplicate && (sec2.count + 1) < sec2.range_count))
+ {
+ // Skip sections containig only duplicates.
+ // They are still important (can indicate non-disjointness)
+ // but they will be found processing adjacent sections.
+ // Do NOT skip if they are the ONLY section
+ return true;
+ }
+
cview_type1 cview1(range_by_section(geometry1, sec1));
cview_type2 cview2(range_by_section(geometry2, sec2));
view_type1 view1(cview1);
@@ -186,7 +218,7 @@ public :
range1_iterator prev1, it1, end1;
get_start_point_iterator(sec1, view1, prev1, it1, end1,
- index1, ndi1, dir1, sec2.bounding_box);
+ index1, ndi1, dir1, sec2.bounding_box, robust_policy);
// We need a circular iterator because it might run through the closing point.
// One circle is actually enough but this one is just convenient.
@@ -197,12 +229,12 @@ public :
// section 2: [--------------]
// section 1: |----|---|---|---|---|
for (prev1 = it1++, next1++;
- it1 != end1 && ! exceeding<0>(dir1, *prev1, sec2.bounding_box);
+ it1 != end1 && ! exceeding<0>(dir1, *prev1, sec2.bounding_box, robust_policy);
++prev1, ++it1, ++index1, ++next1, ++ndi1)
{
ever_circling_iterator<range1_iterator> nd_next1(
begin_range_1, end_range_1, next1, true);
- advance_to_non_duplicate_next(nd_next1, it1, sec1);
+ advance_to_non_duplicate_next(nd_next1, it1, sec1, robust_policy);
int index2 = sec2.begin_index;
int ndi2 = sec2.non_duplicate_index;
@@ -210,12 +242,12 @@ public :
range2_iterator prev2, it2, end2;
get_start_point_iterator(sec2, view2, prev2, it2, end2,
- index2, ndi2, dir2, sec1.bounding_box);
+ index2, ndi2, dir2, sec1.bounding_box, robust_policy);
ever_circling_iterator<range2_iterator> next2(begin_range_2, end_range_2, it2, true);
next2++;
for (prev2 = it2++, next2++;
- it2 != end2 && ! exceeding<0>(dir2, *prev2, sec1.bounding_box);
+ it2 != end2 && ! exceeding<0>(dir2, *prev2, sec1.bounding_box, robust_policy);
++prev2, ++it2, ++index2, ++next2, ++ndi2)
{
bool skip = same_source;
@@ -241,24 +273,28 @@ public :
// Move to the "non duplicate next"
ever_circling_iterator<range2_iterator> nd_next2(
begin_range_2, end_range_2, next2, true);
- advance_to_non_duplicate_next(nd_next2, it2, sec2);
+ advance_to_non_duplicate_next(nd_next2, it2, sec2, robust_policy);
typedef typename boost::range_value<Turns>::type turn_info;
- typedef typename turn_info::point_type ip;
turn_info ti;
- ti.operations[0].seg_id = segment_identifier(source_id1,
- sec1.ring_id.multi_index, sec1.ring_id.ring_index, index1),
- ti.operations[1].seg_id = segment_identifier(source_id2,
- sec2.ring_id.multi_index, sec2.ring_id.ring_index, index2),
-
- ti.operations[0].other_id = ti.operations[1].seg_id;
- ti.operations[1].other_id = ti.operations[0].seg_id;
+ ti.operations[0].seg_id
+ = segment_identifier(source_id1, sec1.ring_id.multi_index,
+ sec1.ring_id.ring_index, index1);
+ ti.operations[1].seg_id
+ = segment_identifier(source_id2, sec2.ring_id.multi_index,
+ sec2.ring_id.ring_index, index2);
std::size_t const size_before = boost::size(turns);
+ bool const is_1_first = sec1.is_non_duplicate_first && index1 == sec1.begin_index;
+ bool const is_1_last = sec1.is_non_duplicate_last && index1+1 >= sec1.end_index;
+ bool const is_2_first = sec2.is_non_duplicate_first && index2 == sec2.begin_index;
+ bool const is_2_last = sec2.is_non_duplicate_last && index2+1 >= sec2.end_index;
+
TurnPolicy::apply(*prev1, *it1, *nd_next1, *prev2, *it2, *nd_next2,
- ti, std::back_inserter(turns));
+ is_1_first, is_1_last, is_2_first, is_2_last,
+ ti, robust_policy, std::back_inserter(turns));
if (InterruptPolicy::enabled)
{
@@ -283,24 +319,34 @@ private :
typedef typename model::referring_segment<point2_type const> segment2_type;
- template <size_t Dim, typename Point, typename Box>
- static inline bool preceding(int dir, Point const& point, Box const& box)
+ template <size_t Dim, typename Point, typename Box, typename RobustPolicy>
+ static inline bool preceding(int dir, Point const& point, Box const& box, RobustPolicy const& robust_policy)
{
- return (dir == 1 && get<Dim>(point) < get<min_corner, Dim>(box))
- || (dir == -1 && get<Dim>(point) > get<max_corner, Dim>(box));
+ typename robust_point_type<Point, RobustPolicy>::type robust_point;
+ geometry::recalculate(robust_point, point, robust_policy);
+ return (dir == 1 && get<Dim>(robust_point) < get<min_corner, Dim>(box))
+ || (dir == -1 && get<Dim>(robust_point) > get<max_corner, Dim>(box));
}
- template <size_t Dim, typename Point, typename Box>
- static inline bool exceeding(int dir, Point const& point, Box const& box)
+ template <size_t Dim, typename Point, typename Box, typename RobustPolicy>
+ static inline bool exceeding(int dir, Point const& point, Box const& box, RobustPolicy const& robust_policy)
{
- return (dir == 1 && get<Dim>(point) > get<max_corner, Dim>(box))
- || (dir == -1 && get<Dim>(point) < get<min_corner, Dim>(box));
+ typename robust_point_type<Point, RobustPolicy>::type robust_point;
+ geometry::recalculate(robust_point, point, robust_policy);
+ return (dir == 1 && get<Dim>(robust_point) > get<max_corner, Dim>(box))
+ || (dir == -1 && get<Dim>(robust_point) < get<min_corner, Dim>(box));
}
- template <typename Iterator, typename RangeIterator, typename Section>
+ template <typename Iterator, typename RangeIterator, typename Section, typename RobustPolicy>
static inline void advance_to_non_duplicate_next(Iterator& next,
- RangeIterator const& it, Section const& section)
+ RangeIterator const& it, Section const& section, RobustPolicy const& robust_policy)
{
+ typedef typename robust_point_type<point1_type, RobustPolicy>::type robust_point_type;
+ robust_point_type robust_point_from_it;
+ robust_point_type robust_point_from_next;
+ geometry::recalculate(robust_point_from_it, *it, robust_policy);
+ geometry::recalculate(robust_point_from_next, *next, robust_policy);
+
// To see where the next segments bend to, in case of touch/intersections
// on end points, we need (in case of degenerate/duplicate points) an extra
// iterator which moves to the REAL next point, so non duplicate.
@@ -311,10 +357,14 @@ private :
// So advance to the "non duplicate next"
// (the check is defensive, to avoid endless loops)
std::size_t check = 0;
- while(! detail::disjoint::disjoint_point_point(*it, *next)
+ while(! detail::disjoint::disjoint_point_point
+ (
+ robust_point_from_it, robust_point_from_next
+ )
&& check++ < section.range_count)
{
next++;
+ geometry::recalculate(robust_point_from_next, *next, robust_policy);
}
}
@@ -322,14 +372,14 @@ private :
// because of the logistics of "index" (the section-iterator automatically
// skips to the begin-point, we loose the index or have to recalculate it)
// So we mimic it here
- template <typename Range, typename Section, typename Box>
+ template <typename Range, typename Section, typename Box, typename RobustPolicy>
static inline void get_start_point_iterator(Section & section,
Range const& range,
typename boost::range_iterator<Range const>::type& it,
typename boost::range_iterator<Range const>::type& prev,
typename boost::range_iterator<Range const>::type& end,
int& index, int& ndi,
- int dir, Box const& other_bounding_box)
+ int dir, Box const& other_bounding_box, RobustPolicy const& robust_policy)
{
it = boost::begin(range) + section.begin_index;
end = boost::begin(range) + section.end_index + 1;
@@ -337,7 +387,7 @@ private :
// Mimic section-iterator:
// Skip to point such that section interects other box
prev = it++;
- for(; it != end && preceding<0>(dir, *it, other_bounding_box);
+ for(; it != end && preceding<0>(dir, *it, other_bounding_box, robust_policy);
prev = it++, index++, ndi++)
{}
// Go back one step because we want to start completely preceding
@@ -369,6 +419,7 @@ template
bool Reverse1, bool Reverse2,
typename Turns,
typename TurnPolicy,
+ typename RobustPolicy,
typename InterruptPolicy
>
struct section_visitor
@@ -377,14 +428,17 @@ struct section_visitor
Geometry1 const& m_geometry1;
int m_source_id2;
Geometry2 const& m_geometry2;
+ RobustPolicy const& m_rescale_policy;
Turns& m_turns;
InterruptPolicy& m_interrupt_policy;
section_visitor(int id1, Geometry1 const& g1,
int id2, Geometry2 const& g2,
+ RobustPolicy const& robust_policy,
Turns& turns, InterruptPolicy& ip)
: m_source_id1(id1), m_geometry1(g1)
, m_source_id2(id2), m_geometry2(g2)
+ , m_rescale_policy(robust_policy)
, m_turns(turns)
, m_interrupt_policy(ip)
{}
@@ -400,13 +454,12 @@ struct section_visitor
Geometry2,
Reverse1, Reverse2,
Section, Section,
- Turns,
- TurnPolicy,
- InterruptPolicy
+ TurnPolicy
>::apply(
m_source_id1, m_geometry1, sec1,
m_source_id2, m_geometry2, sec2,
false,
+ m_rescale_policy,
m_turns, m_interrupt_policy);
}
return true;
@@ -418,37 +471,45 @@ template
<
typename Geometry1, typename Geometry2,
bool Reverse1, bool Reverse2,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
+ typename TurnPolicy
>
class get_turns_generic
{
public:
+ template <typename RobustPolicy, typename Turns, typename InterruptPolicy>
static inline void apply(
int source_id1, Geometry1 const& geometry1,
int source_id2, Geometry2 const& geometry2,
- Turns& turns, InterruptPolicy& interrupt_policy)
+ RobustPolicy const& robust_policy,
+ Turns& turns,
+ InterruptPolicy& interrupt_policy)
{
// First create monotonic sections...
typedef typename boost::range_value<Turns>::type ip_type;
typedef typename ip_type::point_type point_type;
- typedef model::box<point_type> box_type;
+
+ typedef model::box
+ <
+ typename geometry::robust_point_type
+ <
+ point_type, RobustPolicy
+ >::type
+ > box_type;
typedef typename geometry::sections<box_type, 2> sections_type;
sections_type sec1, sec2;
- geometry::sectionalize<Reverse1>(geometry1, sec1, 0);
- geometry::sectionalize<Reverse2>(geometry2, sec2, 1);
+ geometry::sectionalize<Reverse1>(geometry1, robust_policy, true, sec1, 0);
+ geometry::sectionalize<Reverse2>(geometry2, robust_policy, true, sec2, 1);
// ... and then partition them, intersecting overlapping sections in visitor method
section_visitor
<
Geometry1, Geometry2,
Reverse1, Reverse2,
- Turns, TurnPolicy, InterruptPolicy
- > visitor(source_id1, geometry1, source_id2, geometry2, turns, interrupt_policy);
+ Turns, TurnPolicy, RobustPolicy, InterruptPolicy
+ > visitor(source_id1, geometry1, source_id2, geometry2, robust_policy, turns, interrupt_policy);
geometry::partition
<
@@ -463,13 +524,10 @@ template
<
typename Range, typename Box,
bool ReverseRange, bool ReverseBox,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
+ typename TurnPolicy
>
struct get_turns_cs
{
- typedef typename boost::range_value<Turns>::type turn_info;
typedef typename geometry::point_type<Range>::type point_type;
typedef typename geometry::point_type<Box>::type box_point_type;
@@ -491,14 +549,16 @@ struct get_turns_cs
>::type iterator_type;
+ template <typename RobustPolicy, typename Turns, typename InterruptPolicy>
static inline void apply(
int source_id1, Range const& range,
int source_id2, Box const& box,
+ RobustPolicy const& robust_policy,
Turns& turns,
InterruptPolicy& interrupt_policy,
int multi_index = -1, int ring_index = -1)
{
- if (boost::size(range) <= 1)
+ if ( boost::size(range) <= 1)
{
return;
}
@@ -509,6 +569,8 @@ struct get_turns_cs
cview_type cview(range);
view_type view(cview);
+ typename boost::range_size<view_type>::type segments_count1 = boost::size(view) - 1;
+
iterator_type it = boost::begin(view);
ever_circling_iterator<iterator_type> next(
@@ -557,9 +619,13 @@ struct get_turns_cs
get_turns_with_box(seg_id, source_id2,
*prev, *it, *next,
bp[0], bp[1], bp[2], bp[3],
+ // NOTE: some dummy values could be passed below since this would be called only for Polygons and Boxes
+ index == 0,
+ unsigned(index) == segments_count1,
+ robust_policy,
turns, interrupt_policy);
- // Future performance enhancement:
- // return if told by the interrupt policy
+ // Future performance enhancement:
+ // return if told by the interrupt policy
}
}
}
@@ -585,6 +651,7 @@ private:
else return 0;
}
+ template <typename RobustPolicy, typename Turns, typename InterruptPolicy>
static inline void get_turns_with_box(segment_identifier const& seg_id, int source_id2,
// Points from a range:
point_type const& rp0,
@@ -595,34 +662,45 @@ private:
box_point_type const& bp1,
box_point_type const& bp2,
box_point_type const& bp3,
+ bool const is_range_first,
+ bool const is_range_last,
+ RobustPolicy const& robust_policy,
// Output
Turns& turns,
InterruptPolicy& interrupt_policy)
{
+ boost::ignore_unused_variable_warning(interrupt_policy);
+
// Depending on code some relations can be left out
typedef typename boost::range_value<Turns>::type turn_info;
turn_info ti;
ti.operations[0].seg_id = seg_id;
- ti.operations[0].other_id = ti.operations[1].seg_id;
- ti.operations[1].other_id = seg_id;
ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 0);
TurnPolicy::apply(rp0, rp1, rp2, bp0, bp1, bp2,
- ti, std::back_inserter(turns));
+ is_range_first, is_range_last,
+ true, false,
+ ti, robust_policy, std::back_inserter(turns));
ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 1);
TurnPolicy::apply(rp0, rp1, rp2, bp1, bp2, bp3,
- ti, std::back_inserter(turns));
+ is_range_first, is_range_last,
+ false, false,
+ ti, robust_policy, std::back_inserter(turns));
ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 2);
TurnPolicy::apply(rp0, rp1, rp2, bp2, bp3, bp0,
- ti, std::back_inserter(turns));
+ is_range_first, is_range_last,
+ false, false,
+ ti, robust_policy, std::back_inserter(turns));
ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 3);
TurnPolicy::apply(rp0, rp1, rp2, bp3, bp0, bp1,
- ti, std::back_inserter(turns));
+ is_range_first, is_range_last,
+ false, true,
+ ti, robust_policy, std::back_inserter(turns));
if (InterruptPolicy::enabled)
{
@@ -638,15 +716,15 @@ template
<
typename Polygon, typename Box,
bool Reverse, bool ReverseBox,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
+ typename TurnPolicy
>
struct get_turns_polygon_cs
{
+ template <typename RobustPolicy, typename Turns, typename InterruptPolicy>
static inline void apply(
int source_id1, Polygon const& polygon,
int source_id2, Box const& box,
+ RobustPolicy const& robust_policy,
Turns& turns, InterruptPolicy& interrupt_policy,
int multi_index = -1)
{
@@ -656,32 +734,118 @@ struct get_turns_polygon_cs
<
ring_type, Box,
Reverse, ReverseBox,
- Turns,
- TurnPolicy,
- InterruptPolicy
+ TurnPolicy
> intersector_type;
intersector_type::apply(
source_id1, geometry::exterior_ring(polygon),
- source_id2, box, turns, interrupt_policy,
+ source_id2, box,
+ robust_policy,
+ turns, interrupt_policy,
multi_index, -1);
int i = 0;
- typename interior_return_type<Polygon const>::type rings
- = interior_rings(polygon);
- for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings);
- ++it, ++i)
+ typename interior_return_type<Polygon const>::type
+ rings = interior_rings(polygon);
+ for (typename detail::interior_iterator<Polygon const>::type
+ it = boost::begin(rings); it != boost::end(rings); ++it, ++i)
{
intersector_type::apply(
source_id1, *it,
- source_id2, box, turns, interrupt_policy,
+ source_id2, box,
+ robust_policy,
+ turns, interrupt_policy,
multi_index, i);
}
}
};
+
+template
+<
+ typename Multi, typename Box,
+ bool Reverse, bool ReverseBox,
+ typename TurnPolicy
+>
+struct get_turns_multi_polygon_cs
+{
+ template <typename RobustPolicy, typename Turns, typename InterruptPolicy>
+ static inline void apply(
+ int source_id1, Multi const& multi,
+ int source_id2, Box const& box,
+ RobustPolicy const& robust_policy,
+ Turns& turns, InterruptPolicy& interrupt_policy)
+ {
+ typedef typename boost::range_iterator
+ <
+ Multi const
+ >::type iterator_type;
+
+ int i = 0;
+ for (iterator_type it = boost::begin(multi);
+ it != boost::end(multi);
+ ++it, ++i)
+ {
+ // Call its single version
+ get_turns_polygon_cs
+ <
+ typename boost::range_value<Multi>::type, Box,
+ Reverse, ReverseBox,
+ TurnPolicy
+ >::apply(source_id1, *it, source_id2, box,
+ robust_policy, turns, interrupt_policy, i);
+ }
+ }
+};
+
+
+// GET_TURN_INFO_TYPE
+
+template <typename Geometry>
+struct topological_tag_base
+{
+ typedef typename tag_cast<typename tag<Geometry>::type, pointlike_tag, linear_tag, areal_tag>::type type;
+};
+
+template <typename Geometry1, typename Geometry2, typename AssignPolicy,
+ typename Tag1 = typename tag<Geometry1>::type, typename Tag2 = typename tag<Geometry2>::type,
+ typename TagBase1 = typename topological_tag_base<Geometry1>::type, typename TagBase2 = typename topological_tag_base<Geometry2>::type>
+struct get_turn_info_type
+ : overlay::get_turn_info<AssignPolicy>
+{};
+
+template <typename Geometry1, typename Geometry2, typename AssignPolicy, typename Tag1, typename Tag2>
+struct get_turn_info_type<Geometry1, Geometry2, AssignPolicy, Tag1, Tag2, linear_tag, linear_tag>
+ : overlay::get_turn_info_linear_linear<AssignPolicy>
+{};
+
+template <typename Geometry1, typename Geometry2, typename AssignPolicy, typename Tag1, typename Tag2>
+struct get_turn_info_type<Geometry1, Geometry2, AssignPolicy, Tag1, Tag2, linear_tag, areal_tag>
+ : overlay::get_turn_info_linear_areal<AssignPolicy>
+{};
+
+template <typename Geometry1, typename Geometry2, typename SegmentRatio,
+ typename Tag1 = typename tag<Geometry1>::type, typename Tag2 = typename tag<Geometry2>::type,
+ typename TagBase1 = typename topological_tag_base<Geometry1>::type, typename TagBase2 = typename topological_tag_base<Geometry2>::type>
+struct turn_operation_type
+{
+ typedef overlay::turn_operation<SegmentRatio> type;
+};
+
+template <typename Geometry1, typename Geometry2, typename SegmentRatio, typename Tag1, typename Tag2>
+struct turn_operation_type<Geometry1, Geometry2, SegmentRatio, Tag1, Tag2, linear_tag, linear_tag>
+{
+ typedef overlay::turn_operation_linear<SegmentRatio> type;
+};
+
+template <typename Geometry1, typename Geometry2, typename SegmentRatio, typename Tag1, typename Tag2>
+struct turn_operation_type<Geometry1, Geometry2, SegmentRatio, Tag1, Tag2, linear_tag, areal_tag>
+{
+ typedef overlay::turn_operation_linear<SegmentRatio> type;
+};
+
}} // namespace detail::get_turns
#endif // DOXYGEN_NO_DETAIL
@@ -697,18 +861,14 @@ template
typename GeometryTag1, typename GeometryTag2,
typename Geometry1, typename Geometry2,
bool Reverse1, bool Reverse2,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
+ typename TurnPolicy
>
struct get_turns
: detail::get_turns::get_turns_generic
<
Geometry1, Geometry2,
Reverse1, Reverse2,
- Turns,
- TurnPolicy,
- InterruptPolicy
+ TurnPolicy
>
{};
@@ -717,23 +877,19 @@ template
<
typename Polygon, typename Box,
bool ReversePolygon, bool ReverseBox,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
+ typename TurnPolicy
>
struct get_turns
<
polygon_tag, box_tag,
Polygon, Box,
ReversePolygon, ReverseBox,
- Turns,
- TurnPolicy,
- InterruptPolicy
+ TurnPolicy
> : detail::get_turns::get_turns_polygon_cs
<
Polygon, Box,
ReversePolygon, ReverseBox,
- Turns, TurnPolicy, InterruptPolicy
+ TurnPolicy
>
{};
@@ -742,22 +898,18 @@ template
<
typename Ring, typename Box,
bool ReverseRing, bool ReverseBox,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
+ typename TurnPolicy
>
struct get_turns
<
ring_tag, box_tag,
Ring, Box,
ReverseRing, ReverseBox,
- Turns,
- TurnPolicy,
- InterruptPolicy
+ TurnPolicy
> : detail::get_turns::get_turns_cs
<
Ring, Box, ReverseRing, ReverseBox,
- Turns, TurnPolicy, InterruptPolicy
+ TurnPolicy
>
{};
@@ -765,28 +917,52 @@ struct get_turns
template
<
+ typename MultiPolygon,
+ typename Box,
+ bool ReverseMultiPolygon, bool ReverseBox,
+ typename TurnPolicy
+>
+struct get_turns
+ <
+ multi_polygon_tag, box_tag,
+ MultiPolygon, Box,
+ ReverseMultiPolygon, ReverseBox,
+ TurnPolicy
+ >
+ : detail::get_turns::get_turns_multi_polygon_cs
+ <
+ MultiPolygon, Box,
+ ReverseMultiPolygon, ReverseBox,
+ TurnPolicy
+ >
+{};
+
+
+template
+<
typename GeometryTag1, typename GeometryTag2,
typename Geometry1, typename Geometry2,
bool Reverse1, bool Reverse2,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
+ typename TurnPolicy
>
struct get_turns_reversed
{
+ template <typename RobustPolicy, typename Turns, typename InterruptPolicy>
static inline void apply(
int source_id1, Geometry1 const& g1,
int source_id2, Geometry2 const& g2,
- Turns& turns, InterruptPolicy& interrupt_policy)
+ RobustPolicy const& robust_policy,
+ Turns& turns,
+ InterruptPolicy& interrupt_policy)
{
get_turns
<
GeometryTag2, GeometryTag1,
Geometry2, Geometry1,
Reverse2, Reverse1,
- Turns, TurnPolicy,
- InterruptPolicy
- >::apply(source_id2, g2, source_id1, g1, turns, interrupt_policy);
+ TurnPolicy
+ >::apply(source_id2, g2, source_id1, g1, robust_policy,
+ turns, interrupt_policy);
}
};
@@ -804,6 +980,7 @@ struct get_turns_reversed
\tparam Turns type of turn-container (e.g. vector of "intersection/turn point"'s)
\param geometry1 \param_geometry
\param geometry2 \param_geometry
+\param robust_policy policy to handle robustness issues
\param turns container which will contain turn points
\param interrupt_policy policy determining if process is stopped
when intersection is found
@@ -814,31 +991,20 @@ template
typename AssignPolicy,
typename Geometry1,
typename Geometry2,
+ typename RobustPolicy,
typename Turns,
typename InterruptPolicy
>
inline void get_turns(Geometry1 const& geometry1,
Geometry2 const& geometry2,
+ RobustPolicy const& robust_policy,
Turns& turns,
InterruptPolicy& interrupt_policy)
{
concept::check_concepts_and_equal_dimensions<Geometry1 const, Geometry2 const>();
- typedef typename strategy_intersection
- <
- typename cs_tag<Geometry1>::type,
- Geometry1,
- Geometry2,
- typename boost::range_value<Turns>::type
- >::segment_intersection_strategy_type segment_intersection_strategy_type;
-
- typedef detail::overlay::get_turn_info
- <
- typename point_type<Geometry1>::type,
- typename point_type<Geometry2>::type,
- typename boost::range_value<Turns>::type,
- AssignPolicy
- > TurnPolicy;
+ typedef detail::overlay::get_turn_info<AssignPolicy> TurnPolicy;
+ //typedef detail::get_turns::get_turn_info_type<Geometry1, Geometry2, AssignPolicy> TurnPolicy;
boost::mpl::if_c
<
@@ -849,8 +1015,7 @@ inline void get_turns(Geometry1 const& geometry1,
typename tag<Geometry2>::type,
Geometry1, Geometry2,
Reverse1, Reverse2,
- Turns, TurnPolicy,
- InterruptPolicy
+ TurnPolicy
>,
dispatch::get_turns
<
@@ -858,15 +1023,18 @@ inline void get_turns(Geometry1 const& geometry1,
typename tag<Geometry2>::type,
Geometry1, Geometry2,
Reverse1, Reverse2,
- Turns, TurnPolicy,
- InterruptPolicy
+ TurnPolicy
>
>::type::apply(
0, geometry1,
1, geometry2,
+ robust_policy,
turns, interrupt_policy);
}
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
}} // namespace boost::geometry
diff --git a/boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp b/boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp
index 1e878ca525..085933dd7a 100644
--- a/boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp
+++ b/boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp
@@ -14,7 +14,17 @@
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
#include <boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+#include <boost/geometry/algorithms/detail/recalculate.hpp>
+#include <boost/geometry/policies/robustness/robust_point_type.hpp>
+#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
+#include <boost/geometry/policies/robustness/robust_type.hpp>
+
+#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES)
+#include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
+#endif
+
+#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/geometries/segment.hpp>
@@ -31,6 +41,7 @@ template
typename TurnPoints,
typename Indexed,
typename Geometry1, typename Geometry2,
+ typename RobustPolicy,
bool Reverse1, bool Reverse2,
typename Strategy
>
@@ -39,10 +50,12 @@ struct sort_in_cluster
inline sort_in_cluster(TurnPoints const& turn_points
, Geometry1 const& geometry1
, Geometry2 const& geometry2
+ , RobustPolicy const& robust_policy
, Strategy const& strategy)
: m_turn_points(turn_points)
, m_geometry1(geometry1)
, m_geometry2(geometry2)
+ , m_rescale_policy(robust_policy)
, m_strategy(strategy)
{}
@@ -51,49 +64,100 @@ private :
TurnPoints const& m_turn_points;
Geometry1 const& m_geometry1;
Geometry2 const& m_geometry2;
+ RobustPolicy const& m_rescale_policy;
Strategy const& m_strategy;
typedef typename Indexed::type turn_operation_type;
typedef typename geometry::point_type<Geometry1>::type point_type;
- typedef model::referring_segment<point_type const> segment_type;
+
+ typedef typename geometry::robust_point_type
+ <
+ point_type,
+ RobustPolicy
+ >::type robust_point_type;
+
+ // Still necessary in some situations,
+ // for example #case_102_multi, #case_107_multi, #case_recursive_boxes_3
+ inline void get_situation_map(Indexed const& left, Indexed const& right,
+ robust_point_type& pi_rob, robust_point_type& pj_rob,
+ robust_point_type& ri_rob, robust_point_type& rj_rob,
+ robust_point_type& si_rob, robust_point_type& sj_rob) const
+ {
+ point_type pi, pj, ri, rj, si, sj;
+
+ geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
+ left.subject->seg_id,
+ pi, pj);
+ geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
+ *left.other_seg_id,
+ ri, rj);
+ geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
+ *right.other_seg_id,
+ si, sj);
+
+ geometry::recalculate(pi_rob, pi, m_rescale_policy);
+ geometry::recalculate(pj_rob, pj, m_rescale_policy);
+ geometry::recalculate(ri_rob, ri, m_rescale_policy);
+ geometry::recalculate(rj_rob, rj, m_rescale_policy);
+ geometry::recalculate(si_rob, si, m_rescale_policy);
+ geometry::recalculate(sj_rob, sj, m_rescale_policy);
+ }
+
+#if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO
+ // This method was still called but did no effect whatsoever on the results,
+ // with or without robustness-rescaling.
+ // Probable cause: we rescale in this file ourselves, ignoring passed policy
+ // TODO: check this more.
+ // Besides this, it currently does not compile for yet unknown reasons
+ // (does not find specialization for segment_ratio_type)
+ // It is currently only called from the Unit Test "multi_intersection.cpp"
// Determine how p/r and p/s are located.
- template <typename P>
- static inline void overlap_info(P const& pi, P const& pj,
- P const& ri, P const& rj,
- P const& si, P const& sj,
- bool& pr_overlap, bool& ps_overlap, bool& rs_overlap)
+ inline void overlap_info(
+ robust_point_type const& pi, robust_point_type const& pj,
+ robust_point_type const& ri, robust_point_type const& rj,
+ robust_point_type const& si, robust_point_type const& sj,
+ bool& pr_overlap, bool& ps_overlap, bool& rs_overlap) const
{
// Determine how p/r and p/s are located.
// One of them is coming from opposite direction.
+ typedef segment_intersection_points
+ <
+ point_type,
+ typename segment_ratio_type
+ <
+ point_type, RobustPolicy
+ >::type
+ > intersection_return_type;
+
typedef strategy::intersection::relate_cartesian_segments
<
policies::relate::segments_intersection_points
<
- segment_type,
- segment_type,
- segment_intersection_points<point_type>
+ intersection_return_type
>
> policy;
+ typedef model::referring_segment<robust_point_type const> segment_type;
segment_type p(pi, pj);
segment_type r(ri, rj);
segment_type s(si, sj);
// Get the intersection point (or two points)
- segment_intersection_points<point_type> pr = policy::apply(p, r);
- segment_intersection_points<point_type> ps = policy::apply(p, s);
- segment_intersection_points<point_type> rs = policy::apply(r, s);
+ intersection_return_type pr = policy::apply(p, r, m_rescale_policy, pi, pj, ri, rj);
+ intersection_return_type ps = policy::apply(p, s, m_rescale_policy, pi, pj, si, sj);
+ intersection_return_type rs = policy::apply(r, s, m_rescale_policy, ri, rj, si, sj);
// Check on overlap
pr_overlap = pr.count == 2;
ps_overlap = ps.count == 2;
rs_overlap = rs.count == 2;
}
+#endif
-#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
+#ifdef BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES
inline void debug_consider(int order, Indexed const& left,
Indexed const& right, std::string const& header,
bool skip = true,
@@ -102,19 +166,15 @@ private :
{
if (skip) return;
- point_type pi, pj, ri, rj, si, sj;
- geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
- left.subject.seg_id,
- pi, pj);
- geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
- left.subject.other_id,
- ri, rj);
- geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
- right.subject.other_id,
- si, sj);
+ std::cout << "Case: " << header << " for " << left.turn_index << " / " << right.turn_index << std::endl;
+
+ robust_point_type pi, pj, ri, rj, si, sj;
+ get_situation_map(left, right, pi, pj, ri, rj, si, sj);
+#if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO
bool prc = false, psc = false, rsc = false;
overlap_info(pi, pj, ri, rj, si, sj, prc, psc, rsc);
+#endif
int const side_ri_p = m_strategy.apply(pi, pj, ri);
int const side_rj_p = m_strategy.apply(pi, pj, rj);
@@ -123,8 +183,7 @@ private :
int const side_si_r = m_strategy.apply(ri, rj, si);
int const side_sj_r = m_strategy.apply(ri, rj, sj);
- std::cout << "Case: " << header << " for " << left.index << " / " << right.index << std::endl;
-#ifdef BOOST_GEOMETRY_DEBUG_ENRICH_MORE
+#ifdef BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES_MORE
std::cout << " Segment p:" << geometry::wkt(pi) << " .. " << geometry::wkt(pj) << std::endl;
std::cout << " Segment r:" << geometry::wkt(ri) << " .. " << geometry::wkt(rj) << std::endl;
std::cout << " Segment s:" << geometry::wkt(si) << " .. " << geometry::wkt(sj) << std::endl;
@@ -136,13 +195,15 @@ private :
std::cout << header
//<< " order: " << order
- << " ops: " << operation_char(left.subject.operation)
- << "/" << operation_char(right.subject.operation)
+ << " ops: " << operation_char(left.subject->operation)
+ << "/" << operation_char(right.subject->operation)
<< " ri//p: " << side_ri_p
<< " si//p: " << side_si_p
<< " si//r: " << side_si_r
+#if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO
<< " cnts: " << int(prc) << "," << int(psc) << "," << int(rsc)
- //<< " idx: " << left.index << "/" << right.index
+#endif
+ //<< " idx: " << left.turn_index << "/" << right.turn_index
;
if (! extra.empty())
@@ -167,23 +228,23 @@ private :
, std::string const& // header
) const
{
- bool ret = left.index < right.index;
+ bool ret = left.turn_index < right.turn_index;
// In combination of u/x, x/u: take first union, then blocked.
// Solves #88, #61, #56, #80
- if (left.subject.operation == operation_union
- && right.subject.operation == operation_blocked)
+ if (left.subject->operation == operation_union
+ && right.subject->operation == operation_blocked)
{
ret = true;
}
- else if (left.subject.operation == operation_blocked
- && right.subject.operation == operation_union)
+ else if (left.subject->operation == operation_blocked
+ && right.subject->operation == operation_union)
{
ret = false;
}
else
{
-#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
+#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES)
std::cout << "ux/ux unhandled" << std::endl;
#endif
}
@@ -201,32 +262,32 @@ private :
{
bool ret = false;
- if (left.subject.operation == operation_union
- && right.subject.operation == operation_union)
+ if (left.subject->operation == operation_union
+ && right.subject->operation == operation_union)
{
ret = order == 1;
}
- else if (left.subject.operation == operation_union
- && right.subject.operation == operation_blocked)
+ else if (left.subject->operation == operation_union
+ && right.subject->operation == operation_blocked)
{
ret = true;
}
- else if (right.subject.operation == operation_union
- && left.subject.operation == operation_blocked)
+ else if (right.subject->operation == operation_union
+ && left.subject->operation == operation_blocked)
{
ret = false;
}
- else if (left.subject.operation == operation_union)
+ else if (left.subject->operation == operation_union)
{
ret = true;
}
- else if (right.subject.operation == operation_union)
+ else if (right.subject->operation == operation_union)
{
ret = false;
}
else
{
-#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
+#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES)
// this still happens in the traverse.cpp test
std::cout << " iu/ux unhandled" << std::endl;
#endif
@@ -245,43 +306,61 @@ private :
{
//debug_consider(order, left, right, header, false, "iu/ix");
- return left.subject.operation == operation_intersection
- && right.subject.operation == operation_intersection ? order == 1
- : left.subject.operation == operation_intersection ? false
- : right.subject.operation == operation_intersection ? true
+ return left.subject->operation == operation_intersection
+ && right.subject->operation == operation_intersection ? order == 1
+ : left.subject->operation == operation_intersection ? false
+ : right.subject->operation == operation_intersection ? true
: order == 1;
}
+ inline bool consider_ix_ix(Indexed const& left, Indexed const& right
+ , std::string const& // header
+ ) const
+ {
+ // Take first intersection, then blocked.
+ if (left.subject->operation == operation_intersection
+ && right.subject->operation == operation_blocked)
+ {
+ return true;
+ }
+ else if (left.subject->operation == operation_blocked
+ && right.subject->operation == operation_intersection)
+ {
+ return false;
+ }
+
+ // Default case, should not occur
+
+#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES)
+ std::cout << "ix/ix unhandled" << std::endl;
+#endif
+ //debug_consider(0, left, right, header, false, "-> return", ret);
+
+ return left.turn_index < right.turn_index;
+ }
+
inline bool consider_iu_iu(Indexed const& left, Indexed const& right,
- std::string const& header) const
+ std::string const& header, bool redo = false) const
{
//debug_consider(0, left, right, header);
// In general, order it like "union, intersection".
- if (left.subject.operation == operation_intersection
- && right.subject.operation == operation_union)
+ if (left.subject->operation == operation_intersection
+ && right.subject->operation == operation_union)
{
//debug_consider(0, left, right, header, false, "i,u", false);
return false;
}
- else if (left.subject.operation == operation_union
- && right.subject.operation == operation_intersection)
+ else if (left.subject->operation == operation_union
+ && right.subject->operation == operation_intersection)
{
//debug_consider(0, left, right, header, false, "u,i", true);
return true;
}
- point_type pi, pj, ri, rj, si, sj;
- geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
- left.subject.seg_id,
- pi, pj);
- geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
- left.subject.other_id,
- ri, rj);
- geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
- right.subject.other_id,
- si, sj);
+ robust_point_type pi, pj, ri, rj, si, sj;
+ get_situation_map(left, right, pi, pj, ri, rj, si, sj);
int const side_ri_p = m_strategy.apply(pi, pj, ri);
int const side_si_p = m_strategy.apply(pi, pj, si);
@@ -291,8 +370,8 @@ private :
if (side_ri_p * side_si_p == 1 && side_si_r != 0)
{
// Take the most left one
- if (left.subject.operation == operation_union
- && right.subject.operation == operation_union)
+ if (left.subject->operation == operation_union
+ && right.subject->operation == operation_union)
{
bool ret = side_si_r == 1;
//debug_consider(0, left, right, header, false, "same side", ret);
@@ -311,14 +390,18 @@ private :
debug_consider(0, left, right, header, false, "opp.", ret);
return ret;
}
-#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
+#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES)
std::cout << " iu/iu coming from opposite unhandled" << std::endl;
#endif
}
+#if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO
// We need EXTRA information here: are p/r/s overlapping?
bool pr_ov = false, ps_ov = false, rs_ov = false;
overlap_info(pi, pj, ri, rj, si, sj, pr_ov, ps_ov, rs_ov);
+#else
+ // std::cout << "Boost.Geometry: skipping overlap_info" << std::endl;
+#endif
// One coming from right (#83,#90)
// One coming from left (#90, #94, #95)
@@ -326,12 +409,14 @@ private :
{
bool ret = false;
+#if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO
if (pr_ov || ps_ov)
{
int r = side_ri_p != 0 ? side_ri_p : side_si_p;
ret = r * side_si_r == 1;
}
else
+#endif
{
ret = side_si_r == 1;
}
@@ -348,6 +433,7 @@ private :
// Take the one NOT overlapping
bool ret = false;
bool found = false;
+#if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO
if (pr_ov && ! ps_ov)
{
ret = true;
@@ -358,6 +444,7 @@ private :
ret = false;
found = true;
}
+#endif
debug_consider(0, left, right, header, false, "aligned", ret);
if (found)
@@ -366,11 +453,18 @@ private :
}
}
-#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
+#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES)
std::cout << " iu/iu unhandled" << std::endl;
- debug_consider(0, left, right, header, false, "unhandled", left.index < right.index);
+ debug_consider(0, left, right, header, false, "unhandled", left.turn_index < right.turn_index);
#endif
- return left.index < right.index;
+ if (! redo)
+ {
+ // In some cases behaviour is not symmetrical. TODO: fix this properly
+ // OR: alternatively we might consider calling all these functions one-way anyway
+ return ! consider_iu_iu(right, left, header, true);
+ }
+
+ return left.turn_index < right.turn_index;
}
inline bool consider_ii(Indexed const& left, Indexed const& right,
@@ -378,16 +472,8 @@ private :
{
debug_consider(0, left, right, header);
- point_type pi, pj, ri, rj, si, sj;
- geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
- left.subject.seg_id,
- pi, pj);
- geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
- left.subject.other_id,
- ri, rj);
- geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
- right.subject.other_id,
- si, sj);
+ robust_point_type pi, pj, ri, rj, si, sj;
+ get_situation_map(left, right, pi, pj, ri, rj, si, sj);
int const side_ri_p = m_strategy.apply(pi, pj, ri);
int const side_si_p = m_strategy.apply(pi, pj, si);
@@ -402,84 +488,89 @@ private :
bool const ret = side_si_r != 1;
return ret;
}
- return left.index < right.index;
+ return left.turn_index < right.turn_index;
}
public :
inline bool operator()(Indexed const& left, Indexed const& right) const
{
- bool const default_order = left.index < right.index;
+ bool const default_order = left.turn_index < right.turn_index;
- if ((m_turn_points[left.index].discarded || left.discarded)
- && (m_turn_points[right.index].discarded || right.discarded))
+ if ((m_turn_points[left.turn_index].discarded || left.discarded)
+ && (m_turn_points[right.turn_index].discarded || right.discarded))
{
return default_order;
}
- else if (m_turn_points[left.index].discarded || left.discarded)
+ else if (m_turn_points[left.turn_index].discarded || left.discarded)
{
// Be careful to sort discarded first, then all others
return true;
}
- else if (m_turn_points[right.index].discarded || right.discarded)
+ else if (m_turn_points[right.turn_index].discarded || right.discarded)
{
// See above so return false here such that right (discarded)
// is sorted before left (not discarded)
return false;
}
- else if (m_turn_points[left.index].combination(operation_blocked, operation_union)
- && m_turn_points[right.index].combination(operation_blocked, operation_union))
+ else if (m_turn_points[left.turn_index].combination(operation_blocked, operation_union)
+ && m_turn_points[right.turn_index].combination(operation_blocked, operation_union))
{
// ux/ux
return consider_ux_ux(left, right, "ux/ux");
}
- else if (m_turn_points[left.index].both(operation_union)
- && m_turn_points[right.index].both(operation_union))
+ else if (m_turn_points[left.turn_index].both(operation_union)
+ && m_turn_points[right.turn_index].both(operation_union))
{
// uu/uu, Order is arbitrary
// Note: uu/uu is discarded now before so this point will
// not be reached.
return default_order;
}
- else if (m_turn_points[left.index].combination(operation_intersection, operation_union)
- && m_turn_points[right.index].combination(operation_intersection, operation_union))
+ else if (m_turn_points[left.turn_index].combination(operation_intersection, operation_union)
+ && m_turn_points[right.turn_index].combination(operation_intersection, operation_union))
{
return consider_iu_iu(left, right, "iu/iu");
}
- else if (m_turn_points[left.index].both(operation_intersection)
- && m_turn_points[right.index].both(operation_intersection))
+ else if (m_turn_points[left.turn_index].combination(operation_intersection, operation_blocked)
+ && m_turn_points[right.turn_index].combination(operation_intersection, operation_blocked))
+ {
+ return consider_ix_ix(left, right, "ix/ix");
+ }
+ else if (m_turn_points[left.turn_index].both(operation_intersection)
+ && m_turn_points[right.turn_index].both(operation_intersection))
{
return consider_ii(left, right, "ii/ii");
}
- else if (m_turn_points[left.index].combination(operation_union, operation_blocked)
- && m_turn_points[right.index].combination(operation_intersection, operation_union))
+ else if (m_turn_points[left.turn_index].combination(operation_union, operation_blocked)
+ && m_turn_points[right.turn_index].combination(operation_intersection, operation_union))
{
return consider_iu_ux(left, right, -1, "ux/iu");
}
- else if (m_turn_points[left.index].combination(operation_intersection, operation_union)
- && m_turn_points[right.index].combination(operation_union, operation_blocked))
+ else if (m_turn_points[left.turn_index].combination(operation_intersection, operation_union)
+ && m_turn_points[right.turn_index].combination(operation_union, operation_blocked))
{
return consider_iu_ux(left, right, 1, "iu/ux");
}
- else if (m_turn_points[left.index].combination(operation_intersection, operation_blocked)
- && m_turn_points[right.index].combination(operation_intersection, operation_union))
+ else if (m_turn_points[left.turn_index].combination(operation_intersection, operation_blocked)
+ && m_turn_points[right.turn_index].combination(operation_intersection, operation_union))
{
return consider_iu_ix(left, right, 1, "ix/iu");
}
- else if (m_turn_points[left.index].combination(operation_intersection, operation_union)
- && m_turn_points[right.index].combination(operation_intersection, operation_blocked))
+ else if (m_turn_points[left.turn_index].combination(operation_intersection, operation_union)
+ && m_turn_points[right.turn_index].combination(operation_intersection, operation_blocked))
{
return consider_iu_ix(left, right, -1, "iu/ix");
}
- else if (m_turn_points[left.index].method != method_equal
- && m_turn_points[right.index].method == method_equal
+ else if (m_turn_points[left.turn_index].method != method_equal
+ && m_turn_points[right.turn_index].method == method_equal
)
{
// If one of them was EQUAL or CONTINUES, it should always come first
return false;
}
- else if (m_turn_points[left.index].method == method_equal
- && m_turn_points[right.index].method != method_equal
+ else if (m_turn_points[left.turn_index].method == method_equal
+ && m_turn_points[right.turn_index].method != method_equal
)
{
return true;
@@ -487,13 +578,13 @@ public :
// Now we have no clue how to sort.
-#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
- std::cout << " Consider: " << operation_char(m_turn_points[left.index].operations[0].operation)
- << operation_char(m_turn_points[left.index].operations[1].operation)
- << "/" << operation_char(m_turn_points[right.index].operations[0].operation)
- << operation_char(m_turn_points[right.index].operations[1].operation)
- << " " << " Take " << left.index << " < " << right.index
- << std::cout;
+#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES)
+ std::cout << " Consider: " << operation_char(m_turn_points[left.turn_index].operations[0].operation)
+ << operation_char(m_turn_points[left.turn_index].operations[1].operation)
+ << "/" << operation_char(m_turn_points[right.turn_index].operations[0].operation)
+ << operation_char(m_turn_points[right.turn_index].operations[1].operation)
+ << " " << " Take " << left.turn_index << " < " << right.turn_index
+ << std::endl;
#endif
return default_order;
@@ -523,8 +614,8 @@ inline void inspect_cluster(Iterator begin_cluster, Iterator end_cluster,
std::map<std::pair<operation_type, operation_type>, int> inspection;
for (Iterator it = begin_cluster; it != end_cluster; ++it)
{
- operation_type first = turn_points[it->index].operations[0].operation;
- operation_type second = turn_points[it->index].operations[1].operation;
+ operation_type first = turn_points[it->turn_index].operations[0].operation;
+ operation_type second = turn_points[it->turn_index].operations[1].operation;
if (first > second)
{
std::swap(first, second);
@@ -553,7 +644,7 @@ inline void inspect_cluster(Iterator begin_cluster, Iterator end_cluster,
// Because (in case of not discarding iu) correctly ordering of ii/iu appears impossible
for (Iterator it = begin_cluster; it != end_cluster; ++it)
{
- if (turn_points[it->index].combination(operation_intersection, operation_union))
+ if (turn_points[it->turn_index].combination(operation_intersection, operation_union))
{
it->discarded = true;
}
@@ -569,7 +660,7 @@ inline void inspect_cluster(Iterator begin_cluster, Iterator end_cluster,
if (! it->discarded)
{
nd_count++;
- if (turn_points[it->index].both(operation_continue))
+ if (turn_points[it->turn_index].both(operation_continue))
{
cc_count++;
}
@@ -585,7 +676,7 @@ inline void inspect_cluster(Iterator begin_cluster, Iterator end_cluster,
{
for (Iterator it = begin_cluster; it != end_cluster; ++it)
{
- if (turn_points[it->index].both(operation_continue))
+ if (turn_points[it->turn_index].both(operation_continue))
{
it->discarded = true;
}
@@ -602,12 +693,14 @@ template
typename TurnPoints,
typename Geometry1,
typename Geometry2,
+ typename RobustPolicy,
typename Strategy
>
inline void handle_cluster(Iterator begin_cluster, Iterator end_cluster,
TurnPoints& turn_points,
operation_type for_operation,
Geometry1 const& geometry1, Geometry2 const& geometry2,
+ RobustPolicy& robust_policy,
Strategy const& strategy)
{
// First inspect and (possibly) discard rows
@@ -622,31 +715,31 @@ inline void handle_cluster(Iterator begin_cluster, Iterator end_cluster,
TurnPoints,
IndexType,
Geometry1, Geometry2,
+ RobustPolicy,
Reverse1, Reverse2,
Strategy
- >(turn_points, geometry1, geometry2, strategy));
-
+ >(turn_points, geometry1, geometry2, robust_policy, strategy));
-#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
+#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES)
typedef typename IndexType::type operations_type;
- operations_type const& op = turn_points[begin_cluster->index].operations[begin_cluster->operation_index];
- std::cout << "Clustered points on equal distance " << op.enriched.distance << std::endl;
- std::cout << "->Indexes ";
+ operations_type const& op = turn_points[begin_cluster->turn_index].operations[begin_cluster->operation_index];
+ std::cout << std::endl << "Clustered points on equal distance " << op.fraction << std::endl;
+ std::cout << "->Indexes ";
for (Iterator it = begin_cluster; it != end_cluster; ++it)
{
- std::cout << " " << it->index;
+ std::cout << " " << it->turn_index;
}
std::cout << std::endl << "->Methods: ";
for (Iterator it = begin_cluster; it != end_cluster; ++it)
{
- std::cout << " " << method_char(turn_points[it->index].method);
+ std::cout << " " << method_char(turn_points[it->turn_index].method);
}
std::cout << std::endl << "->Operations: ";
for (Iterator it = begin_cluster; it != end_cluster; ++it)
{
- std::cout << " " << operation_char(turn_points[it->index].operations[0].operation)
- << operation_char(turn_points[it->index].operations[1].operation);
+ std::cout << " " << operation_char(turn_points[it->turn_index].operations[0].operation)
+ << operation_char(turn_points[it->turn_index].operations[1].operation);
}
std::cout << std::endl << "->Discarded: ";
for (Iterator it = begin_cluster; it != end_cluster; ++it)
@@ -656,7 +749,7 @@ inline void handle_cluster(Iterator begin_cluster, Iterator end_cluster,
std::cout << std::endl;
//<< "\tOn segments: " << prev_op.seg_id << " / " << prev_op.other_id
//<< " and " << op.seg_id << " / " << op.other_id
- //<< geometry::distance(turn_points[prev->index].point, turn_points[it->index].point)
+ //<< geometry::distance(turn_points[prev->turn_index].point, turn_points[it->turn_index].point)
#endif
}
diff --git a/boost/geometry/algorithms/detail/overlay/intersection_box_box.hpp b/boost/geometry/algorithms/detail/overlay/intersection_box_box.hpp
new file mode 100644
index 0000000000..dd041b0d7d
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/intersection_box_box.hpp
@@ -0,0 +1,84 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-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_OVERLAY_INTERSECTION_BOX_BOX_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_INTERSECTION_BOX_BOX_HPP
+
+
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/coordinate_type.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace intersection
+{
+
+template <std::size_t Dimension, std::size_t DimensionCount>
+struct intersection_box_box
+{
+ template
+ <
+ typename Box1, typename Box2,
+ typename RobustPolicy,
+ typename BoxOut,
+ typename Strategy
+ >
+ static inline bool apply(Box1 const& box1,
+ Box2 const& box2,
+ RobustPolicy const& robust_policy,
+ BoxOut& box_out,
+ Strategy const& strategy)
+ {
+ typedef typename coordinate_type<BoxOut>::type ct;
+
+ ct min1 = get<min_corner, Dimension>(box1);
+ ct min2 = get<min_corner, Dimension>(box2);
+ ct max1 = get<max_corner, Dimension>(box1);
+ ct max2 = get<max_corner, Dimension>(box2);
+
+ if (max1 < min2 || max2 < min1)
+ {
+ return false;
+ }
+ // Set dimensions of output coordinate
+ set<min_corner, Dimension>(box_out, min1 < min2 ? min2 : min1);
+ set<max_corner, Dimension>(box_out, max1 > max2 ? max2 : max1);
+
+ return intersection_box_box<Dimension + 1, DimensionCount>
+ ::apply(box1, box2, robust_policy, box_out, strategy);
+ }
+};
+
+template <std::size_t DimensionCount>
+struct intersection_box_box<DimensionCount, DimensionCount>
+{
+ template
+ <
+ typename Box1, typename Box2,
+ typename RobustPolicy,
+ typename BoxOut,
+ typename Strategy
+ >
+ static inline bool apply(Box1 const&, Box2 const&,
+ RobustPolicy const&, BoxOut&, Strategy const&)
+ {
+ return true;
+ }
+};
+
+
+}} // namespace detail::intersection
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_INTERSECTION_BOX_BOX_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp b/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp
index 8bca790d74..a13a627456 100644
--- a/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp
+++ b/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp
@@ -1,6 +1,11 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2014.
+// Modifications copyright (c) 2014 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -28,8 +33,17 @@
#include <boost/geometry/algorithms/detail/overlay/overlay.hpp>
#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
#include <boost/geometry/algorithms/detail/overlay/follow.hpp>
+
+#include <boost/geometry/policies/robustness/robust_point_type.hpp>
+#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
+#include <boost/geometry/policies/robustness/get_rescale_policy.hpp>
+
#include <boost/geometry/views/segment_view.hpp>
+#include <boost/geometry/algorithms/detail/overlay/linear_linear.hpp>
+#include <boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp>
+
+
#if defined(BOOST_GEOMETRY_DEBUG_FOLLOW)
#include <boost/foreach.hpp>
#endif
@@ -41,31 +55,64 @@ namespace boost { namespace geometry
namespace detail { namespace intersection
{
-template
-<
- typename Segment1, typename Segment2,
- typename OutputIterator, typename PointOut,
- typename Strategy
->
+template <typename PointOut>
struct intersection_segment_segment_point
{
+ template
+ <
+ typename Segment1, typename Segment2,
+ typename RobustPolicy,
+ typename OutputIterator, typename Strategy
+ >
static inline OutputIterator apply(Segment1 const& segment1,
- Segment2 const& segment2, OutputIterator out,
+ Segment2 const& segment2,
+ RobustPolicy const& robust_policy,
+ OutputIterator out,
Strategy const& )
{
typedef typename point_type<PointOut>::type point_type;
+ typedef typename geometry::robust_point_type
+ <
+ typename geometry::point_type<Segment1>::type,
+ RobustPolicy
+ >::type robust_point_type;
+
+ // TODO: rescale segment -> robust points
+ robust_point_type pi_rob, pj_rob, qi_rob, qj_rob;
+ {
+ // Workaround:
+ point_type pi, pj, qi, qj;
+ assign_point_from_index<0>(segment1, pi);
+ assign_point_from_index<1>(segment1, pj);
+ assign_point_from_index<0>(segment2, qi);
+ assign_point_from_index<1>(segment2, qj);
+ geometry::recalculate(pi_rob, pi, robust_policy);
+ geometry::recalculate(pj_rob, pj, robust_policy);
+ geometry::recalculate(qi_rob, qi, robust_policy);
+ geometry::recalculate(qj_rob, qj, robust_policy);
+ }
+
// Get the intersection point (or two points)
- segment_intersection_points<point_type> is
- = strategy::intersection::relate_cartesian_segments
+ typedef segment_intersection_points
+ <
+ point_type,
+ typename segment_ratio_type
+ <
+ point_type, RobustPolicy
+ >::type
+ > intersection_return_type;
+
+ typedef strategy::intersection::relate_cartesian_segments
<
policies::relate::segments_intersection_points
<
- Segment1,
- Segment2,
- segment_intersection_points<point_type>
+ intersection_return_type
>
- >::apply(segment1, segment2);
+ > policy;
+
+ intersection_return_type is = policy::apply(segment1, segment2,
+ robust_policy, pi_rob, pj_rob, qi_rob, qj_rob);
for (std::size_t i = 0; i < is.count; i++)
{
@@ -77,24 +124,31 @@ struct intersection_segment_segment_point
}
};
-template
-<
- typename Linestring1, typename Linestring2,
- typename OutputIterator, typename PointOut,
- typename Strategy
->
+template <typename PointOut>
struct intersection_linestring_linestring_point
{
+ template
+ <
+ typename Linestring1, typename Linestring2,
+ typename RobustPolicy,
+ typename OutputIterator, typename Strategy
+ >
static inline OutputIterator apply(Linestring1 const& linestring1,
- Linestring2 const& linestring2, OutputIterator out,
+ Linestring2 const& linestring2,
+ RobustPolicy const& robust_policy,
+ OutputIterator out,
Strategy const& )
{
typedef typename point_type<PointOut>::type point_type;
- typedef detail::overlay::turn_info<point_type> turn_info;
+ typedef detail::overlay::turn_info
+ <
+ point_type,
+ typename segment_ratio_type<point_type, RobustPolicy>::type
+ > turn_info;
std::deque<turn_info> turns;
- geometry::get_intersection_points(linestring1, linestring2, turns);
+ geometry::get_intersection_points(linestring1, linestring2, robust_policy, turns);
for (typename boost::range_iterator<std::deque<turn_info> const>::type
it = boost::begin(turns); it != boost::end(turns); ++it)
@@ -112,25 +166,15 @@ struct intersection_linestring_linestring_point
*/
template
<
- typename LineString, typename Areal,
bool ReverseAreal,
- typename OutputIterator, typename LineStringOut,
- overlay_type OverlayType,
- typename Strategy
+ typename LineStringOut,
+ overlay_type OverlayType
>
struct intersection_of_linestring_with_areal
{
- typedef detail::overlay::follow
- <
- LineStringOut,
- LineString,
- Areal,
- OverlayType
- > follower;
-
#if defined(BOOST_GEOMETRY_DEBUG_FOLLOW)
template <typename Turn, typename Operation>
- static inline void debug_follow(Turn const& turn, Operation op,
+ static inline void debug_follow(Turn const& turn, Operation op,
int index)
{
std::cout << index
@@ -145,7 +189,14 @@ struct intersection_of_linestring_with_areal
}
#endif
+ template
+ <
+ typename LineString, typename Areal,
+ typename RobustPolicy,
+ typename OutputIterator, typename Strategy
+ >
static inline OutputIterator apply(LineString const& linestring, Areal const& areal,
+ RobustPolicy const& robust_policy,
OutputIterator out,
Strategy const& )
{
@@ -154,9 +205,20 @@ struct intersection_of_linestring_with_areal
return out;
}
- typedef typename point_type<LineStringOut>::type point_type;
+ typedef detail::overlay::follow
+ <
+ LineStringOut,
+ LineString,
+ Areal,
+ OverlayType
+ > follower;
- typedef detail::overlay::traversal_turn_info<point_type> turn_info;
+ typedef typename point_type<LineStringOut>::type point_type;
+ typedef detail::overlay::traversal_turn_info
+ <
+ point_type,
+ typename geometry::segment_ratio_type<point_type, RobustPolicy>::type
+ > turn_info;
std::deque<turn_info> turns;
detail::get_turns::no_interrupt_policy policy;
@@ -164,12 +226,12 @@ struct intersection_of_linestring_with_areal
<
false,
(OverlayType == overlay_intersection ? ReverseAreal : !ReverseAreal),
- detail::overlay::calculate_distance_policy
- >(linestring, areal, turns, policy);
+ detail::overlay::assign_null_policy
+ >(linestring, areal, robust_policy, turns, policy);
if (turns.empty())
{
- // No intersection points, it is either completely
+ // No intersection points, it is either completely
// inside (interior + borders)
// or completely outside
@@ -181,8 +243,7 @@ struct intersection_of_linestring_with_areal
return out;
}
-
- if (follower::included(border_point, areal))
+ if (follower::included(border_point, areal, robust_policy))
{
LineStringOut copy;
geometry::convert(linestring, copy);
@@ -203,7 +264,7 @@ struct intersection_of_linestring_with_areal
(
linestring, areal,
geometry::detail::overlay::operation_intersection,
- turns, out
+ turns, robust_policy, out
);
}
};
@@ -220,18 +281,22 @@ namespace dispatch
template
<
- // tag dispatching:
- typename TagIn1, typename TagIn2, typename TagOut,
- // orientation
- // metafunction finetuning helpers:
- bool Areal1, bool Areal2, bool ArealOut,
// real types
typename Geometry1, typename Geometry2,
- bool Reverse1, bool Reverse2, bool ReverseOut,
- typename OutputIterator,
typename GeometryOut,
overlay_type OverlayType,
- typename Strategy
+ // orientation
+ bool Reverse1 = detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
+ bool Reverse2 = detail::overlay::do_reverse<geometry::point_order<Geometry2>::value>::value,
+ bool ReverseOut = detail::overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value,
+ // tag dispatching:
+ typename TagIn1 = typename geometry::tag<Geometry1>::type,
+ typename TagIn2 = typename geometry::tag<Geometry2>::type,
+ typename TagOut = typename geometry::tag<GeometryOut>::type,
+ // metafunction finetuning helpers:
+ bool Areal1 = geometry::is_areal<Geometry1>::value,
+ bool Areal2 = geometry::is_areal<Geometry2>::value,
+ bool ArealOut = geometry::is_areal<GeometryOut>::value
>
struct intersection_insert
{
@@ -245,124 +310,106 @@ struct intersection_insert
template
<
- typename TagIn1, typename TagIn2, typename TagOut,
typename Geometry1, typename Geometry2,
- bool Reverse1, bool Reverse2, bool ReverseOut,
- typename OutputIterator,
typename GeometryOut,
overlay_type OverlayType,
- typename Strategy
+ bool Reverse1, bool Reverse2, bool ReverseOut,
+ typename TagIn1, typename TagIn2, typename TagOut
>
struct intersection_insert
<
- TagIn1, TagIn2, TagOut,
- true, true, true,
Geometry1, Geometry2,
- Reverse1, Reverse2, ReverseOut,
- OutputIterator, GeometryOut,
+ GeometryOut,
OverlayType,
- Strategy
+ Reverse1, Reverse2, ReverseOut,
+ TagIn1, TagIn2, TagOut,
+ true, true, true
> : detail::overlay::overlay
- <Geometry1, Geometry2, Reverse1, Reverse2, ReverseOut, OutputIterator, GeometryOut, OverlayType, Strategy>
+ <Geometry1, Geometry2, Reverse1, Reverse2, ReverseOut, GeometryOut, OverlayType>
{};
// Any areal type with box:
template
<
- typename TagIn, typename TagOut,
typename Geometry, typename Box,
- bool Reverse1, bool Reverse2, bool ReverseOut,
- typename OutputIterator,
typename GeometryOut,
overlay_type OverlayType,
- typename Strategy
+ bool Reverse1, bool Reverse2, bool ReverseOut,
+ typename TagIn, typename TagOut
>
struct intersection_insert
<
- TagIn, box_tag, TagOut,
- true, true, true,
Geometry, Box,
- Reverse1, Reverse2, ReverseOut,
- OutputIterator, GeometryOut,
+ GeometryOut,
OverlayType,
- Strategy
+ Reverse1, Reverse2, ReverseOut,
+ TagIn, box_tag, TagOut,
+ true, true, true
> : detail::overlay::overlay
- <Geometry, Box, Reverse1, Reverse2, ReverseOut, OutputIterator, GeometryOut, OverlayType, Strategy>
+ <Geometry, Box, Reverse1, Reverse2, ReverseOut, GeometryOut, OverlayType>
{};
template
<
typename Segment1, typename Segment2,
- bool Reverse1, bool Reverse2, bool ReverseOut,
- typename OutputIterator, typename GeometryOut,
+ typename GeometryOut,
overlay_type OverlayType,
- typename Strategy
+ bool Reverse1, bool Reverse2, bool ReverseOut
>
struct intersection_insert
<
- segment_tag, segment_tag, point_tag,
- false, false, false,
Segment1, Segment2,
+ GeometryOut,
+ OverlayType,
Reverse1, Reverse2, ReverseOut,
- OutputIterator, GeometryOut,
- OverlayType, Strategy
- > : detail::intersection::intersection_segment_segment_point
- <
- Segment1, Segment2,
- OutputIterator, GeometryOut,
- Strategy
- >
+ segment_tag, segment_tag, point_tag,
+ false, false, false
+ > : detail::intersection::intersection_segment_segment_point<GeometryOut>
{};
template
<
typename Linestring1, typename Linestring2,
- bool Reverse1, bool Reverse2, bool ReverseOut,
- typename OutputIterator, typename GeometryOut,
+ typename GeometryOut,
overlay_type OverlayType,
- typename Strategy
+ bool Reverse1, bool Reverse2, bool ReverseOut
>
struct intersection_insert
<
- linestring_tag, linestring_tag, point_tag,
- false, false, false,
Linestring1, Linestring2,
+ GeometryOut,
+ OverlayType,
Reverse1, Reverse2, ReverseOut,
- OutputIterator, GeometryOut,
- OverlayType, Strategy
- > : detail::intersection::intersection_linestring_linestring_point
- <
- Linestring1, Linestring2,
- OutputIterator, GeometryOut,
- Strategy
- >
+ linestring_tag, linestring_tag, point_tag,
+ false, false, false
+ > : detail::intersection::intersection_linestring_linestring_point<GeometryOut>
{};
template
<
typename Linestring, typename Box,
- bool Reverse1, bool Reverse2, bool ReverseOut,
- typename OutputIterator, typename GeometryOut,
- overlay_type OverlayType,
- typename Strategy
+ typename GeometryOut,
+ bool Reverse1, bool Reverse2, bool ReverseOut
>
struct intersection_insert
<
- linestring_tag, box_tag, linestring_tag,
- false, true, false,
Linestring, Box,
+ GeometryOut,
+ overlay_intersection,
Reverse1, Reverse2, ReverseOut,
- OutputIterator, GeometryOut,
- OverlayType,
- Strategy
+ linestring_tag, box_tag, linestring_tag,
+ false, true, false
>
{
+ template <typename RobustPolicy, typename OutputIterator, typename Strategy>
static inline OutputIterator apply(Linestring const& linestring,
- Box const& box, OutputIterator out, Strategy const& )
+ Box const& box,
+ RobustPolicy const& ,
+ OutputIterator out, Strategy const& )
{
typedef typename point_type<GeometryOut>::type point_type;
strategy::intersection::liang_barsky<Box, point_type> lb_strategy;
@@ -375,27 +422,23 @@ struct intersection_insert
template
<
typename Linestring, typename Polygon,
- bool ReverseLinestring, bool ReversePolygon, bool ReverseOut,
- typename OutputIterator, typename GeometryOut,
+ typename GeometryOut,
overlay_type OverlayType,
- typename Strategy
+ bool ReverseLinestring, bool ReversePolygon, bool ReverseOut
>
struct intersection_insert
<
- linestring_tag, polygon_tag, linestring_tag,
- false, true, false,
Linestring, Polygon,
- ReverseLinestring, ReversePolygon, ReverseOut,
- OutputIterator, GeometryOut,
+ GeometryOut,
OverlayType,
- Strategy
+ ReverseLinestring, ReversePolygon, ReverseOut,
+ linestring_tag, polygon_tag, linestring_tag,
+ false, true, false
> : detail::intersection::intersection_of_linestring_with_areal
<
- Linestring, Polygon,
ReversePolygon,
- OutputIterator, GeometryOut,
- OverlayType,
- Strategy
+ GeometryOut,
+ OverlayType
>
{};
@@ -403,51 +446,48 @@ struct intersection_insert
template
<
typename Linestring, typename Ring,
- bool ReverseLinestring, bool ReverseRing, bool ReverseOut,
- typename OutputIterator, typename GeometryOut,
+ typename GeometryOut,
overlay_type OverlayType,
- typename Strategy
+ bool ReverseLinestring, bool ReverseRing, bool ReverseOut
>
struct intersection_insert
<
- linestring_tag, ring_tag, linestring_tag,
- false, true, false,
Linestring, Ring,
- ReverseLinestring, ReverseRing, ReverseOut,
- OutputIterator, GeometryOut,
+ GeometryOut,
OverlayType,
- Strategy
+ ReverseLinestring, ReverseRing, ReverseOut,
+ linestring_tag, ring_tag, linestring_tag,
+ false, true, false
> : detail::intersection::intersection_of_linestring_with_areal
<
- Linestring, Ring,
ReverseRing,
- OutputIterator, GeometryOut,
- OverlayType,
- Strategy
+ GeometryOut,
+ OverlayType
>
{};
template
<
typename Segment, typename Box,
- bool Reverse1, bool Reverse2, bool ReverseOut,
- typename OutputIterator, typename GeometryOut,
+ typename GeometryOut,
overlay_type OverlayType,
- typename Strategy
+ bool Reverse1, bool Reverse2, bool ReverseOut
>
struct intersection_insert
<
- segment_tag, box_tag, linestring_tag,
- false, true, false,
Segment, Box,
- Reverse1, Reverse2, ReverseOut,
- OutputIterator, GeometryOut,
+ GeometryOut,
OverlayType,
- Strategy
+ Reverse1, Reverse2, ReverseOut,
+ segment_tag, box_tag, linestring_tag,
+ false, true, false
>
{
+ template <typename RobustPolicy, typename OutputIterator, typename Strategy>
static inline OutputIterator apply(Segment const& segment,
- Box const& box, OutputIterator out, Strategy const& )
+ Box const& box,
+ RobustPolicy const& ,// TODO: propagate to clip_range_with_box
+ OutputIterator out, Strategy const& )
{
geometry::segment_view<Segment> range(segment);
@@ -460,37 +500,42 @@ struct intersection_insert
template
<
- typename Tag1, typename Tag2,
- bool Areal1, bool Areal2,
typename Geometry1, typename Geometry2,
- bool Reverse1, bool Reverse2, bool ReverseOut,
- typename OutputIterator, typename PointOut,
+ typename PointOut,
overlay_type OverlayType,
- typename Strategy
+ bool Reverse1, bool Reverse2, bool ReverseOut,
+ typename Tag1, typename Tag2,
+ bool Areal1, bool Areal2
>
struct intersection_insert
<
- Tag1, Tag2, point_tag,
- Areal1, Areal2, false,
Geometry1, Geometry2,
- Reverse1, Reverse2, ReverseOut,
- OutputIterator, PointOut,
+ PointOut,
OverlayType,
- Strategy
+ Reverse1, Reverse2, ReverseOut,
+ Tag1, Tag2, point_tag,
+ Areal1, Areal2, false
>
{
+ template <typename RobustPolicy, typename OutputIterator, typename Strategy>
static inline OutputIterator apply(Geometry1 const& geometry1,
- Geometry2 const& geometry2, OutputIterator out, Strategy const& )
+ Geometry2 const& geometry2,
+ RobustPolicy const& robust_policy,
+ OutputIterator out, Strategy const& )
{
- typedef detail::overlay::turn_info<PointOut> turn_info;
+ typedef detail::overlay::turn_info
+ <
+ PointOut,
+ typename segment_ratio_type<PointOut, RobustPolicy>::type
+ > turn_info;
std::vector<turn_info> turns;
detail::get_turns::no_interrupt_policy policy;
geometry::get_turns
<
false, false, detail::overlay::assign_null_policy
- >(geometry1, geometry2, turns, policy);
+ >(geometry1, geometry2, robust_policy, turns, policy);
for (typename std::vector<turn_info>::const_iterator it
= turns.begin(); it != turns.end(); ++it)
{
@@ -504,35 +549,156 @@ struct intersection_insert
template
<
- typename GeometryTag1, typename GeometryTag2, typename GeometryTag3,
- bool Areal1, bool Areal2, bool ArealOut,
- typename Geometry1, typename Geometry2,
- bool Reverse1, bool Reverse2, bool ReverseOut,
- typename OutputIterator, typename GeometryOut,
+ typename Geometry1, typename Geometry2, typename GeometryOut,
overlay_type OverlayType,
- typename Strategy
+ bool Reverse1, bool Reverse2, bool ReverseOut
>
struct intersection_insert_reversed
{
+ template <typename RobustPolicy, typename OutputIterator, typename Strategy>
static inline OutputIterator apply(Geometry1 const& g1,
- Geometry2 const& g2, OutputIterator out,
+ Geometry2 const& g2,
+ RobustPolicy const& robust_policy,
+ OutputIterator out,
Strategy const& strategy)
{
return intersection_insert
<
- GeometryTag2, GeometryTag1, GeometryTag3,
- Areal2, Areal1, ArealOut,
- Geometry2, Geometry1,
- Reverse2, Reverse1, ReverseOut,
- OutputIterator, GeometryOut,
+ Geometry2, Geometry1, GeometryOut,
OverlayType,
- Strategy
- >::apply(g2, g1, out, strategy);
+ Reverse2, Reverse1, ReverseOut
+ >::apply(g2, g1, robust_policy, out, strategy);
}
};
+// dispatch for non-areal geometries
+template
+<
+ typename Geometry1, typename Geometry2, typename GeometryOut,
+ overlay_type OverlayType,
+ bool Reverse1, bool Reverse2, bool ReverseOut,
+ typename TagIn1, typename TagIn2
+>
+struct intersection_insert
+ <
+ Geometry1, Geometry2, GeometryOut,
+ OverlayType,
+ Reverse1, Reverse2, ReverseOut,
+ TagIn1, TagIn2, linestring_tag,
+ false, false, false
+ > : intersection_insert
+ <
+ Geometry1, Geometry2, GeometryOut,
+ OverlayType,
+ Reverse1, Reverse2, ReverseOut,
+ typename tag_cast<TagIn1, pointlike_tag, linear_tag>::type,
+ typename tag_cast<TagIn2, pointlike_tag, linear_tag>::type,
+ linestring_tag,
+ false, false, false
+ >
+{};
+
+
+// dispatch for difference/intersection of linear geometries
+template
+<
+ typename Linear1, typename Linear2, typename LineStringOut,
+ overlay_type OverlayType,
+ bool Reverse1, bool Reverse2, bool ReverseOut
+>
+struct intersection_insert
+ <
+ Linear1, Linear2, LineStringOut, OverlayType,
+ Reverse1, Reverse2, ReverseOut,
+ linear_tag, linear_tag, linestring_tag,
+ false, false, false
+ > : detail::overlay::linear_linear_linestring
+ <
+ Linear1, Linear2, LineStringOut, OverlayType
+ >
+{};
+
+
+// dispatch for difference/intersection of point-like geometries
+
+template
+<
+ typename Point1, typename Point2, typename PointOut,
+ overlay_type OverlayType,
+ bool Reverse1, bool Reverse2, bool ReverseOut
+>
+struct intersection_insert
+ <
+ Point1, Point2, PointOut, OverlayType,
+ Reverse1, Reverse2, ReverseOut,
+ point_tag, point_tag, point_tag,
+ false, false, false
+ > : detail::overlay::point_point_point
+ <
+ Point1, Point2, PointOut, OverlayType
+ >
+{};
+
+
+template
+<
+ typename MultiPoint, typename Point, typename PointOut,
+ overlay_type OverlayType,
+ bool Reverse1, bool Reverse2, bool ReverseOut
+>
+struct intersection_insert
+ <
+ MultiPoint, Point, PointOut, OverlayType,
+ Reverse1, Reverse2, ReverseOut,
+ multi_point_tag, point_tag, point_tag,
+ false, false, false
+ > : detail::overlay::multipoint_point_point
+ <
+ MultiPoint, Point, PointOut, OverlayType
+ >
+{};
+
+
+template
+<
+ typename Point, typename MultiPoint, typename PointOut,
+ overlay_type OverlayType,
+ bool Reverse1, bool Reverse2, bool ReverseOut
+>
+struct intersection_insert
+ <
+ Point, MultiPoint, PointOut, OverlayType,
+ Reverse1, Reverse2, ReverseOut,
+ point_tag, multi_point_tag, point_tag,
+ false, false, false
+ > : detail::overlay::point_multipoint_point
+ <
+ Point, MultiPoint, PointOut, OverlayType
+ >
+{};
+
+
+template
+<
+ typename MultiPoint1, typename MultiPoint2, typename PointOut,
+ overlay_type OverlayType,
+ bool Reverse1, bool Reverse2, bool ReverseOut
+>
+struct intersection_insert
+ <
+ MultiPoint1, MultiPoint2, PointOut, OverlayType,
+ Reverse1, Reverse2, ReverseOut,
+ multi_point_tag, multi_point_tag, point_tag,
+ false, false, false
+ > : detail::overlay::multipoint_multipoint_point
+ <
+ MultiPoint1, MultiPoint2, PointOut, OverlayType
+ >
+{};
+
+
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
@@ -548,50 +714,37 @@ template
bool ReverseSecond,
overlay_type OverlayType,
typename Geometry1, typename Geometry2,
+ typename RobustPolicy,
typename OutputIterator,
typename Strategy
>
inline OutputIterator insert(Geometry1 const& geometry1,
Geometry2 const& geometry2,
+ RobustPolicy robust_policy,
OutputIterator out,
Strategy const& strategy)
{
return boost::mpl::if_c
+ <
+ geometry::reverse_dispatch<Geometry1, Geometry2>::type::value,
+ geometry::dispatch::intersection_insert_reversed
<
- geometry::reverse_dispatch<Geometry1, Geometry2>::type::value,
- geometry::dispatch::intersection_insert_reversed
- <
- typename geometry::tag<Geometry1>::type,
- typename geometry::tag<Geometry2>::type,
- typename geometry::tag<GeometryOut>::type,
- geometry::is_areal<Geometry1>::value,
- geometry::is_areal<Geometry2>::value,
- geometry::is_areal<GeometryOut>::value,
- Geometry1, Geometry2,
- overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
- overlay::do_reverse<geometry::point_order<Geometry2>::value, ReverseSecond>::value,
- overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value,
- OutputIterator, GeometryOut,
- OverlayType,
- Strategy
- >,
- geometry::dispatch::intersection_insert
- <
- typename geometry::tag<Geometry1>::type,
- typename geometry::tag<Geometry2>::type,
- typename geometry::tag<GeometryOut>::type,
- geometry::is_areal<Geometry1>::value,
- geometry::is_areal<Geometry2>::value,
- geometry::is_areal<GeometryOut>::value,
- Geometry1, Geometry2,
- geometry::detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
- geometry::detail::overlay::do_reverse<geometry::point_order<Geometry2>::value, ReverseSecond>::value,
- geometry::detail::overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value,
- OutputIterator, GeometryOut,
- OverlayType,
- Strategy
- >
- >::type::apply(geometry1, geometry2, out, strategy);
+ Geometry1, Geometry2,
+ GeometryOut,
+ OverlayType,
+ overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
+ overlay::do_reverse<geometry::point_order<Geometry2>::value, ReverseSecond>::value,
+ overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value
+ >,
+ geometry::dispatch::intersection_insert
+ <
+ Geometry1, Geometry2,
+ GeometryOut,
+ OverlayType,
+ geometry::detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
+ geometry::detail::overlay::do_reverse<geometry::point_order<Geometry2>::value, ReverseSecond>::value
+ >
+ >::type::apply(geometry1, geometry2, robust_policy, out, strategy);
}
@@ -630,10 +783,14 @@ inline OutputIterator intersection_insert(Geometry1 const& geometry1,
concept::check<Geometry1 const>();
concept::check<Geometry2 const>();
+ typedef typename Strategy::rescale_policy_type rescale_policy_type;
+ rescale_policy_type robust_policy
+ = geometry::get_rescale_policy<rescale_policy_type>(geometry1, geometry2);
+
return detail::intersection::insert
<
GeometryOut, false, overlay_intersection
- >(geometry1, geometry2, out, strategy);
+ >(geometry1, geometry2, robust_policy, out, strategy);
}
@@ -667,12 +824,18 @@ inline OutputIterator intersection_insert(Geometry1 const& geometry1,
concept::check<Geometry1 const>();
concept::check<Geometry2 const>();
+ typedef typename geometry::rescale_policy_type
+ <
+ typename geometry::point_type<Geometry1>::type // TODO from both
+ >::type rescale_policy_type;
+
typedef strategy_intersection
<
typename cs_tag<GeometryOut>::type,
Geometry1,
Geometry2,
- typename geometry::point_type<GeometryOut>::type
+ typename geometry::point_type<GeometryOut>::type,
+ rescale_policy_type
> strategy;
return intersection_insert<GeometryOut>(geometry1, geometry2, out,
diff --git a/boost/geometry/algorithms/detail/overlay/linear_linear.hpp b/boost/geometry/algorithms/detail/overlay/linear_linear.hpp
new file mode 100644
index 0000000000..3a7a7a7f3e
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/linear_linear.hpp
@@ -0,0 +1,326 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_LINEAR_LINEAR_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_LINEAR_LINEAR_HPP
+
+#include <algorithm>
+#include <vector>
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/algorithms/detail/relate/turns.hpp>
+
+#include <boost/geometry/algorithms/detail/turns/compare_turns.hpp>
+#include <boost/geometry/algorithms/detail/turns/filter_continue_turns.hpp>
+#include <boost/geometry/algorithms/detail/turns/remove_duplicate_turns.hpp>
+
+#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
+#include <boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp>
+
+#include <boost/geometry/algorithms/convert.hpp>
+
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+
+template
+<
+ typename LineStringOut,
+ overlay_type OverlayType,
+ typename Geometry,
+ typename GeometryTag
+>
+struct linear_linear_no_intersections;
+
+
+template <typename LineStringOut, typename LineString>
+struct linear_linear_no_intersections
+ <
+ LineStringOut, overlay_difference, LineString, linestring_tag
+ >
+{
+ template <typename OutputIterator>
+ static inline OutputIterator apply(LineString const& linestring,
+ OutputIterator oit)
+ {
+ LineStringOut ls_out;
+ geometry::convert(linestring, ls_out);
+ *oit++ = ls_out;
+ return oit;
+ }
+};
+
+
+template <typename LineStringOut, typename MultiLineString>
+struct linear_linear_no_intersections
+ <
+ LineStringOut,
+ overlay_difference,
+ MultiLineString,
+ multi_linestring_tag
+ >
+{
+ template <typename OutputIterator>
+ static inline OutputIterator apply(MultiLineString const& multilinestring,
+ OutputIterator oit)
+ {
+ for (typename boost::range_iterator<MultiLineString const>::type
+ it = boost::begin(multilinestring);
+ it != boost::end(multilinestring); ++it)
+ {
+ LineStringOut ls_out;
+ geometry::convert(*it, ls_out);
+ *oit++ = ls_out;
+ }
+ return oit;
+ }
+};
+
+
+template <typename LineStringOut, typename Geometry, typename GeometryTag>
+struct linear_linear_no_intersections
+ <
+ LineStringOut, overlay_intersection, Geometry, GeometryTag
+ >
+{
+ template <typename OutputIterator>
+ static inline OutputIterator apply(Geometry const&,
+ OutputIterator oit)
+ {
+ return oit;
+ }
+};
+
+
+
+
+
+
+
+template
+<
+ typename Linear1,
+ typename Linear2,
+ typename LinestringOut,
+ overlay_type OverlayType,
+ bool EnableFilterContinueTurns = false,
+ bool EnableRemoveDuplicateTurns = false,
+ bool EnableDegenerateTurns = true,
+#ifdef BOOST_GEOMETRY_INTERSECTION_DO_NOT_INCLUDE_ISOLATED_POINTS
+ bool EnableFollowIsolatedPoints = false
+#else
+ bool EnableFollowIsolatedPoints = true
+#endif
+>
+class linear_linear_linestring
+{
+protected:
+ struct assign_policy
+ {
+ static bool const include_no_turn = false;
+ static bool const include_degenerate = EnableDegenerateTurns;
+ static bool const include_opposite = false;
+
+ template
+ <
+ typename Info,
+ typename Point1,
+ typename Point2,
+ typename IntersectionInfo,
+ typename DirInfo
+ >
+ static inline void apply(Info& , Point1 const& , Point2 const& ,
+ IntersectionInfo const& , DirInfo const& )
+ {
+ }
+ };
+
+
+ template
+ <
+ typename Turns,
+ typename LinearGeometry1,
+ typename LinearGeometry2
+ >
+ static inline void compute_turns(Turns& turns,
+ LinearGeometry1 const& linear1,
+ LinearGeometry2 const& linear2)
+ {
+ turns.clear();
+ geometry::detail::relate::turns::get_turns
+ <
+ LinearGeometry1,
+ LinearGeometry2,
+ detail::get_turns::get_turn_info_type
+ <
+ LinearGeometry1,
+ LinearGeometry2,
+ assign_policy
+ >
+ >::apply(turns, linear1, linear2);
+ }
+
+
+ template
+ <
+ overlay_type OverlayTypeForFollow,
+ bool FollowIsolatedPoints,
+ typename Turns,
+ typename LinearGeometry1,
+ typename LinearGeometry2,
+ typename OutputIterator
+ >
+ static inline OutputIterator
+ sort_and_follow_turns(Turns& turns,
+ LinearGeometry1 const& linear1,
+ LinearGeometry2 const& linear2,
+ OutputIterator oit)
+ {
+ // remove turns that have no added value
+ turns::filter_continue_turns
+ <
+ Turns,
+ EnableFilterContinueTurns && OverlayType != overlay_intersection
+ >::apply(turns);
+
+ // sort by seg_id, distance, and operation
+ std::sort(boost::begin(turns), boost::end(turns),
+ detail::turns::less_seg_fraction_other_op<>());
+
+ // remove duplicate turns
+ turns::remove_duplicate_turns
+ <
+ Turns, EnableRemoveDuplicateTurns
+ >::apply(turns);
+
+ return detail::overlay::following::linear::follow
+ <
+ LinestringOut,
+ LinearGeometry1,
+ LinearGeometry2,
+ OverlayTypeForFollow,
+ FollowIsolatedPoints,
+ !EnableFilterContinueTurns || OverlayType == overlay_intersection
+ >::apply(linear1, linear2, boost::begin(turns), boost::end(turns),
+ oit);
+ }
+
+public:
+ template
+ <
+ typename RobustPolicy, typename OutputIterator, typename Strategy
+ >
+ static inline OutputIterator apply(Linear1 const& linear1,
+ Linear2 const& linear2,
+ RobustPolicy const&,
+ OutputIterator oit,
+ Strategy const& )
+ {
+ typedef typename detail::relate::turns::get_turns
+ <
+ Linear1, Linear2
+ >::turn_info turn_info;
+
+ typedef std::vector<turn_info> turns_container;
+
+ turns_container turns;
+ compute_turns(turns, linear1, linear2);
+
+ if ( turns.empty() )
+ {
+ // the two linear geometries are disjoint
+ return linear_linear_no_intersections
+ <
+ LinestringOut,
+ OverlayType,
+ Linear1,
+ typename tag<Linear1>::type
+ >::apply(linear1, oit);
+ }
+
+ return sort_and_follow_turns
+ <
+ OverlayType,
+ EnableFollowIsolatedPoints
+ && OverlayType == overlay_intersection
+ >(turns, linear1, linear2, oit);
+ }
+};
+
+
+
+
+template
+<
+ typename Linear1,
+ typename Linear2,
+ typename LinestringOut,
+ bool EnableFilterContinueTurns,
+ bool EnableRemoveDuplicateTurns,
+ bool EnableDegenerateTurns,
+ bool EnableFollowIsolatedPoints
+>
+struct linear_linear_linestring
+ <
+ Linear1, Linear2, LinestringOut, overlay_union,
+ EnableFilterContinueTurns, EnableRemoveDuplicateTurns,
+ EnableDegenerateTurns, EnableFollowIsolatedPoints
+ >
+{
+ template
+ <
+ typename RobustPolicy, typename OutputIterator, typename Strategy
+ >
+ static inline OutputIterator apply(Linear1 const& linear1,
+ Linear2 const& linear2,
+ RobustPolicy const& robust_policy,
+ OutputIterator oit,
+ Strategy const& strategy)
+ {
+ oit = linear_linear_no_intersections
+ <
+ LinestringOut,
+ overlay_difference,
+ Linear1,
+ typename tag<Linear1>::type
+ >::apply(linear1, oit);
+
+ return linear_linear_linestring
+ <
+ Linear2, Linear1, LinestringOut, overlay_difference,
+ EnableFilterContinueTurns, EnableRemoveDuplicateTurns,
+ EnableDegenerateTurns, EnableFollowIsolatedPoints
+ >::apply(linear2, linear1, robust_policy, oit, strategy);
+ }
+};
+
+
+
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_LINEAR_LINEAR_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/overlay.hpp b/boost/geometry/algorithms/detail/overlay/overlay.hpp
index 41665e0af1..44b5a0df3c 100644
--- a/boost/geometry/algorithms/detail/overlay/overlay.hpp
+++ b/boost/geometry/algorithms/detail/overlay/overlay.hpp
@@ -1,6 +1,7 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -17,7 +18,6 @@
#include <boost/mpl/assert.hpp>
-#include <boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp>
#include <boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp>
#include <boost/geometry/algorithms/detail/overlay/enrichment_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
@@ -26,6 +26,7 @@
#include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+#include <boost/geometry/algorithms/detail/recalculate.hpp>
#include <boost/geometry/algorithms/num_points.hpp>
#include <boost/geometry/algorithms/reverse.hpp>
@@ -34,12 +35,19 @@
#include <boost/geometry/algorithms/detail/overlay/assign_parents.hpp>
#include <boost/geometry/algorithms/detail/overlay/ring_properties.hpp>
#include <boost/geometry/algorithms/detail/overlay/select_rings.hpp>
+#include <boost/geometry/algorithms/detail/overlay/do_reverse.hpp>
+
+#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
#ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE
# include <boost/geometry/io/dsv/write.hpp>
#endif
+#ifdef BOOST_GEOMETRY_TIME_OVERLAY
+# include <boost/timer.hpp>
+#endif
+
namespace boost { namespace geometry
{
@@ -66,19 +74,17 @@ inline void map_turns(Map& map, TurnPoints const& turn_points)
typedef typename boost::range_value<TurnPoints>::type turn_point_type;
typedef typename turn_point_type::container_type container_type;
- int index = 0;
for (typename boost::range_iterator<TurnPoints const>::type
it = boost::begin(turn_points);
it != boost::end(turn_points);
- ++it, ++index)
+ ++it)
{
if (! skip(*it))
{
- int op_index = 0;
for (typename boost::range_iterator<container_type const>::type
op_it = boost::begin(it->operations);
op_it != boost::end(it->operations);
- ++op_it, ++op_index)
+ ++op_it)
{
ring_identifier ring_id
(
@@ -110,6 +116,12 @@ inline OutputIterator return_if_one_input_is_empty(Geometry1 const& geometry1,
typedef ring_properties<typename geometry::point_type<Geometry1>::type> properties;
+// Silence warning C4127: conditional expression is constant
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4127)
+#endif
+
// Union: return either of them
// Intersection: return nothing
// Difference: return first of them
@@ -120,6 +132,11 @@ inline OutputIterator return_if_one_input_is_empty(Geometry1 const& geometry1,
return out;
}
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
+
std::map<ring_identifier, int> empty;
std::map<ring_identifier, properties> all_of_one_of_them;
@@ -134,25 +151,26 @@ template
<
typename Geometry1, typename Geometry2,
bool Reverse1, bool Reverse2, bool ReverseOut,
- typename OutputIterator, typename GeometryOut,
- overlay_type Direction,
- typename Strategy
+ typename GeometryOut,
+ overlay_type Direction
>
struct overlay
{
+ template <typename RobustPolicy, typename OutputIterator, typename Strategy>
static inline OutputIterator apply(
Geometry1 const& geometry1, Geometry2 const& geometry2,
+ RobustPolicy const& robust_policy,
OutputIterator out,
Strategy const& )
{
- if (geometry::num_points(geometry1) == 0
- && geometry::num_points(geometry2) == 0)
+ if ( geometry::num_points(geometry1) == 0
+ && geometry::num_points(geometry2) == 0 )
{
return out;
}
- if (geometry::num_points(geometry1) == 0
- || geometry::num_points(geometry2) == 0)
+ if ( geometry::num_points(geometry1) == 0
+ || geometry::num_points(geometry2) == 0 )
{
return return_if_one_input_is_empty
<
@@ -161,7 +179,11 @@ struct overlay
}
typedef typename geometry::point_type<GeometryOut>::type point_type;
- typedef detail::overlay::traversal_turn_info<point_type> turn_info;
+ typedef detail::overlay::traversal_turn_info
+ <
+ point_type,
+ typename geometry::segment_ratio_type<point_type, RobustPolicy>::type
+ > turn_info;
typedef std::deque<turn_info> container_type;
typedef std::deque
@@ -182,8 +204,8 @@ std::cout << "get turns" << std::endl;
geometry::get_turns
<
Reverse1, Reverse2,
- detail::overlay::calculate_distance_policy
- >(geometry1, geometry2, turn_points, policy);
+ detail::overlay::assign_null_policy
+ >(geometry1, geometry2, robust_policy, turn_points, policy);
#ifdef BOOST_GEOMETRY_TIME_OVERLAY
std::cout << "get_turns: " << timer.elapsed() << std::endl;
@@ -198,6 +220,7 @@ std::cout << "enrich" << std::endl;
? geometry::detail::overlay::operation_union
: geometry::detail::overlay::operation_intersection,
geometry1, geometry2,
+ robust_policy,
side_strategy);
#ifdef BOOST_GEOMETRY_TIME_OVERLAY
@@ -218,6 +241,7 @@ std::cout << "traverse" << std::endl;
Direction == overlay_union
? geometry::detail::overlay::operation_union
: geometry::detail::overlay::operation_intersection,
+ robust_policy,
turn_points, rings
);
@@ -248,8 +272,8 @@ std::cout << "traverse" << std::endl;
ring_identifier id(2, 0, -1);
for (typename boost::range_iterator<ring_container_type>::type
it = boost::begin(rings);
- it != boost::end(rings);
- ++it)
+ it != boost::end(rings);
+ ++it)
{
selected[id] = properties(*it, true);
selected[id].reversed = ReverseOut;
@@ -273,24 +297,6 @@ std::cout << "traverse" << std::endl;
};
-// Metafunction helper for intersection and union
-template <order_selector Selector, bool Reverse = false>
-struct do_reverse {};
-
-template <>
-struct do_reverse<clockwise, false> : boost::false_type {};
-
-template <>
-struct do_reverse<clockwise, true> : boost::true_type {};
-
-template <>
-struct do_reverse<counterclockwise, false> : boost::true_type {};
-
-template <>
-struct do_reverse<counterclockwise, true> : boost::false_type {};
-
-
-
}} // namespace detail::overlay
#endif // DOXYGEN_NO_DETAIL
diff --git a/boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp b/boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp
new file mode 100644
index 0000000000..0af062d271
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp
@@ -0,0 +1,435 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_POINTLIKE_POINTLIKE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_POINTLIKE_POINTLIKE_HPP
+
+#include <algorithm>
+#include <vector>
+
+#include <boost/assert.hpp>
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/algorithms/convert.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
+
+#include <boost/geometry/algorithms/detail/relate/less.hpp>
+#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
+#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+
+// struct for copying points of the pointlike geometries to output
+template
+<
+ typename PointOut,
+ typename GeometryIn,
+ typename TagIn = typename tag<GeometryIn>::type
+>
+struct copy_points
+ : not_implemented<PointOut, GeometryIn>
+{};
+
+template <typename PointOut, typename PointIn>
+struct copy_points<PointOut, PointIn, point_tag>
+{
+ template <typename OutputIterator>
+ static inline void apply(PointIn const& point_in,
+ OutputIterator& oit)
+ {
+ PointOut point_out;
+ geometry::convert(point_in, point_out);
+ *oit++ = point_out;
+ }
+};
+
+
+template <typename PointOut, typename MultiPointIn>
+struct copy_points<PointOut, MultiPointIn, multi_point_tag>
+{
+ template <typename OutputIterator>
+ static inline void apply(MultiPointIn const& multi_point_in,
+ OutputIterator& oit)
+ {
+ for (typename boost::range_iterator<MultiPointIn const>::type
+ it = boost::begin(multi_point_in);
+ it != boost::end(multi_point_in); ++it)
+ {
+ PointOut point_out;
+ geometry::convert(*it, point_out);
+ *oit++ = point_out;
+ }
+ }
+};
+
+
+
+// action struct for difference/intersection
+template <typename PointOut, overlay_type OverlayType>
+struct action_selector_pl_pl
+{};
+
+template <typename PointOut>
+struct action_selector_pl_pl<PointOut, overlay_intersection>
+{
+ template
+ <
+ typename Point,
+ typename OutputIterator
+ >
+ static inline void apply(Point const& point,
+ bool is_common,
+ OutputIterator& oit)
+ {
+ if ( is_common )
+ {
+ copy_points<PointOut, Point>::apply(point, oit);
+ }
+ }
+};
+
+
+
+template <typename PointOut>
+struct action_selector_pl_pl<PointOut, overlay_difference>
+{
+ template
+ <
+ typename Point,
+ typename OutputIterator
+ >
+ static inline void apply(Point const& point,
+ bool is_common,
+ OutputIterator& oit)
+ {
+ if ( !is_common )
+ {
+ copy_points<PointOut, Point>::apply(point, oit);
+ }
+ }
+};
+
+
+//===========================================================================
+
+// difference/intersection of point-point
+template
+<
+ typename Point1,
+ typename Point2,
+ typename PointOut,
+ overlay_type OverlayType
+>
+struct point_point_point
+{
+ template <typename RobustPolicy, typename OutputIterator, typename Strategy>
+ static inline OutputIterator apply(Point1 const& point1,
+ Point2 const& point2,
+ RobustPolicy const& ,
+ OutputIterator oit,
+ Strategy const&)
+ {
+ action_selector_pl_pl
+ <
+ PointOut, OverlayType
+ >::apply(point1,
+ detail::equals::equals_point_point(point1, point2),
+ oit);
+
+ return oit;
+ }
+};
+
+
+
+// difference of multipoint-point
+//
+// the apply method in the following struct is called only for
+// difference; for intersection the reversal will
+// always call the point-multipoint version
+template
+<
+ typename MultiPoint,
+ typename Point,
+ typename PointOut,
+ overlay_type OverlayType
+>
+struct multipoint_point_point
+{
+ template <typename RobustPolicy, typename OutputIterator, typename Strategy>
+ static inline OutputIterator apply(MultiPoint const& multipoint,
+ Point const& point,
+ RobustPolicy const& ,
+ OutputIterator oit,
+ Strategy const&)
+ {
+ BOOST_ASSERT( OverlayType == overlay_difference );
+
+ for (typename boost::range_iterator<MultiPoint const>::type
+ it = boost::begin(multipoint);
+ it != boost::end(multipoint); ++it)
+ {
+ action_selector_pl_pl
+ <
+ PointOut, OverlayType
+ >::apply(*it,
+ detail::equals::equals_point_point(*it, point),
+ oit);
+ }
+
+ return oit;
+ }
+};
+
+
+// difference/intersection of point-multipoint
+template
+<
+ typename Point,
+ typename MultiPoint,
+ typename PointOut,
+ overlay_type OverlayType
+>
+struct point_multipoint_point
+{
+ template <typename RobustPolicy, typename OutputIterator, typename Strategy>
+ static inline OutputIterator apply(Point const& point,
+ MultiPoint const& multipoint,
+ RobustPolicy const& ,
+ OutputIterator oit,
+ Strategy const&)
+ {
+ typedef action_selector_pl_pl<PointOut, OverlayType> action;
+
+ for (typename boost::range_iterator<MultiPoint const>::type
+ it = boost::begin(multipoint);
+ it != boost::end(multipoint); ++it)
+ {
+ if ( detail::equals::equals_point_point(*it, point) )
+ {
+ action::apply(point, true, oit);
+ return oit;
+ }
+ }
+
+ action::apply(point, false, oit);
+ return oit;
+ }
+};
+
+
+
+// difference/intersection of multipoint-multipoint
+template
+<
+ typename MultiPoint1,
+ typename MultiPoint2,
+ typename PointOut,
+ overlay_type OverlayType
+>
+struct multipoint_multipoint_point
+{
+ template <typename RobustPolicy, typename OutputIterator, typename Strategy>
+ static inline OutputIterator apply(MultiPoint1 const& multipoint1,
+ MultiPoint2 const& multipoint2,
+ RobustPolicy const& robust_policy,
+ OutputIterator oit,
+ Strategy const& strategy)
+ {
+ if ( OverlayType != overlay_difference
+ && boost::size(multipoint1) > boost::size(multipoint2) )
+ {
+ return multipoint_multipoint_point
+ <
+ MultiPoint2, MultiPoint1, PointOut, OverlayType
+ >::apply(multipoint2, multipoint1, robust_policy, oit, strategy);
+ }
+
+ std::vector<typename point_type<MultiPoint2>::type>
+ points2(boost::begin(multipoint2), boost::end(multipoint2));
+
+ std::sort(points2.begin(), points2.end(), detail::relate::less());
+
+ for (typename boost::range_iterator<MultiPoint1 const>::type
+ it1 = boost::begin(multipoint1);
+ it1 != boost::end(multipoint1); ++it1)
+ {
+ bool found = std::binary_search(points2.begin(), points2.end(),
+ *it1, detail::relate::less());
+
+ action_selector_pl_pl
+ <
+ PointOut, OverlayType
+ >::apply(*it1, found, oit);
+ }
+ return oit;
+ }
+};
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+
+//===========================================================================
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace detail_dispatch { namespace overlay
+{
+
+// dispatch struct for pointlike-pointlike difference/intersection
+// computation
+template
+<
+ typename PointLike1,
+ typename PointLike2,
+ typename PointOut,
+ overlay_type OverlayType,
+ typename Tag1,
+ typename Tag2
+>
+struct pointlike_pointlike_point
+ : not_implemented<PointLike1, PointLike2, PointOut>
+{};
+
+
+template
+<
+ typename Point1,
+ typename Point2,
+ typename PointOut,
+ overlay_type OverlayType
+>
+struct pointlike_pointlike_point
+ <
+ Point1, Point2, PointOut, OverlayType,
+ point_tag, point_tag
+ > : detail::overlay::point_point_point
+ <
+ Point1, Point2, PointOut, OverlayType
+ >
+{};
+
+
+template
+<
+ typename Point,
+ typename MultiPoint,
+ typename PointOut,
+ overlay_type OverlayType
+>
+struct pointlike_pointlike_point
+ <
+ Point, MultiPoint, PointOut, OverlayType,
+ point_tag, multi_point_tag
+ > : detail::overlay::point_multipoint_point
+ <
+ Point, MultiPoint, PointOut, OverlayType
+ >
+{};
+
+
+template
+<
+ typename MultiPoint,
+ typename Point,
+ typename PointOut,
+ overlay_type OverlayType
+>
+struct pointlike_pointlike_point
+ <
+ MultiPoint, Point, PointOut, OverlayType,
+ multi_point_tag, point_tag
+ > : detail::overlay::multipoint_point_point
+ <
+ MultiPoint, Point, PointOut, OverlayType
+ >
+{};
+
+
+template
+<
+ typename MultiPoint1,
+ typename MultiPoint2,
+ typename PointOut,
+ overlay_type OverlayType
+>
+struct pointlike_pointlike_point
+ <
+ MultiPoint1, MultiPoint2, PointOut, OverlayType,
+ multi_point_tag, multi_point_tag
+ > : detail::overlay::multipoint_multipoint_point
+ <
+ MultiPoint1, MultiPoint2, PointOut, OverlayType
+ >
+{};
+
+
+}} // namespace detail_dispatch::overlay
+#endif // DOXYGEN_NO_DISPATCH
+
+
+//===========================================================================
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+
+// generic pointlike-pointlike union implementation
+template
+<
+ typename PointLike1,
+ typename PointLike2,
+ typename PointOut
+>
+struct union_pointlike_pointlike_point
+{
+ template <typename RobustPolicy, typename OutputIterator, typename Strategy>
+ static inline OutputIterator apply(PointLike1 const& pointlike1,
+ PointLike2 const& pointlike2,
+ RobustPolicy const& robust_policy,
+ OutputIterator oit,
+ Strategy const& strategy)
+ {
+ copy_points<PointOut, PointLike1>::apply(pointlike1, oit);
+
+ return detail_dispatch::overlay::pointlike_pointlike_point
+ <
+ PointLike2, PointLike1, PointOut, overlay_difference,
+ typename tag<PointLike2>::type,
+ typename tag<PointLike1>::type
+ >::apply(pointlike2, pointlike1, robust_policy, oit, strategy);
+ }
+
+};
+
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_POINTLIKE_POINTLIKE_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/segment_identifier.hpp b/boost/geometry/algorithms/detail/overlay/segment_identifier.hpp
index 007113ffba..516ec349e8 100644
--- a/boost/geometry/algorithms/detail/overlay/segment_identifier.hpp
+++ b/boost/geometry/algorithms/detail/overlay/segment_identifier.hpp
@@ -14,19 +14,19 @@
# define BOOST_GEOMETRY_DEBUG_SEGMENT_IDENTIFIER
#endif
+#if defined(BOOST_GEOMETRY_DEBUG_SEGMENT_IDENTIFIER)
+#include <iostream>
+#endif
-#include <vector>
-
-
-#include <boost/geometry/core/access.hpp>
-#include <boost/geometry/core/coordinate_dimension.hpp>
+#include <boost/geometry/algorithms/detail/signed_index_type.hpp>
namespace boost { namespace geometry
{
+
// Internal struct to uniquely identify a segment
// on a linestring,ring
// or polygon (needs ring_index)
@@ -40,7 +40,10 @@ struct segment_identifier
, segment_index(-1)
{}
- inline segment_identifier(int src, int mul, int rin, int seg)
+ inline segment_identifier(signed_index_type src,
+ signed_index_type mul,
+ signed_index_type rin,
+ signed_index_type seg)
: source_index(src)
, multi_index(mul)
, ring_index(rin)
@@ -68,20 +71,20 @@ struct segment_identifier
#if defined(BOOST_GEOMETRY_DEBUG_SEGMENT_IDENTIFIER)
friend std::ostream& operator<<(std::ostream &os, segment_identifier const& seg_id)
{
- std::cout
+ os
<< "s:" << seg_id.source_index
- << ", v:" << seg_id.segment_index // ~vertex
+ << ", v:" << seg_id.segment_index // v:vertex because s is used for source
;
- if (seg_id.ring_index >= 0) std::cout << ", r:" << seg_id.ring_index;
- if (seg_id.multi_index >= 0) std::cout << ", m:" << seg_id.multi_index;
+ if (seg_id.ring_index >= 0) os << ", r:" << seg_id.ring_index;
+ if (seg_id.multi_index >= 0) os << ", m:" << seg_id.multi_index;
return os;
}
#endif
- int source_index;
- int multi_index;
- int ring_index;
- int segment_index;
+ signed_index_type source_index;
+ signed_index_type multi_index;
+ signed_index_type ring_index;
+ signed_index_type segment_index;
};
diff --git a/boost/geometry/algorithms/detail/overlay/select_rings.hpp b/boost/geometry/algorithms/detail/overlay/select_rings.hpp
index f664b19514..385658a190 100644
--- a/boost/geometry/algorithms/detail/overlay/select_rings.hpp
+++ b/boost/geometry/algorithms/detail/overlay/select_rings.hpp
@@ -1,6 +1,7 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -9,11 +10,16 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SELECT_RINGS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SELECT_RINGS_HPP
+
#include <map>
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/area.hpp>
#include <boost/geometry/algorithms/within.hpp>
+#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
#include <boost/geometry/algorithms/detail/point_on_border.hpp>
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
#include <boost/geometry/algorithms/detail/overlay/ring_properties.hpp>
@@ -40,14 +46,14 @@ namespace dispatch
struct select_rings<box_tag, Box>
{
template <typename Geometry, typename Map>
- static inline void apply(Box const& box, Geometry const& ,
+ static inline void apply(Box const& box, Geometry const& ,
ring_identifier const& id, Map& map, bool midpoint)
{
map[id] = typename Map::mapped_type(box, midpoint);
}
template <typename Map>
- static inline void apply(Box const& box,
+ static inline void apply(Box const& box,
ring_identifier const& id, Map& map, bool midpoint)
{
map[id] = typename Map::mapped_type(box, midpoint);
@@ -68,7 +74,7 @@ namespace dispatch
}
template <typename Map>
- static inline void apply(Ring const& ring,
+ static inline void apply(Ring const& ring,
ring_identifier const& id, Map& map, bool midpoint)
{
if (boost::size(ring) > 0)
@@ -91,9 +97,10 @@ namespace dispatch
per_ring::apply(exterior_ring(polygon), geometry, id, map, midpoint);
- typename interior_return_type<Polygon const>::type rings
- = interior_rings(polygon);
- for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
+ typename interior_return_type<Polygon const>::type
+ rings = interior_rings(polygon);
+ for (typename detail::interior_iterator<Polygon const>::type
+ it = boost::begin(rings); it != boost::end(rings); ++it)
{
id.ring_index++;
per_ring::apply(*it, geometry, id, map, midpoint);
@@ -109,16 +116,42 @@ namespace dispatch
per_ring::apply(exterior_ring(polygon), id, map, midpoint);
- typename interior_return_type<Polygon const>::type rings
- = interior_rings(polygon);
- for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
+ typename interior_return_type<Polygon const>::type
+ rings = interior_rings(polygon);
+ for (typename detail::interior_iterator<Polygon const>::type
+ it = boost::begin(rings); it != boost::end(rings); ++it)
{
id.ring_index++;
per_ring::apply(*it, id, map, midpoint);
}
}
};
-}
+
+ template <typename Multi>
+ struct select_rings<multi_polygon_tag, Multi>
+ {
+ template <typename Geometry, typename Map>
+ static inline void apply(Multi const& multi, Geometry const& geometry,
+ ring_identifier id, Map& map, bool midpoint)
+ {
+ typedef typename boost::range_iterator
+ <
+ Multi const
+ >::type iterator_type;
+
+ typedef select_rings<polygon_tag, typename boost::range_value<Multi>::type> per_polygon;
+
+ id.multi_index = 0;
+ for (iterator_type it = boost::begin(multi); it != boost::end(multi); ++it)
+ {
+ id.ring_index = -1;
+ per_polygon::apply(*it, geometry, id, map, midpoint);
+ id.multi_index++;
+ }
+ }
+ };
+
+} // namespace dispatch
template<overlay_type OverlayType>
@@ -213,7 +246,7 @@ inline void update_selection_map(Geometry1 const& geometry1,
typename SelectionMap::mapped_type properties = it->second; // Copy by value
// Calculate the "within code" (previously this was done earlier but is
- // must efficienter here - it can be even more efficient doing it all at once,
+ // much efficienter here - it can be even more efficient doing it all at once,
// using partition, TODO)
// So though this is less elegant than before, it avoids many unused point-in-poly calculations
switch(id.source_index)
@@ -248,7 +281,7 @@ template
typename IntersectionMap, typename SelectionMap
>
inline void select_rings(Geometry1 const& geometry1, Geometry2 const& geometry2,
- IntersectionMap const& intersection_map,
+ IntersectionMap const& intersection_map,
SelectionMap& selection_map, bool midpoint)
{
typedef typename geometry::tag<Geometry1>::type tag1;
@@ -271,16 +304,16 @@ template
typename IntersectionMap, typename SelectionMap
>
inline void select_rings(Geometry const& geometry,
- IntersectionMap const& intersection_map,
+ IntersectionMap const& intersection_map,
SelectionMap& selection_map, bool midpoint)
{
typedef typename geometry::tag<Geometry>::type tag;
SelectionMap map_with_all;
- dispatch::select_rings<tag, Geometry>::apply(geometry,
+ dispatch::select_rings<tag, Geometry>::apply(geometry,
ring_identifier(0, -1, -1), map_with_all, midpoint);
- update_selection_map<OverlayType>(geometry, geometry, intersection_map,
+ update_selection_map<OverlayType>(geometry, geometry, intersection_map,
map_with_all, selection_map);
}
diff --git a/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp b/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp
index 9c4c99394e..8dffeae283 100644
--- a/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp
+++ b/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp
@@ -9,16 +9,18 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SELF_TURN_POINTS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SELF_TURN_POINTS_HPP
+
#include <cstddef>
#include <boost/range.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
-#include <boost/geometry/algorithms/detail/disjoint.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
#include <boost/geometry/algorithms/detail/partition.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
@@ -55,17 +57,21 @@ template
typename Geometry,
typename Turns,
typename TurnPolicy,
+ typename RobustPolicy,
typename InterruptPolicy
>
struct self_section_visitor
{
Geometry const& m_geometry;
+ RobustPolicy const& m_rescale_policy;
Turns& m_turns;
InterruptPolicy& m_interrupt_policy;
inline self_section_visitor(Geometry const& g,
+ RobustPolicy const& rp,
Turns& turns, InterruptPolicy& ip)
: m_geometry(g)
+ , m_rescale_policy(rp)
, m_turns(turns)
, m_interrupt_policy(ip)
{}
@@ -82,12 +88,12 @@ struct self_section_visitor
Geometry, Geometry,
false, false,
Section, Section,
- Turns, TurnPolicy,
- InterruptPolicy
+ TurnPolicy
>::apply(
0, m_geometry, sec1,
0, m_geometry, sec2,
false,
+ m_rescale_policy,
m_turns, m_interrupt_policy);
}
if (m_interrupt_policy.has_intersections)
@@ -103,17 +109,13 @@ struct self_section_visitor
-template
-<
- typename Geometry,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
->
+template<typename TurnPolicy>
struct get_turns
{
+ template <typename Geometry, typename RobustPolicy, typename Turns, typename InterruptPolicy>
static inline bool apply(
Geometry const& geometry,
+ RobustPolicy const& robust_policy,
Turns& turns,
InterruptPolicy& interrupt_policy)
{
@@ -127,20 +129,20 @@ struct get_turns
> sections_type;
sections_type sec;
- geometry::sectionalize<false>(geometry, sec);
+ geometry::sectionalize<false>(geometry, robust_policy, false, sec);
self_section_visitor
<
Geometry,
- Turns, TurnPolicy, InterruptPolicy
- > visitor(geometry, turns, interrupt_policy);
+ Turns, TurnPolicy, RobustPolicy, InterruptPolicy
+ > visitor(geometry, robust_policy, turns, interrupt_policy);
try
{
geometry::partition
<
- box_type,
- detail::get_turns::get_section_box,
+ box_type,
+ detail::get_turns::get_section_box,
detail::get_turns::ovelaps_section_box
>::apply(sec, visitor);
}
@@ -166,9 +168,7 @@ template
<
typename GeometryTag,
typename Geometry,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
+ typename TurnPolicy
>
struct self_get_turn_points
{
@@ -178,44 +178,32 @@ struct self_get_turn_points
template
<
typename Ring,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
+ typename TurnPolicy
>
struct self_get_turn_points
<
ring_tag, Ring,
- Turns,
- TurnPolicy,
- InterruptPolicy
+ TurnPolicy
>
- : detail::self_get_turn_points::get_turns
- <
- Ring,
- Turns,
- TurnPolicy,
- InterruptPolicy
- >
+ : detail::self_get_turn_points::get_turns<TurnPolicy>
{};
template
<
typename Box,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
+ typename TurnPolicy
>
struct self_get_turn_points
<
box_tag, Box,
- Turns,
- TurnPolicy,
- InterruptPolicy
+ TurnPolicy
>
{
+ template <typename RobustPolicy, typename Turns, typename InterruptPolicy>
static inline bool apply(
Box const& ,
+ RobustPolicy const& ,
Turns& ,
InterruptPolicy& )
{
@@ -227,24 +215,28 @@ struct self_get_turn_points
template
<
typename Polygon,
- typename Turns,
- typename TurnPolicy,
- typename InterruptPolicy
+ typename TurnPolicy
>
struct self_get_turn_points
<
polygon_tag, Polygon,
- Turns,
- TurnPolicy,
- InterruptPolicy
+ TurnPolicy
+ >
+ : detail::self_get_turn_points::get_turns<TurnPolicy>
+{};
+
+
+template
+<
+ typename MultiPolygon,
+ typename TurnPolicy
+>
+struct self_get_turn_points
+ <
+ multi_polygon_tag, MultiPolygon,
+ TurnPolicy
>
- : detail::self_get_turn_points::get_turns
- <
- Polygon,
- Turns,
- TurnPolicy,
- InterruptPolicy
- >
+ : detail::self_get_turn_points::get_turns<TurnPolicy>
{};
@@ -259,6 +251,7 @@ struct self_get_turn_points
\tparam Turns type of intersection container
(e.g. vector of "intersection/turn point"'s)
\param geometry geometry
+ \param robust_policy policy to handle robustness issues
\param turns container which will contain intersection points
\param interrupt_policy policy determining if process is stopped
when intersection is found
@@ -267,38 +260,24 @@ template
<
typename AssignPolicy,
typename Geometry,
+ typename RobustPolicy,
typename Turns,
typename InterruptPolicy
>
inline void self_turns(Geometry const& geometry,
+ RobustPolicy const& robust_policy,
Turns& turns, InterruptPolicy& interrupt_policy)
{
concept::check<Geometry const>();
- typedef typename strategy_intersection
- <
- typename cs_tag<Geometry>::type,
- Geometry,
- Geometry,
- typename boost::range_value<Turns>::type
- >::segment_intersection_strategy_type strategy_type;
-
- typedef detail::overlay::get_turn_info
- <
- typename point_type<Geometry>::type,
- typename point_type<Geometry>::type,
- typename boost::range_value<Turns>::type,
- detail::overlay::assign_null_policy
- > TurnPolicy;
+ typedef detail::overlay::get_turn_info<detail::overlay::assign_null_policy> turn_policy;
dispatch::self_get_turn_points
<
typename tag<Geometry>::type,
Geometry,
- Turns,
- TurnPolicy,
- InterruptPolicy
- >::apply(geometry, turns, interrupt_policy);
+ turn_policy
+ >::apply(geometry, robust_policy, turns, interrupt_policy);
}
diff --git a/boost/geometry/algorithms/detail/overlay/stream_info.hpp b/boost/geometry/algorithms/detail/overlay/stream_info.hpp
index eebe381944..51fd1b3dca 100644
--- a/boost/geometry/algorithms/detail/overlay/stream_info.hpp
+++ b/boost/geometry/algorithms/detail/overlay/stream_info.hpp
@@ -35,7 +35,6 @@ namespace detail { namespace overlay
template <typename P>
std::ostream& operator<<(std::ostream &os, turn_info<P> const& info)
{
- typename geometry::coordinate_type<P>::type d = info.distance;
os << "\t"
<< " src " << info.seg_id.source_index
<< " seg " << info.seg_id.segment_index
@@ -54,7 +53,7 @@ namespace detail { namespace overlay
<< " nxt seg " << info.travels_to_vertex_index
<< " , ip " << info.travels_to_ip_index
<< " , or " << info.next_ip_index
- << " dst " << double(d)
+ << " frac " << info.fraction
<< info.visit_state;
if (info.flagged)
{
diff --git a/boost/geometry/algorithms/detail/overlay/traversal_info.hpp b/boost/geometry/algorithms/detail/overlay/traversal_info.hpp
index 810a27af04..6ee32c17c0 100644
--- a/boost/geometry/algorithms/detail/overlay/traversal_info.hpp
+++ b/boost/geometry/algorithms/detail/overlay/traversal_info.hpp
@@ -24,15 +24,21 @@ namespace detail { namespace overlay
{
-template <typename P>
-struct traversal_turn_operation : public turn_operation
+template <typename Point, typename SegmentRatio>
+struct traversal_turn_operation : public turn_operation<SegmentRatio>
{
- enrichment_info<P> enriched;
+ enrichment_info<Point> enriched;
visit_info visited;
};
-template <typename P>
-struct traversal_turn_info : public turn_info<P, traversal_turn_operation<P> >
+template <typename Point, typename SegmentRatio>
+struct traversal_turn_info
+ : public turn_info
+ <
+ Point,
+ SegmentRatio,
+ traversal_turn_operation<Point, SegmentRatio>
+ >
{};
diff --git a/boost/geometry/algorithms/detail/overlay/traverse.hpp b/boost/geometry/algorithms/detail/overlay/traverse.hpp
index 12daafa0cf..59d2ba703e 100644
--- a/boost/geometry/algorithms/detail/overlay/traverse.hpp
+++ b/boost/geometry/algorithms/detail/overlay/traverse.hpp
@@ -13,11 +13,12 @@
#include <boost/range.hpp>
-#include <boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp>
#include <boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp>
#include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+#include <boost/geometry/algorithms/num_points.hpp>
#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
@@ -38,7 +39,7 @@ namespace detail { namespace overlay
template <typename Turn, typename Operation>
#ifdef BOOST_GEOMETRY_DEBUG_TRAVERSE
-inline void debug_traverse(Turn const& turn, Operation op,
+inline void debug_traverse(Turn const& turn, Operation op,
std::string const& header)
{
std::cout << header
@@ -57,7 +58,7 @@ inline void debug_traverse(Turn const& turn, Operation op,
}
}
#else
-inline void debug_traverse(Turn const& , Operation, std::string const& )
+inline void debug_traverse(Turn const& , Operation, const char*)
{
}
#endif
@@ -92,14 +93,16 @@ template
typename G1,
typename G2,
typename Turns,
- typename IntersectionInfo
+ typename IntersectionInfo,
+ typename RobustPolicy
>
inline bool assign_next_ip(G1 const& g1, G2 const& g2,
Turns& turns,
typename boost::range_iterator<Turns>::type& ip,
GeometryOut& current_output,
IntersectionInfo& info,
- segment_identifier& seg_id)
+ segment_identifier& seg_id,
+ RobustPolicy const& robust_policy)
{
info.visited.set_visited();
set_visited_for_continue(*ip, info);
@@ -107,7 +110,7 @@ inline bool assign_next_ip(G1 const& g1, G2 const& g2,
// If there is no next IP on this segment
if (info.enriched.next_ip_index < 0)
{
- if (info.enriched.travels_to_vertex_index < 0
+ if (info.enriched.travels_to_vertex_index < 0
|| info.enriched.travels_to_ip_index < 0)
{
return false;
@@ -120,12 +123,14 @@ inline bool assign_next_ip(G1 const& g1, G2 const& g2,
{
geometry::copy_segments<Reverse1>(g1, info.seg_id,
info.enriched.travels_to_vertex_index,
+ robust_policy,
current_output);
}
else
{
geometry::copy_segments<Reverse2>(g2, info.seg_id,
info.enriched.travels_to_vertex_index,
+ robust_policy,
current_output);
}
seg_id = info.seg_id;
@@ -137,12 +142,16 @@ inline bool assign_next_ip(G1 const& g1, G2 const& g2,
seg_id = info.seg_id;
}
- detail::overlay::append_no_duplicates(current_output, ip->point);
+ detail::overlay::append_no_dups_or_spikes(current_output, ip->point,
+ robust_policy);
+
return true;
}
-inline bool select_source(operation_type operation, int source1, int source2)
+inline bool select_source(operation_type operation,
+ signed_index_type source1,
+ signed_index_type source2)
{
return (operation == operation_intersection && source1 != source2)
|| (operation == operation_union && source1 == source2)
@@ -227,12 +236,14 @@ template
class traverse
{
public :
- template <typename Turns, typename Rings>
+ template <typename RobustPolicy, typename Turns, typename Rings>
static inline void apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
detail::overlay::operation_type operation,
+ RobustPolicy const& robust_policy,
Turns& turns, Rings& rings)
{
+ typedef typename boost::range_value<Rings>::type ring_type;
typedef typename boost::range_iterator<Turns>::type turn_iterator;
typedef typename boost::range_value<Turns>::type turn_type;
typedef typename boost::range_iterator
@@ -240,6 +251,12 @@ public :
typename turn_type::container_type
>::type turn_operation_iterator_type;
+ std::size_t const min_num_points
+ = core_detail::closure::minimum_ring_size
+ <
+ geometry::closure<ring_type>::value
+ >::value;
+
std::size_t size_at_start = boost::size(rings);
typename Backtrack::state_type state;
@@ -253,7 +270,7 @@ public :
++it)
{
// Skip discarded ones
- if (! (it->is_discarded() || it->blocked()))
+ if (! (it->discarded || ! it->selectable_start || it->blocked()))
{
for (turn_operation_iterator_type iit = boost::begin(it->operations);
state.good() && iit != boost::end(it->operations);
@@ -267,9 +284,9 @@ public :
{
set_visited_for_continue(*it, *iit);
- typename boost::range_value<Rings>::type current_output;
- detail::overlay::append_no_duplicates(current_output,
- it->point, true);
+ ring_type current_output;
+ detail::overlay::append_no_dups_or_spikes(current_output,
+ it->point, robust_policy);
turn_iterator current = it;
turn_operation_iterator_type current_iit = iit;
@@ -279,13 +296,14 @@ public :
geometry1, geometry2,
turns,
current, current_output,
- *iit, current_seg_id))
+ *iit, current_seg_id,
+ robust_policy))
{
Backtrack::apply(
- size_at_start,
+ size_at_start,
rings, current_output, turns, *current_iit,
"No next IP",
- geometry1, geometry2, state);
+ geometry1, geometry2, robust_policy, state);
}
if (! detail::overlay::select_next_ip(
@@ -295,10 +313,10 @@ public :
current_iit))
{
Backtrack::apply(
- size_at_start,
+ size_at_start,
rings, current_output, turns, *iit,
"Dead end at start",
- geometry1, geometry2, state);
+ geometry1, geometry2, robust_policy, state);
}
else
{
@@ -308,7 +326,7 @@ public :
detail::overlay::debug_traverse(*current, *current_iit, "Selected ");
- unsigned int i = 0;
+ typename boost::range_size<Turns>::type i = 0;
while (current_iit != iit && state.good())
{
@@ -317,10 +335,10 @@ public :
// It visits a visited node again, without passing the start node.
// This makes it suspicious for endless loops
Backtrack::apply(
- size_at_start,
+ size_at_start,
rings, current_output, turns, *iit,
"Visit again",
- geometry1, geometry2, state);
+ geometry1, geometry2, robust_policy, state);
}
else
{
@@ -339,7 +357,8 @@ public :
detail::overlay::assign_next_ip<Reverse1, Reverse2>(
geometry1, geometry2,
turns, current, current_output,
- *current_iit, current_seg_id);
+ *current_iit, current_seg_id,
+ robust_policy);
if (! detail::overlay::select_next_ip(
operation,
@@ -351,12 +370,15 @@ public :
// Should not occur in self-intersecting polygons without spikes
// Might occur in polygons with spikes
Backtrack::apply(
- size_at_start,
+ size_at_start,
rings, current_output, turns, *iit,
"Dead end",
- geometry1, geometry2, state);
+ geometry1, geometry2, robust_policy, state);
+ }
+ else
+ {
+ detail::overlay::debug_traverse(*current, *current_iit, "Selected ");
}
- detail::overlay::debug_traverse(*current, *current_iit, "Selected ");
if (i++ > 2 + 2 * turns.size())
{
@@ -364,10 +386,10 @@ public :
// than turn points.
// Turn points marked as "ii" can be visited twice.
Backtrack::apply(
- size_at_start,
+ size_at_start,
rings, current_output, turns, *iit,
"Endless loop",
- geometry1, geometry2, state);
+ geometry1, geometry2, robust_policy, state);
}
}
}
@@ -376,7 +398,11 @@ public :
{
iit->visited.set_finished();
detail::overlay::debug_traverse(*current, *iit, "->Finished");
- rings.push_back(current_output);
+ if (geometry::num_points(current_output) >= min_num_points)
+ {
+ clean_closing_dups_and_spikes(current_output, robust_policy);
+ rings.push_back(current_output);
+ }
}
}
}
diff --git a/boost/geometry/algorithms/detail/overlay/turn_info.hpp b/boost/geometry/algorithms/detail/overlay/turn_info.hpp
index 89a60b21ab..26669a4b1f 100644
--- a/boost/geometry/algorithms/detail/overlay/turn_info.hpp
+++ b/boost/geometry/algorithms/detail/overlay/turn_info.hpp
@@ -54,11 +54,12 @@ enum method_type
The class is to be included in the turn_info class, either direct
or a derived or similar class with more (e.g. enrichment) information.
*/
+template <typename SegmentRatio>
struct turn_operation
{
operation_type operation;
segment_identifier seg_id;
- segment_identifier other_id;
+ SegmentRatio fraction;
inline turn_operation()
: operation(operation_none)
@@ -78,7 +79,8 @@ struct turn_operation
template
<
typename Point,
- typename Operation = turn_operation,
+ typename SegmentRatio,
+ typename Operation = turn_operation<SegmentRatio>,
typename Container = boost::array<Operation, 2>
>
struct turn_info
@@ -90,6 +92,7 @@ struct turn_info
Point point;
method_type method;
bool discarded;
+ bool selectable_start; // Can be used as starting-turn in traverse
Container operations;
@@ -97,13 +100,14 @@ struct turn_info
inline turn_info()
: method(method_none)
, discarded(false)
+ , selectable_start(true)
{}
inline bool both(operation_type type) const
{
return has12(type, type);
}
-
+
inline bool has(operation_type type) const
{
return this->operations[0].operation == type
@@ -115,8 +119,6 @@ struct turn_info
return has12(type1, type2) || has12(type2, type1);
}
-
- inline bool is_discarded() const { return discarded; }
inline bool blocked() const
{
return both(operation_blocked);
diff --git a/boost/geometry/algorithms/detail/overlay/visit_info.hpp b/boost/geometry/algorithms/detail/overlay/visit_info.hpp
index 6be63f42b4..4284a801a1 100644
--- a/boost/geometry/algorithms/detail/overlay/visit_info.hpp
+++ b/boost/geometry/algorithms/detail/overlay/visit_info.hpp
@@ -10,11 +10,6 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_VISIT_INFO_HPP
-#ifdef BOOST_GEOMETRY_USE_MSM
-# include <boost/geometry/algorithms/detail/overlay/msm_state.hpp>
-#endif
-
-
namespace boost { namespace geometry
{
@@ -22,9 +17,6 @@ namespace boost { namespace geometry
namespace detail { namespace overlay
{
-
-#if ! defined(BOOST_GEOMETRY_USE_MSM)
-
class visit_info
{
private :
@@ -66,8 +58,6 @@ public:
}
}
-
-
#ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION
friend std::ostream& operator<<(std::ostream &os, visit_info const& v)
{
@@ -82,50 +72,6 @@ public:
};
-#else
-
-
-class visit_info
-{
-
-private :
-
-#ifndef USE_MSM_MINI
- mutable
-#endif
- traverse_state state;
-
-public :
- inline visit_info()
- {
- state.start();
- }
-
- inline void set_none() { state.process_event(none()); } // Not Yet Implemented!
- inline void set_visited() { state.process_event(visit()); }
- inline void set_started() { state.process_event(starting()); }
- inline void set_finished() { state.process_event(finish()); }
-
-#ifdef USE_MSM_MINI
- inline bool none() const { return state.flag_none(); }
- inline bool visited() const { return state.flag_visited(); }
- inline bool started() const { return state.flag_started(); }
-#else
- inline bool none() const { return state.is_flag_active<is_init>(); }
- inline bool visited() const { return state.is_flag_active<is_visited>(); }
- inline bool started() const { return state.is_flag_active<is_started>(); }
-#endif
-
-#ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION
- friend std::ostream& operator<<(std::ostream &os, visit_info const& v)
- {
- return os;
- }
-#endif
-};
-#endif
-
-
}} // namespace detail::overlay
#endif //DOXYGEN_NO_DETAIL