summaryrefslogtreecommitdiff
path: root/boost/geometry/algorithms/detail
diff options
context:
space:
mode:
Diffstat (limited to 'boost/geometry/algorithms/detail')
-rw-r--r--boost/geometry/algorithms/detail/azimuth.hpp158
-rw-r--r--boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp155
-rw-r--r--boost/geometry/algorithms/detail/buffer/buffer_policies.hpp11
-rw-r--r--boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp503
-rw-r--r--boost/geometry/algorithms/detail/buffer/buffered_ring.hpp6
-rw-r--r--boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp152
-rw-r--r--boost/geometry/algorithms/detail/buffer/turn_in_input.hpp98
-rw-r--r--boost/geometry/algorithms/detail/buffer/turn_in_original_visitor.hpp268
-rw-r--r--boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp557
-rw-r--r--boost/geometry/algorithms/detail/closest_feature/geometry_to_range.hpp3
-rw-r--r--boost/geometry/algorithms/detail/closest_feature/range_to_range.hpp1
-rw-r--r--boost/geometry/algorithms/detail/comparable_distance/interface.hpp20
-rw-r--r--boost/geometry/algorithms/detail/course.hpp24
-rw-r--r--boost/geometry/algorithms/detail/disjoint/box_box.hpp2
-rw-r--r--boost/geometry/algorithms/detail/disjoint/implementation.hpp1
-rw-r--r--boost/geometry/algorithms/detail/disjoint/interface.hpp2
-rw-r--r--boost/geometry/algorithms/detail/disjoint/linear_areal.hpp104
-rw-r--r--boost/geometry/algorithms/detail/disjoint/linear_linear.hpp47
-rw-r--r--boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.hpp31
-rw-r--r--boost/geometry/algorithms/detail/disjoint/multipoint_geometry.hpp162
-rw-r--r--boost/geometry/algorithms/detail/disjoint/multirange_geometry.hpp85
-rw-r--r--boost/geometry/algorithms/detail/disjoint/point_box.hpp15
-rw-r--r--boost/geometry/algorithms/detail/distance/geometry_to_segment_or_box.hpp8
-rw-r--r--boost/geometry/algorithms/detail/distance/interface.hpp20
-rw-r--r--boost/geometry/algorithms/detail/distance/multipoint_to_geometry.hpp33
-rw-r--r--boost/geometry/algorithms/detail/distance/segment_to_box.hpp3
-rw-r--r--boost/geometry/algorithms/detail/distance/segment_to_segment.hpp4
-rw-r--r--boost/geometry/algorithms/detail/equals/collect_vectors.hpp5
-rw-r--r--boost/geometry/algorithms/detail/flattening.hpp69
-rw-r--r--boost/geometry/algorithms/detail/intersection/interface.hpp8
-rw-r--r--boost/geometry/algorithms/detail/is_simple/areal.hpp6
-rw-r--r--boost/geometry/algorithms/detail/is_simple/debug_print_boundary_points.hpp81
-rw-r--r--boost/geometry/algorithms/detail/is_simple/failure_policy.hpp53
-rw-r--r--boost/geometry/algorithms/detail/is_simple/interface.hpp2
-rw-r--r--boost/geometry/algorithms/detail/is_simple/linear.hpp305
-rw-r--r--boost/geometry/algorithms/detail/is_simple/multipoint.hpp9
-rw-r--r--boost/geometry/algorithms/detail/is_valid/box.hpp27
-rw-r--r--boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp50
-rw-r--r--boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp4
-rw-r--r--boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp13
-rw-r--r--boost/geometry/algorithms/detail/is_valid/has_spikes.hpp36
-rw-r--r--boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp32
-rw-r--r--boost/geometry/algorithms/detail/is_valid/interface.hpp99
-rw-r--r--boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp12
-rw-r--r--boost/geometry/algorithms/detail/is_valid/linear.hpp81
-rw-r--r--boost/geometry/algorithms/detail/is_valid/multipolygon.hpp131
-rw-r--r--boost/geometry/algorithms/detail/is_valid/pointlike.hpp28
-rw-r--r--boost/geometry/algorithms/detail/is_valid/polygon.hpp163
-rw-r--r--boost/geometry/algorithms/detail/is_valid/ring.hpp98
-rw-r--r--boost/geometry/algorithms/detail/is_valid/segment.hpp16
-rw-r--r--boost/geometry/algorithms/detail/not.hpp17
-rw-r--r--boost/geometry/algorithms/detail/occupation_info.hpp6
-rw-r--r--boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp7
-rw-r--r--boost/geometry/algorithms/detail/overlay/assign_parents.hpp19
-rw-r--r--boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp33
-rw-r--r--boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp59
-rw-r--r--boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp26
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_turn_info.hpp111
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp10
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp4
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp195
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp78
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_turns.hpp80
-rw-r--r--boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp43
-rw-r--r--boost/geometry/algorithms/detail/overlay/intersection_insert.hpp9
-rw-r--r--boost/geometry/algorithms/detail/overlay/linear_linear.hpp5
-rw-r--r--boost/geometry/algorithms/detail/overlay/overlay.hpp118
-rw-r--r--boost/geometry/algorithms/detail/overlay/ring_properties.hpp14
-rw-r--r--boost/geometry/algorithms/detail/overlay/select_rings.hpp217
-rw-r--r--boost/geometry/algorithms/detail/overlay/self_turn_points.hpp25
-rw-r--r--boost/geometry/algorithms/detail/partition.hpp349
-rw-r--r--boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp3
-rw-r--r--boost/geometry/algorithms/detail/relate/areal_areal.hpp52
-rw-r--r--boost/geometry/algorithms/detail/relate/follow_helpers.hpp13
-rw-r--r--boost/geometry/algorithms/detail/relate/linear_areal.hpp385
-rw-r--r--boost/geometry/algorithms/detail/relate/linear_linear.hpp35
-rw-r--r--boost/geometry/algorithms/detail/relate/point_geometry.hpp12
-rw-r--r--boost/geometry/algorithms/detail/relate/result.hpp27
-rw-r--r--boost/geometry/algorithms/detail/relate/turns.hpp85
-rw-r--r--boost/geometry/algorithms/detail/sections/range_by_section.hpp9
-rw-r--r--boost/geometry/algorithms/detail/sections/section_box_policies.hpp49
-rw-r--r--boost/geometry/algorithms/detail/sections/section_functions.hpp66
-rw-r--r--boost/geometry/algorithms/detail/sections/sectionalize.hpp368
-rw-r--r--boost/geometry/algorithms/detail/single_geometry.hpp3
-rw-r--r--boost/geometry/algorithms/detail/sub_range.hpp12
-rw-r--r--boost/geometry/algorithms/detail/turns/print_turns.hpp37
-rw-r--r--boost/geometry/algorithms/detail/vincenty_direct.hpp190
-rw-r--r--boost/geometry/algorithms/detail/vincenty_inverse.hpp218
-rw-r--r--boost/geometry/algorithms/detail/within/point_in_geometry.hpp24
89 files changed, 5006 insertions, 1808 deletions
diff --git a/boost/geometry/algorithms/detail/azimuth.hpp b/boost/geometry/algorithms/detail/azimuth.hpp
new file mode 100644
index 0000000..7810b48
--- /dev/null
+++ b/boost/geometry/algorithms/detail/azimuth.hpp
@@ -0,0 +1,158 @@
+// 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_AZIMUTH_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_AZIMUTH_HPP
+
+#include <boost/geometry/core/cs.hpp>
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/radian_access.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/util/math.hpp>
+
+#include <boost/geometry/algorithms/not_implemented.hpp>
+#include <boost/geometry/algorithms/detail/vincenty_inverse.hpp>
+
+namespace boost { namespace geometry
+{
+
+// An azimuth is an angle between a vector/segment from origin to a point of
+// interest and a reference vector. Typically north-based azimuth is used.
+// North direction is used as a reference, angle is measured clockwise
+// (North - 0deg, East - 90deg). For consistency in 2d cartesian CS
+// the reference vector is Y axis, angle is measured clockwise.
+// http://en.wikipedia.org/wiki/Azimuth
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace detail_dispatch
+{
+
+template <typename ReturnType, typename Tag>
+struct azimuth
+ : not_implemented<Tag>
+{};
+
+template <typename ReturnType>
+struct azimuth<ReturnType, geographic_tag>
+{
+ template <typename P1, typename P2, typename Spheroid>
+ static inline ReturnType apply(P1 const& p1, P2 const& p2, Spheroid const& spheroid)
+ {
+ return geometry::detail::vincenty_inverse<ReturnType>
+ ( get_as_radian<0>(p1), get_as_radian<1>(p1),
+ get_as_radian<0>(p2), get_as_radian<1>(p2),
+ spheroid ).azimuth12();
+ }
+
+ template <typename P1, typename P2>
+ static inline ReturnType apply(P1 const& p1, P2 const& p2)
+ {
+ return apply(p1, p2, srs::spheroid<ReturnType>());
+ }
+};
+
+template <typename ReturnType>
+struct azimuth<ReturnType, spherical_equatorial_tag>
+{
+ template <typename P1, typename P2, typename Sphere>
+ static inline ReturnType apply(P1 const& p1, P2 const& p2, Sphere const& /*unused*/)
+ {
+ // http://williams.best.vwh.net/avform.htm#Crs
+ ReturnType dlon = get_as_radian<0>(p2) - get_as_radian<0>(p1);
+ ReturnType cos_p2lat = cos(get_as_radian<1>(p2));
+
+ // An optimization which should kick in often for Boxes
+ //if ( math::equals(dlon, ReturnType(0)) )
+ //if ( get<0>(p1) == get<0>(p2) )
+ //{
+ // return - sin(get_as_radian<1>(p1)) * cos_p2lat);
+ //}
+
+ // "An alternative formula, not requiring the pre-computation of d"
+ // In the formula below dlon is used as "d"
+ return atan2(sin(dlon) * cos_p2lat,
+ cos(get_as_radian<1>(p1)) * sin(get_as_radian<1>(p2))
+ - sin(get_as_radian<1>(p1)) * cos_p2lat * cos(dlon));
+ }
+
+ template <typename P1, typename P2>
+ static inline ReturnType apply(P1 const& p1, P2 const& p2)
+ {
+ return apply(p1, p2, 0); // dummy model
+ }
+};
+
+template <typename ReturnType>
+struct azimuth<ReturnType, spherical_polar_tag>
+ : azimuth<ReturnType, spherical_equatorial_tag>
+{};
+
+template <typename ReturnType>
+struct azimuth<ReturnType, cartesian_tag>
+{
+ template <typename P1, typename P2, typename Plane>
+ static inline ReturnType apply(P1 const& p1, P2 const& p2, Plane const& /*unused*/)
+ {
+ ReturnType x = get<0>(p2) - get<0>(p1);
+ ReturnType y = get<1>(p2) - get<1>(p1);
+
+ // NOTE: azimuth 0 is at Y axis, increasing right
+ // as in spherical/geographic where 0 is at North axis
+ return atan2(x, y);
+ }
+
+ template <typename P1, typename P2>
+ static inline ReturnType apply(P1 const& p1, P2 const& p2)
+ {
+ return apply(p1, p2, 0); // dummy model
+ }
+};
+
+} // detail_dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail
+{
+
+/// Calculate azimuth between two points.
+/// The result is in radians.
+template <typename ReturnType, typename Point1, typename Point2>
+inline ReturnType azimuth(Point1 const& p1, Point2 const& p2)
+{
+ return detail_dispatch::azimuth
+ <
+ ReturnType,
+ typename geometry::cs_tag<Point1>::type
+ >::apply(p1, p2);
+}
+
+/// Calculate azimuth between two points.
+/// The result is in radians.
+template <typename ReturnType, typename Point1, typename Point2, typename Model>
+inline ReturnType azimuth(Point1 const& p1, Point2 const& p2, Model const& model)
+{
+ return detail_dispatch::azimuth
+ <
+ ReturnType,
+ typename geometry::cs_tag<Point1>::type
+ >::apply(p1, p2, model);
+}
+
+} // namespace detail
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_AZIMUTH_HPP
diff --git a/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp b/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp
index c959ee8..127e4c3 100644
--- a/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp
+++ b/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp
@@ -12,6 +12,7 @@
#include <cstddef>
#include <iterator>
+#include <boost/core/ignore_unused.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/range.hpp>
@@ -20,6 +21,7 @@
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/util/condition.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/strategies/buffer.hpp>
@@ -28,6 +30,7 @@
#include <boost/geometry/algorithms/detail/buffer/line_line_intersection.hpp>
#include <boost/geometry/algorithms/detail/buffer/parallel_continue.hpp>
+#include <boost/geometry/algorithms/num_interior_rings.hpp>
#include <boost/geometry/algorithms/simplify.hpp>
#include <boost/geometry/views/detail/normalized_view.hpp>
@@ -144,15 +147,25 @@ struct buffer_range
intersection_point);
}
+
switch(join)
{
case strategy::buffer::join_continue :
// No join, we get two consecutive sides
- return;
+ break;
case strategy::buffer::join_concave :
- collection.add_piece(strategy::buffer::buffered_concave,
- previous_input, prev_perp2, perp1);
- return;
+ {
+ std::vector<output_point_type> range_out;
+ range_out.push_back(prev_perp2);
+ range_out.push_back(previous_input);
+ collection.add_piece(strategy::buffer::buffered_concave, previous_input, range_out);
+
+ range_out.clear();
+ range_out.push_back(previous_input);
+ range_out.push_back(perp1);
+ collection.add_piece(strategy::buffer::buffered_concave, previous_input, range_out);
+ }
+ break;
case strategy::buffer::join_spike :
{
// For linestrings, only add spike at one side to avoid
@@ -160,22 +173,24 @@ struct buffer_range
std::vector<output_point_type> range_out;
end_strategy.apply(penultimate_input, prev_perp2, previous_input, perp1, side, distance, range_out);
collection.add_endcap(end_strategy, range_out, previous_input);
+ collection.set_current_ring_concave();
}
- return;
+ break;
case strategy::buffer::join_convex :
- break; // All code below handles this
- }
-
- // The corner is convex, we create a join
- // TODO (future) - avoid a separate vector, add the piece directly
- std::vector<output_point_type> range_out;
- if (join_strategy.apply(intersection_point,
- previous_input, prev_perp2, perp1,
- distance.apply(previous_input, input, side),
- range_out))
- {
- collection.add_piece(strategy::buffer::buffered_join,
- previous_input, range_out);
+ {
+ // The corner is convex, we create a join
+ // TODO (future) - avoid a separate vector, add the piece directly
+ std::vector<output_point_type> range_out;
+ if (join_strategy.apply(intersection_point,
+ previous_input, prev_perp2, perp1,
+ distance.apply(previous_input, input, side),
+ range_out))
+ {
+ collection.add_piece(strategy::buffer::buffered_join,
+ previous_input, range_out);
+ }
+ }
+ break;
}
}
@@ -225,18 +240,13 @@ struct buffer_range
output_point_type& last_p1,
output_point_type& last_p2)
{
+ boost::ignore_unused(side_strategy);
+
typedef typename std::iterator_traits
<
Iterator
>::value_type point_type;
- typedef typename robust_point_type
- <
- point_type,
- RobustPolicy
- >::type robust_point_type;
-
- robust_point_type previous_robust_input;
point_type second_point, penultimate_point, ultimate_point; // last two points from begin/end
/*
@@ -261,57 +271,50 @@ struct buffer_range
Iterator it = begin;
- geometry::recalculate(previous_robust_input, *begin, robust_policy);
-
std::vector<output_point_type> generated_side;
generated_side.reserve(2);
for (Iterator prev = it++; it != end; ++it)
{
- robust_point_type robust_input;
- geometry::recalculate(robust_input, *it, robust_policy);
- // Check on equality - however, if input is simplified, this is
- // unlikely (though possible by rescaling or for degenerated pointlike polygons)
- if (! detail::equals::equals_point_point(previous_robust_input, robust_input))
- {
- generated_side.clear();
- side_strategy.apply(*prev, *it, side,
- distance_strategy, generated_side);
+ generated_side.clear();
+ side_strategy.apply(*prev, *it, side,
+ distance_strategy, generated_side);
- if (generated_side.empty())
- {
- break;
- }
+ if (generated_side.empty())
+ {
+ // Because input is simplified, this is improbable,
+ // but it can happen for degenerate geometries
+ // Further handling of this side is skipped
+ continue;
+ }
- result = true;
+ result = true;
- if (! first)
- {
- add_join(collection,
- penultimate_point,
- *prev, last_p1, last_p2,
- *it, generated_side.front(), generated_side.back(),
- side,
- distance_strategy, join_strategy, end_strategy,
- robust_policy);
- }
+ if (! first)
+ {
+ add_join(collection,
+ penultimate_point,
+ *prev, last_p1, last_p2,
+ *it, generated_side.front(), generated_side.back(),
+ side,
+ distance_strategy, join_strategy, end_strategy,
+ robust_policy);
+ }
- collection.add_side_piece(*prev, *it, generated_side, first);
+ collection.add_side_piece(*prev, *it, generated_side, first);
- penultimate_point = *prev;
- ultimate_point = *it;
- last_p1 = generated_side.front();
- last_p2 = generated_side.back();
- prev = it;
- if (first)
- {
- first = false;
- second_point = *it;
- first_p1 = generated_side.front();
- first_p2 = generated_side.back();
- }
+ penultimate_point = *prev;
+ ultimate_point = *it;
+ last_p1 = generated_side.front();
+ last_p2 = generated_side.back();
+ prev = it;
+ if (first)
+ {
+ first = false;
+ second_point = *it;
+ first_p1 = generated_side.front();
+ first_p2 = generated_side.back();
}
- previous_robust_input = robust_input;
}
return result;
}
@@ -775,7 +778,7 @@ public:
distance, side_strategy,
join_strategy, end_strategy, point_strategy,
robust_policy);
- collection.finish_ring();
+ collection.finish_ring(false, geometry::num_interior_rings(polygon) > 0u);
}
apply_interior_rings(interior_rings(polygon),
@@ -839,6 +842,8 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator
VisitPiecesPolicy& visit_pieces_policy
)
{
+ boost::ignore_unused(visit_pieces_policy);
+
typedef detail::buffer::buffered_piece_collection
<
typename geometry::ring_type<GeometryOutput>::type,
@@ -852,6 +857,11 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator
typename tag_cast<typename tag<GeometryInput>::type, areal_tag>::type,
areal_tag
>::type::value;
+ bool const linear = boost::is_same
+ <
+ typename tag_cast<typename tag<GeometryInput>::type, linear_tag>::type,
+ linear_tag
+ >::type::value;
dispatch::buffer_inserter
<
@@ -868,9 +878,10 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator
robust_policy);
collection.get_turns();
- if (areal)
+ collection.classify_turns(linear);
+ if (BOOST_GEOMETRY_CONDITION(areal))
{
- collection.check_remaining_points(distance_strategy.factor());
+ collection.check_remaining_points(distance_strategy);
}
// Visit the piece collection. This does nothing (by default), but
@@ -889,7 +900,8 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator
// - the output is counter clockwise
// and avoid reversing twice
bool reverse = distance_strategy.negative() && areal;
- if (geometry::point_order<GeometryOutput>::value == counterclockwise)
+ if (BOOST_GEOMETRY_CONDITION(
+ geometry::point_order<GeometryOutput>::value == counterclockwise))
{
reverse = ! reverse;
}
@@ -898,6 +910,11 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator
collection.reverse();
}
+ if (distance_strategy.negative() && areal)
+ {
+ collection.discard_nonintersecting_deflated_rings();
+ }
+
collection.template assign<GeometryOutput>(out);
// Visit collection again
diff --git a/boost/geometry/algorithms/detail/buffer/buffer_policies.hpp b/boost/geometry/algorithms/detail/buffer/buffer_policies.hpp
index 6a2e6b3..c5bb8ac 100644
--- a/boost/geometry/algorithms/detail/buffer/buffer_policies.hpp
+++ b/boost/geometry/algorithms/detail/buffer/buffer_policies.hpp
@@ -35,7 +35,7 @@ namespace detail { namespace buffer
enum intersection_location_type
{
- location_ok, inside_buffer, inside_original
+ location_ok, inside_buffer, location_discard
};
class backtrack_for_buffer
@@ -120,10 +120,14 @@ struct buffer_turn_info
return robust_point;
}
-
intersection_location_type location;
int count_within;
+
+ bool within_original;
+ int count_on_original_boundary;
+ int count_in_original; // increased by +1 for in ext.ring, -1 for int.ring
+
int count_on_offsetted;
int count_on_helper;
int count_within_near_offsetted;
@@ -138,6 +142,9 @@ struct buffer_turn_info
: turn_index(-1)
, location(location_ok)
, count_within(0)
+ , within_original(false)
+ , count_on_original_boundary(0)
+ , count_in_original(0)
, count_on_offsetted(0)
, count_on_helper(0)
, count_within_near_offsetted(0)
diff --git a/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp b/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp
index 558a61f..a501e3f 100644
--- a/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp
+++ b/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp
@@ -12,8 +12,9 @@
#include <algorithm>
#include <cstddef>
#include <set>
-#include <boost/range.hpp>
+#include <boost/core/ignore_unused.hpp>
+#include <boost/range.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/point_type.hpp>
@@ -24,13 +25,14 @@
#include <boost/geometry/strategies/buffer.hpp>
#include <boost/geometry/geometries/ring.hpp>
-#include <boost/geometry/geometries/polygon.hpp>
#include <boost/geometry/algorithms/detail/buffer/buffered_ring.hpp>
#include <boost/geometry/algorithms/detail/buffer/buffer_policies.hpp>
#include <boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp>
#include <boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp>
+#include <boost/geometry/algorithms/detail/buffer/turn_in_original_visitor.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/point_box.hpp>
#include <boost/geometry/algorithms/detail/overlay/add_rings.hpp>
#include <boost/geometry/algorithms/detail/overlay/assign_parents.hpp>
#include <boost/geometry/algorithms/detail/overlay/enrichment_info.hpp>
@@ -41,6 +43,8 @@
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
#include <boost/geometry/algorithms/detail/occupation_info.hpp>
#include <boost/geometry/algorithms/detail/partition.hpp>
+#include <boost/geometry/algorithms/detail/sections/sectionalize.hpp>
+#include <boost/geometry/algorithms/detail/sections/section_box_policies.hpp>
#include <boost/geometry/util/range.hpp>
@@ -89,7 +93,7 @@ enum segment_relation_code
* form together the offsetted ring (marked with o below)
* The 8 pieces are part of the piece collection and use for inside-checks
* The inner parts form (using 1 or 2 points per piece, often co-located)
- * form together the robust_ring (marked with r below)
+ * form together the robust_polygons (marked with r below)
* The remaining piece-segments are helper-segments (marked with h)
*
* ooooooooooooooooo
@@ -120,7 +124,7 @@ struct buffered_piece_collection
// Robust ring/polygon type, always clockwise
typedef geometry::model::ring<robust_point_type> robust_ring_type;
- typedef geometry::model::polygon<robust_point_type> robust_polygon_type;
+ typedef geometry::model::box<robust_point_type> robust_box_type;
typedef typename strategy::side::services::default_strategy
<
@@ -164,6 +168,9 @@ struct buffered_piece_collection
struct piece
{
+ typedef robust_ring_type piece_robust_ring_type;
+ typedef geometry::section<robust_box_type, 1> section_type;
+
strategy::buffer::piece_type type;
int index;
@@ -181,18 +188,58 @@ struct buffered_piece_collection
#if defined(BOOST_GEOMETRY_BUFFER_USE_HELPER_POINTS)
// 2: half, not part of offsetted rings - part of robust ring
- std::vector<point_type> helper_points; // 4 points for segment, 3 points for join - 0 points for flat-end
+ std::vector<point_type> helper_points; // 4 points for side, 3 points for join - 0 points for flat-end
#endif
+ bool is_monotonic_increasing[2]; // 0=x, 1=y
+ bool is_monotonic_decreasing[2]; // 0=x, 1=y
+
+ // Monotonic sections of pieces around points
+ std::vector<section_type> sections;
+
+
// Robust representations
// 3: complete ring
robust_ring_type robust_ring;
- geometry::model::box<robust_point_type> robust_envelope;
+ robust_box_type robust_envelope;
+ robust_box_type robust_offsetted_envelope;
std::vector<robust_turn> robust_turns; // Used only in insert_rescaled_piece_turns - we might use a map instead
};
+ struct robust_original
+ {
+ typedef robust_ring_type original_robust_ring_type;
+ typedef geometry::sections<robust_box_type, 1> sections_type;
+
+ inline robust_original()
+ : m_is_interior(false)
+ , m_has_interiors(true)
+ {}
+
+ inline robust_original(robust_ring_type const& ring,
+ bool is_interior, bool has_interiors)
+ : m_ring(ring)
+ , m_is_interior(is_interior)
+ , m_has_interiors(has_interiors)
+ {
+ geometry::envelope(m_ring, m_box);
+
+ // create monotonic sections in y-dimension
+ typedef boost::mpl::vector_c<std::size_t, 1> dimensions;
+ geometry::sectionalize<false, dimensions>(m_ring,
+ detail::no_rescale_policy(), m_sections);
+ }
+
+ robust_ring_type m_ring;
+ robust_box_type m_box;
+ sections_type m_sections;
+
+ bool m_is_interior;
+ bool m_has_interiors;
+ };
+
typedef std::vector<piece> piece_vector_type;
piece_vector_type m_pieces;
@@ -200,11 +247,17 @@ struct buffered_piece_collection
int m_first_piece_index;
buffered_ring_collection<buffered_ring<Ring> > offsetted_rings; // indexed by multi_index
- buffered_ring_collection<robust_polygon_type> robust_polygons; // robust representation of the original(s)
+ std::vector<robust_original> robust_originals; // robust representation of the original(s)
robust_ring_type current_robust_ring;
buffered_ring_collection<Ring> traversed_rings;
segment_identifier current_segment_id;
+ // Specificly for offsetted rings around points
+ // but also for large joins with many points
+ typedef geometry::sections<robust_box_type, 2> sections_type;
+ sections_type monotonic_sections;
+
+
RobustPolicy const& m_robust_policy;
struct redundant_turn
@@ -378,7 +431,7 @@ struct buffered_piece_collection
}
}
- inline void classify_turns()
+ inline void classify_turns(bool linear)
{
for (typename boost::range_iterator<turn_vector_type>::type it =
boost::begin(m_turns); it != boost::end(m_turns); ++it)
@@ -387,6 +440,10 @@ struct buffered_piece_collection
{
it->location = inside_buffer;
}
+ if (it->count_on_original_boundary > 0 && ! linear)
+ {
+ it->location = inside_buffer;
+ }
if (it->count_within_near_offsetted > 0)
{
// Within can have in rare cases a rounding issue. We don't discard this
@@ -394,31 +451,40 @@ struct buffered_piece_collection
// will never start a new ring from this type of points.
it->selectable_start = false;
}
-
}
}
- inline void check_remaining_points(int factor)
+ template <typename DistanceStrategy>
+ inline void check_remaining_points(DistanceStrategy const& distance_strategy)
{
- // TODO: use partition
+ // Check if a turn is inside any of the originals
+
+ turn_in_original_visitor<turn_vector_type> visitor(m_turns);
+ geometry::partition
+ <
+ robust_box_type,
+ turn_get_box, turn_in_original_ovelaps_box,
+ original_get_box, original_ovelaps_box,
+ include_turn_policy, detail::partition::include_all_policy
+ >::apply(m_turns, robust_originals, visitor);
+
+ bool const deflate = distance_strategy.negative();
for (typename boost::range_iterator<turn_vector_type>::type it =
boost::begin(m_turns); it != boost::end(m_turns); ++it)
{
- if (it->location == location_ok)
+ buffer_turn_info_type& turn = *it;
+ if (turn.location == location_ok)
{
- int code = -1;
- for (std::size_t i = 0; i < robust_polygons.size(); i++)
+ if (deflate && turn.count_in_original <= 0)
{
- if (geometry::covered_by(it->robust_point, robust_polygons[i]))
- {
- code = 1;
- break;
- }
+ // For deflate: it is not in original, discard
+ turn.location = location_discard;
}
- if (code * factor == 1)
+ else if (! deflate && turn.count_in_original > 0)
{
- it->location = inside_original;
+ // For inflate: it is in original, discard
+ turn.location = location_discard;
}
}
}
@@ -474,6 +540,7 @@ struct buffered_piece_collection
// Take into account for the box (intersection points should fall inside,
// but in theory they can be one off because of rounding
geometry::expand(pc.robust_envelope, it->robust_point);
+ geometry::expand(pc.robust_offsetted_envelope, it->robust_point);
}
}
@@ -502,9 +569,10 @@ struct buffered_piece_collection
{
int const index_in_vector = 1 + rit->seg_id.segment_index - piece_segment_index;
BOOST_ASSERT
- (
- index_in_vector > 0 && index_in_vector < pc.offsetted_count
- );
+ (
+ index_in_vector > 0
+ && index_in_vector < pc.offsetted_count
+ );
pc.robust_ring.insert(boost::begin(pc.robust_ring) + index_in_vector, rit->point);
pc.offsetted_count++;
@@ -517,25 +585,132 @@ struct buffered_piece_collection
BOOST_ASSERT(assert_indices_in_robust_rings());
}
+ template <std::size_t Dimension>
+ static inline void determine_monotonicity(piece& pc,
+ robust_point_type const& current,
+ robust_point_type const& next)
+ {
+ if (geometry::get<Dimension>(current) >= geometry::get<Dimension>(next))
+ {
+ pc.is_monotonic_increasing[Dimension] = false;
+ }
+ if (geometry::get<Dimension>(current) <= geometry::get<Dimension>(next))
+ {
+ pc.is_monotonic_decreasing[Dimension] = false;
+ }
+ }
+
+ static inline void determine_properties(piece& pc)
+ {
+ pc.is_monotonic_increasing[0] = true;
+ pc.is_monotonic_increasing[1] = true;
+ pc.is_monotonic_decreasing[0] = true;
+ pc.is_monotonic_decreasing[1] = true;
+
+ if (pc.offsetted_count < 2)
+ {
+ return;
+ }
+
+ typename robust_ring_type::const_iterator current = pc.robust_ring.begin();
+ typename robust_ring_type::const_iterator next = current + 1;
+
+ for (int i = 1; i < pc.offsetted_count; i++)
+ {
+ determine_monotonicity<0>(pc, *current, *next);
+ determine_monotonicity<1>(pc, *current, *next);
+ current = next;
+ ++next;
+ }
+
+ }
+
+ void determine_properties()
+ {
+ for (typename piece_vector_type::iterator it = boost::begin(m_pieces);
+ it != boost::end(m_pieces);
+ ++it)
+ {
+ determine_properties(*it);
+ }
+ }
+
+ inline void reverse_negative_robust_rings()
+ {
+ for (typename piece_vector_type::iterator it = boost::begin(m_pieces);
+ it != boost::end(m_pieces);
+ ++it)
+ {
+ piece& pc = *it;
+ if (geometry::area(pc.robust_ring) < 0)
+ {
+ // Rings can be ccw:
+ // - in a concave piece
+ // - in a line-buffer with a negative buffer-distance
+ std::reverse(pc.robust_ring.begin(), pc.robust_ring.end());
+ }
+ }
+ }
+
+ inline void prepare_buffered_point_piece(piece& pc)
+ {
+ // create monotonic sections in y-dimension
+ typedef boost::mpl::vector_c<std::size_t, 1> dimensions;
+ geometry::sectionalize<false, dimensions>(pc.robust_ring,
+ detail::no_rescale_policy(), pc.sections);
+
+ // TODO (next phase) determine min/max radius
+ }
+
+ inline void prepare_buffered_point_pieces()
+ {
+ for (typename piece_vector_type::iterator it = boost::begin(m_pieces);
+ it != boost::end(m_pieces);
+ ++it)
+ {
+ if (it->type == geometry::strategy::buffer::buffered_point)
+ {
+ prepare_buffered_point_piece(*it);
+ }
+ }
+ }
+
inline void get_turns()
{
+ for(typename boost::range_iterator<sections_type>::type it
+ = boost::begin(monotonic_sections);
+ it != boost::end(monotonic_sections);
+ ++it)
+ {
+ enlarge_box(it->bounding_box, 1);
+ }
+
{
// Calculate the turns
piece_turn_visitor
<
+ piece_vector_type,
buffered_ring_collection<buffered_ring<Ring> >,
turn_vector_type,
RobustPolicy
- > visitor(offsetted_rings, m_turns, m_robust_policy);
+ > visitor(m_pieces, offsetted_rings, m_turns, m_robust_policy);
geometry::partition
<
- model::box<robust_point_type>, piece_get_box, piece_ovelaps_box
- >::apply(m_pieces, visitor);
+ robust_box_type,
+ detail::section::get_section_box,
+ detail::section::overlaps_section_box
+ >::apply(monotonic_sections, visitor);
}
insert_rescaled_piece_turns();
+ reverse_negative_robust_rings();
+
+ determine_properties();
+
+ prepare_buffered_point_pieces();
+
{
// Check if it is inside any of the pieces
turn_in_piece_visitor
@@ -545,16 +720,12 @@ struct buffered_piece_collection
geometry::partition
<
- model::box<robust_point_type>,
+ robust_box_type,
turn_get_box, turn_ovelaps_box,
piece_get_box, piece_ovelaps_box
>::apply(m_turns, m_pieces, visitor);
}
-
- classify_turns();
-
- //get_occupation();
}
inline void start_new_ring()
@@ -571,7 +742,38 @@ struct buffered_piece_collection
m_first_piece_index = boost::size(m_pieces);
}
- inline void finish_ring(bool is_interior = false)
+ inline void update_closing_point()
+ {
+ BOOST_ASSERT(! offsetted_rings.empty());
+ buffered_ring<Ring>& added = offsetted_rings.back();
+ if (! boost::empty(added))
+ {
+ range::back(added) = range::front(added);
+ }
+ }
+
+ inline void update_last_point(point_type const& p,
+ buffered_ring<Ring>& ring)
+ {
+ // For the first point of a new piece, and there were already
+ // points in the offsetted ring, for some piece types the first point
+ // is a duplicate of the last point of the previous piece.
+
+ // TODO: disable that, that point should not be added
+
+ // For now, it is made equal because due to numerical instability,
+ // it can be a tiny bit off, possibly causing a self-intersection
+
+ BOOST_ASSERT(boost::size(m_pieces) > 0);
+ if (! ring.empty()
+ && current_segment_id.segment_index
+ == m_pieces.back().first_seg_id.segment_index)
+ {
+ ring.back() = p;
+ }
+ }
+
+ inline void finish_ring(bool is_interior = false, bool has_interiors = false)
{
if (m_first_piece_index == -1)
{
@@ -588,41 +790,50 @@ struct buffered_piece_collection
}
m_first_piece_index = -1;
- if (!current_robust_ring.empty())
+ update_closing_point();
+
+ if (! current_robust_ring.empty())
{
- BOOST_ASSERT(geometry::equals(current_robust_ring.front(), current_robust_ring.back()));
+ BOOST_ASSERT
+ (
+ geometry::equals(current_robust_ring.front(),
+ current_robust_ring.back())
+ );
- if (is_interior)
- {
- if (!robust_polygons.empty())
- {
- robust_polygons.back().inners().push_back(current_robust_ring);
- }
- }
- else
- {
- robust_polygons.resize(robust_polygons.size() + 1);
- robust_polygons.back().outer() = current_robust_ring;
- }
+ robust_originals.push_back(
+ robust_original(current_robust_ring,
+ is_interior, has_interiors));
}
}
+ inline void set_current_ring_concave()
+ {
+ BOOST_ASSERT(boost::size(offsetted_rings) > 0);
+ offsetted_rings.back().has_concave = true;
+ }
+
inline int add_point(point_type const& p)
{
- BOOST_ASSERT
- (
- boost::size(offsetted_rings) > 0
- );
+ BOOST_ASSERT(boost::size(offsetted_rings) > 0);
+
+ buffered_ring<Ring>& current_ring = offsetted_rings.back();
+ update_last_point(p, current_ring);
current_segment_id.segment_index++;
- offsetted_rings.back().push_back(p);
- return offsetted_rings.back().size();
+ current_ring.push_back(p);
+ return current_ring.size();
}
//-------------------------------------------------------------------------
- inline piece& create_piece(strategy::buffer::piece_type type, bool decrease_segment_index_by_one)
+ inline piece& create_piece(strategy::buffer::piece_type type,
+ bool decrease_segment_index_by_one)
{
+ if (type == strategy::buffer::buffered_concave)
+ {
+ offsetted_rings.back().has_concave = true;
+ }
+
piece pc;
pc.type = type;
pc.index = boost::size(m_pieces);
@@ -634,6 +845,7 @@ struct buffered_piece_collection
std::size_t const n = boost::size(offsetted_rings.back());
pc.first_seg_id.segment_index = decrease_segment_index_by_one ? n - 1 : n;
+ pc.last_segment_index = pc.first_seg_id.segment_index;
m_pieces.push_back(pc);
return m_pieces.back();
@@ -641,6 +853,18 @@ struct buffered_piece_collection
inline void init_rescale_piece(piece& pc, std::size_t helper_points_size)
{
+ if (pc.first_seg_id.segment_index < 0)
+ {
+ // This indicates an error situation: an earlier piece was empty
+ // It currently does not happen
+ // std::cout << "EMPTY " << pc.type << " " << pc.index << " " << pc.first_seg_id.multi_index << std::endl;
+ pc.offsetted_count = 0;
+ return;
+ }
+
+ BOOST_ASSERT(pc.first_seg_id.multi_index >= 0);
+ BOOST_ASSERT(pc.last_segment_index >= 0);
+
pc.offsetted_count = pc.last_segment_index - pc.first_seg_id.segment_index;
BOOST_ASSERT(pc.offsetted_count >= 0);
@@ -674,16 +898,65 @@ struct buffered_piece_collection
return rob_point;
}
+ // TODO: this is shared with sectionalize, move to somewhere else (assign?)
+ template <typename Box, typename Value>
+ inline void enlarge_box(Box& box, Value value)
+ {
+ geometry::set<0, 0>(box, geometry::get<0, 0>(box) - value);
+ geometry::set<0, 1>(box, geometry::get<0, 1>(box) - value);
+ geometry::set<1, 0>(box, geometry::get<1, 0>(box) + value);
+ geometry::set<1, 1>(box, geometry::get<1, 1>(box) + value);
+ }
+
inline void calculate_robust_envelope(piece& pc)
{
+ if (pc.offsetted_count == 0)
+ {
+ return;
+ }
+
geometry::detail::envelope::envelope_range::apply(pc.robust_ring,
pc.robust_envelope);
+
+ geometry::assign_inverse(pc.robust_offsetted_envelope);
+ for (int i = 0; i < pc.offsetted_count; i++)
+ {
+ geometry::expand(pc.robust_offsetted_envelope, pc.robust_ring[i]);
+ }
+
+ // Take roundings into account, enlarge boxes with 1 integer
+ enlarge_box(pc.robust_envelope, 1);
+ enlarge_box(pc.robust_offsetted_envelope, 1);
+ }
+
+ inline void sectionalize(piece& pc)
+ {
+
+ buffered_ring<Ring> const& ring = offsetted_rings.back();
+
+ typedef geometry::detail::sectionalize::sectionalize_part
+ <
+ point_type,
+ boost::mpl::vector_c<std::size_t, 0, 1> // x,y dimension
+ > sectionalizer;
+
+ // Create a ring-identifier. The source-index is the piece index
+ // The multi_index is as in this collection (the ring), but not used here
+ // The ring_index is not used
+ ring_identifier ring_id(pc.index, pc.first_seg_id.multi_index, -1);
+
+ sectionalizer::apply(monotonic_sections,
+ boost::begin(ring) + pc.first_seg_id.segment_index,
+ boost::begin(ring) + pc.last_segment_index,
+ m_robust_policy,
+ ring_id, 10);
}
inline void finish_piece(piece& pc)
{
init_rescale_piece(pc, 0u);
calculate_robust_envelope(pc);
+ sectionalize(pc);
}
inline void finish_piece(piece& pc,
@@ -692,10 +965,16 @@ struct buffered_piece_collection
const point_type& point3)
{
init_rescale_piece(pc, 3u);
+ if (pc.offsetted_count == 0)
+ {
+ return;
+ }
+
add_helper_point(pc, point1);
robust_point_type mid_point = add_helper_point(pc, point2);
add_helper_point(pc, point3);
calculate_robust_envelope(pc);
+ sectionalize(pc);
current_robust_ring.push_back(mid_point);
}
@@ -711,6 +990,7 @@ struct buffered_piece_collection
robust_point_type mid_point2 = add_helper_point(pc, point2);
robust_point_type mid_point1 = add_helper_point(pc, point3);
add_helper_point(pc, point4);
+ sectionalize(pc);
calculate_robust_envelope(pc);
// Add mid-points in other order to current helper_ring
@@ -730,10 +1010,7 @@ struct buffered_piece_collection
template <typename Range>
inline void add_range_to_piece(piece& pc, Range const& range, bool add_front)
{
- if (boost::size(range) == 0u)
- {
- return;
- }
+ BOOST_ASSERT(boost::size(range) != 0u);
typename Range::const_iterator it = boost::begin(range);
@@ -753,10 +1030,15 @@ struct buffered_piece_collection
template <typename Range>
- inline void add_piece(strategy::buffer::piece_type type, Range const& range, bool decrease_segment_index_by_one)
+ inline void add_piece(strategy::buffer::piece_type type, Range const& range,
+ bool decrease_segment_index_by_one)
{
piece& pc = create_piece(type, decrease_segment_index_by_one);
- add_range_to_piece(pc, range, offsetted_rings.back().empty());
+
+ if (boost::size(range) > 0u)
+ {
+ add_range_to_piece(pc, range, offsetted_rings.back().empty());
+ }
finish_piece(pc);
}
@@ -772,13 +1054,14 @@ struct buffered_piece_collection
}
template <typename Range>
- inline void add_piece(strategy::buffer::piece_type type, point_type const& p, Range const& range)
+ inline void add_piece(strategy::buffer::piece_type type,
+ point_type const& p, Range const& range)
{
piece& pc = create_piece(type, true);
- add_range_to_piece(pc, range, offsetted_rings.back().empty());
- if (boost::size(range) > 0)
+ if (boost::size(range) > 0u)
{
+ add_range_to_piece(pc, range, offsetted_rings.back().empty());
finish_piece(pc, range.back(), p, range.front());
}
else
@@ -788,8 +1071,11 @@ struct buffered_piece_collection
}
template <typename EndcapStrategy, typename Range>
- inline void add_endcap(EndcapStrategy const& strategy, Range const& range, point_type const& end_point)
+ inline void add_endcap(EndcapStrategy const& strategy, Range const& range,
+ point_type const& end_point)
{
+ boost::ignore_unused(strategy);
+
if (range.empty())
{
return;
@@ -842,6 +1128,80 @@ struct buffered_piece_collection
}
}
+ inline bool point_coveredby_original(point_type const& point)
+ {
+ robust_point_type any_point;
+ geometry::recalculate(any_point, point, m_robust_policy);
+
+ int count_in_original = 0;
+
+ // Check of the robust point of this outputted ring is in
+ // any of the robust original rings
+ // This can go quadratic if the input has many rings, and there
+ // are many untouched deflated rings around
+ for (typename std::vector<robust_original>::const_iterator it
+ = robust_originals.begin();
+ it != robust_originals.end();
+ ++it)
+ {
+ robust_original const& original = *it;
+ if (detail::disjoint::disjoint_point_box(any_point,
+ original.m_box))
+ {
+ continue;
+ }
+
+ int const geometry_code
+ = detail::within::point_in_geometry(any_point,
+ original.m_ring);
+
+ if (geometry_code == -1)
+ {
+ // Outside, continue
+ continue;
+ }
+
+ // Apply for possibly nested interior rings
+ if (original.m_is_interior)
+ {
+ count_in_original--;
+ }
+ else if (original.m_has_interiors)
+ {
+ count_in_original++;
+ }
+ else
+ {
+ // Exterior ring without interior rings
+ return true;
+ }
+ }
+ return count_in_original > 0;
+ }
+
+ // For a deflate, all rings around inner rings which are untouched
+ // (no intersections/turns) and which are OUTSIDE the original should
+ // be discarded
+ inline void discard_nonintersecting_deflated_rings()
+ {
+ for(typename buffered_ring_collection<buffered_ring<Ring> >::iterator it
+ = boost::begin(offsetted_rings);
+ it != boost::end(offsetted_rings);
+ ++it)
+ {
+ buffered_ring<Ring>& ring = *it;
+ if (! ring.has_intersections()
+ && boost::size(ring) > 0u
+ && geometry::area(ring) < 0)
+ {
+ if (! point_coveredby_original(geometry::range::front(ring)))
+ {
+ ring.is_untouched_outside_original = true;
+ }
+ }
+ }
+ }
+
inline void block_turns()
{
// To fix left-turn issues like #rt_u13
@@ -876,7 +1236,8 @@ struct buffered_piece_collection
typedef detail::overlay::traverse
<
false, false,
- buffered_ring_collection<buffered_ring<Ring> >, buffered_ring_collection<buffered_ring<Ring > >,
+ buffered_ring_collection<buffered_ring<Ring> >,
+ buffered_ring_collection<buffered_ring<Ring > >,
backtrack_for_buffer
> traverser;
@@ -914,16 +1275,20 @@ struct buffered_piece_collection
std::map<ring_identifier, properties> selected;
- // Select all rings which do not have any self-intersection (other ones should be traversed)
+ // Select all rings which do not have any self-intersection
+ // Inner rings, for deflate, which do not have intersections, and
+ // which are outside originals, are skipped
+ // (other ones should be traversed)
int index = 0;
for(typename buffered_ring_collection<buffered_ring<Ring> >::const_iterator it = boost::begin(offsetted_rings);
it != boost::end(offsetted_rings);
++it, ++index)
{
- if (! it->has_intersections())
+ if (! it->has_intersections()
+ && ! it->is_untouched_outside_original)
{
ring_identifier id(0, index, -1);
- selected[id] = properties(*it, true);
+ selected[id] = properties(*it);
}
}
@@ -935,7 +1300,7 @@ struct buffered_piece_collection
++it, ++index)
{
ring_identifier id(2, index, -1);
- selected[id] = properties(*it, true);
+ selected[id] = properties(*it);
}
detail::overlay::assign_parents(offsetted_rings, traversed_rings, selected, true);
diff --git a/boost/geometry/algorithms/detail/buffer/buffered_ring.hpp b/boost/geometry/algorithms/detail/buffer/buffered_ring.hpp
index 03ec598..9ea8bc1 100644
--- a/boost/geometry/algorithms/detail/buffer/buffered_ring.hpp
+++ b/boost/geometry/algorithms/detail/buffer/buffered_ring.hpp
@@ -43,12 +43,16 @@ struct buffered_ring_collection_tag : polygonal_tag, multi_tag
template <typename Ring>
struct buffered_ring : public Ring
{
+ bool has_concave;
bool has_accepted_intersections;
bool has_discarded_intersections;
+ bool is_untouched_outside_original;
inline buffered_ring()
- : has_accepted_intersections(false)
+ : has_concave(false)
+ , has_accepted_intersections(false)
, has_discarded_intersections(false)
+ , is_untouched_outside_original(false)
{}
inline bool discarded() const
diff --git a/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp b/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp
index 395921c..6a3daa2 100644
--- a/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp
+++ b/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp
@@ -16,6 +16,7 @@
#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
#include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
+#include <boost/geometry/algorithms/detail/sections/section_functions.hpp>
namespace boost { namespace geometry
@@ -27,32 +28,16 @@ namespace detail { namespace buffer
{
-struct piece_get_box
-{
- template <typename Box, typename Piece>
- static inline void apply(Box& total, Piece const& piece)
- {
- geometry::expand(total, piece.robust_envelope);
- }
-};
-
-struct piece_ovelaps_box
-{
- template <typename Box, typename Piece>
- static inline bool apply(Box const& box, Piece const& piece)
- {
- return ! geometry::detail::disjoint::disjoint_box_box(box, piece.robust_envelope);
- }
-};
-
template
<
+ typename Pieces,
typename Rings,
typename Turns,
typename RobustPolicy
>
class piece_turn_visitor
{
+ Pieces const& m_pieces;
Rings const& m_rings;
Turns& m_turns;
RobustPolicy const& m_robust_policy;
@@ -69,6 +54,17 @@ class piece_turn_visitor
|| piece1.index == piece2.right_index;
}
+ template <typename Piece>
+ inline bool is_on_same_convex_ring(Piece const& piece1, Piece const& piece2) const
+ {
+ if (piece1.first_seg_id.multi_index != piece2.first_seg_id.multi_index)
+ {
+ return false;
+ }
+
+ return ! m_rings[piece1.first_seg_id.multi_index].has_concave;
+ }
+
template <typename Range, typename Iterator>
inline void move_to_next_point(Range const& range, Iterator& next) const
{
@@ -93,46 +89,110 @@ class piece_turn_visitor
return result;
}
- template <typename Piece>
- inline void calculate_turns(Piece const& piece1, Piece const& piece2)
+ template <std::size_t Dimension, typename Iterator, typename Box>
+ inline void move_begin_iterator(Iterator& it_begin, Iterator it_beyond,
+ int& index, int dir, Box const& other_bounding_box)
+ {
+ for(; it_begin != it_beyond
+ && it_begin + 1 != it_beyond
+ && detail::section::preceding<Dimension>(dir, *(it_begin + 1),
+ other_bounding_box, m_robust_policy);
+ ++it_begin, index++)
+ {}
+ }
+
+ template <std::size_t Dimension, typename Iterator, typename Box>
+ inline void move_end_iterator(Iterator it_begin, Iterator& it_beyond,
+ int dir, Box const& other_bounding_box)
+ {
+ while (it_beyond != it_begin
+ && it_beyond - 1 != it_begin
+ && it_beyond - 2 != it_begin)
+ {
+ if (detail::section::exceeding<Dimension>(dir, *(it_beyond - 2),
+ other_bounding_box, m_robust_policy))
+ {
+ --it_beyond;
+ }
+ else
+ {
+ return;
+ }
+ }
+ }
+
+ template <typename Piece, typename Section>
+ inline void calculate_turns(Piece const& piece1, Piece const& piece2,
+ Section const& section1, Section const& section2)
{
typedef typename boost::range_value<Rings const>::type ring_type;
typedef typename boost::range_value<Turns const>::type turn_type;
typedef typename boost::range_iterator<ring_type const>::type iterator;
- segment_identifier seg_id1 = piece1.first_seg_id;
- segment_identifier seg_id2 = piece2.first_seg_id;
-
- if (seg_id1.segment_index < 0 || seg_id2.segment_index < 0)
+ int const piece1_first_index = piece1.first_seg_id.segment_index;
+ int const piece2_first_index = piece2.first_seg_id.segment_index;
+ if (piece1_first_index < 0 || piece2_first_index < 0)
{
return;
}
- ring_type const& ring1 = m_rings[seg_id1.multi_index];
- iterator it1_first = boost::begin(ring1) + seg_id1.segment_index;
- iterator it1_last = boost::begin(ring1) + piece1.last_segment_index;
-
- ring_type const& ring2 = m_rings[seg_id2.multi_index];
- iterator it2_first = boost::begin(ring2) + seg_id2.segment_index;
- iterator it2_last = boost::begin(ring2) + piece2.last_segment_index;
+ // Get indices of part of offsetted_rings for this monotonic section:
+ int const sec1_first_index = piece1_first_index + section1.begin_index;
+ int const sec2_first_index = piece2_first_index + section2.begin_index;
+
+ // index of last point in section, beyond-end is one further
+ int const sec1_last_index = piece1_first_index + section1.end_index;
+ int const sec2_last_index = piece2_first_index + section2.end_index;
+
+ // get geometry and iterators over these sections
+ ring_type const& ring1 = m_rings[piece1.first_seg_id.multi_index];
+ iterator it1_first = boost::begin(ring1) + sec1_first_index;
+ iterator it1_beyond = boost::begin(ring1) + sec1_last_index + 1;
+
+ ring_type const& ring2 = m_rings[piece2.first_seg_id.multi_index];
+ iterator it2_first = boost::begin(ring2) + sec2_first_index;
+ iterator it2_beyond = boost::begin(ring2) + sec2_last_index + 1;
+
+ // Set begin/end of monotonic ranges, in both x/y directions
+ int index1 = sec1_first_index;
+ move_begin_iterator<0>(it1_first, it1_beyond, index1,
+ section1.directions[0], section2.bounding_box);
+ move_end_iterator<0>(it1_first, it1_beyond,
+ section1.directions[0], section2.bounding_box);
+ move_begin_iterator<1>(it1_first, it1_beyond, index1,
+ section1.directions[1], section2.bounding_box);
+ move_end_iterator<1>(it1_first, it1_beyond,
+ section1.directions[1], section2.bounding_box);
+
+ int index2 = sec2_first_index;
+ move_begin_iterator<0>(it2_first, it2_beyond, index2,
+ section2.directions[0], section1.bounding_box);
+ move_end_iterator<0>(it2_first, it2_beyond,
+ section2.directions[0], section1.bounding_box);
+ move_begin_iterator<1>(it2_first, it2_beyond, index2,
+ section2.directions[1], section1.bounding_box);
+ move_end_iterator<1>(it2_first, it2_beyond,
+ section2.directions[1], section1.bounding_box);
turn_type the_model;
the_model.operations[0].piece_index = piece1.index;
the_model.operations[0].seg_id = piece1.first_seg_id;
+ the_model.operations[0].seg_id.segment_index = index1; // override
iterator it1 = it1_first;
for (iterator prev1 = it1++;
- it1 != it1_last;
+ it1 != it1_beyond;
prev1 = it1++, the_model.operations[0].seg_id.segment_index++)
{
the_model.operations[1].piece_index = piece2.index;
the_model.operations[1].seg_id = piece2.first_seg_id;
+ the_model.operations[1].seg_id.segment_index = index2; // override
iterator next1 = next_point(ring1, it1);
iterator it2 = it2_first;
for (iterator prev2 = it2++;
- it2 != it2_last;
+ it2 != it2_beyond;
prev2 = it2++, the_model.operations[1].seg_id.segment_index++)
{
iterator next2 = next_point(ring2, it2);
@@ -158,26 +218,36 @@ class piece_turn_visitor
public:
- piece_turn_visitor(Rings const& ring_collection,
+ piece_turn_visitor(Pieces const& pieces,
+ Rings const& ring_collection,
Turns& turns,
RobustPolicy const& robust_policy)
- : m_rings(ring_collection)
+ : m_pieces(pieces)
+ , m_rings(ring_collection)
, m_turns(turns)
, m_robust_policy(robust_policy)
{}
- template <typename Piece>
- inline void apply(Piece const& piece1, Piece const& piece2,
+ template <typename Section>
+ inline void apply(Section const& section1, Section const& section2,
bool first = true)
{
boost::ignore_unused_variable_warning(first);
- if ( is_adjacent(piece1, piece2)
- || detail::disjoint::disjoint_box_box(piece1.robust_envelope,
- piece2.robust_envelope))
+
+ typedef typename boost::range_value<Pieces const>::type piece_type;
+ piece_type const& piece1 = m_pieces[section1.ring_id.source_index];
+ piece_type const& piece2 = m_pieces[section2.ring_id.source_index];
+
+ if ( piece1.index == piece2.index
+ || is_adjacent(piece1, piece2)
+ || is_on_same_convex_ring(piece1, piece2)
+ || detail::disjoint::disjoint_box_box(section1.bounding_box,
+ section2.bounding_box) )
{
return;
}
- calculate_turns(piece1, piece2);
+
+ calculate_turns(piece1, piece2, section1, section2);
}
};
diff --git a/boost/geometry/algorithms/detail/buffer/turn_in_input.hpp b/boost/geometry/algorithms/detail/buffer/turn_in_input.hpp
deleted file mode 100644
index 2b1c33d..0000000
--- a/boost/geometry/algorithms/detail/buffer/turn_in_input.hpp
+++ /dev/null
@@ -1,98 +0,0 @@
-// Boost.Geometry (aka GGL, Generic Geometry Library)
-
-// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
-
-// Use, modification and distribution is subject to the Boost Software License,
-// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
-// http://www.boost.org/LICENSE_1_0.txt)
-
-#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_INPUT_HPP
-#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_INPUT_HPP
-
-#include <boost/geometry/core/tags.hpp>
-#include <boost/geometry/algorithms/covered_by.hpp>
-
-
-namespace boost { namespace geometry
-{
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace buffer
-{
-
-// Checks if an turn/intersection point is inside (or covered by) the input geometry
-
-template <typename Tag>
-struct turn_in_input
-{
-};
-
-template <>
-struct turn_in_input<polygon_tag>
-{
- template <typename Point, typename Geometry>
- static inline int apply(Point const& point, Geometry const& geometry)
- {
- return geometry::covered_by(point, geometry) ? 1 : -1;
- }
-};
-
-template <>
-struct turn_in_input<linestring_tag>
-{
- template <typename Point, typename Geometry>
- static inline int apply(Point const& , Geometry const& )
- {
- return 0;
- }
-};
-
-template <>
-struct turn_in_input<point_tag>
-{
- template <typename Point, typename Geometry>
- static inline int apply(Point const& , Geometry const& )
- {
- return 0;
- }
-};
-
-template <>
-struct turn_in_input<multi_polygon_tag>
-{
- template <typename Point, typename Geometry>
- static inline int apply(Point const& point, Geometry const& geometry)
- {
- return geometry::covered_by(point, geometry) ? 1 : -1;
- }
-};
-
-template <>
-struct turn_in_input<multi_linestring_tag>
-{
- template <typename Point, typename Geometry>
- static inline int apply(Point const& , Geometry const& )
- {
- return 0;
- }
-};
-
-template <>
-struct turn_in_input<multi_point_tag>
-{
- template <typename Point, typename Geometry>
- static inline int apply(Point const& , Geometry const& )
- {
- return 0;
- }
-};
-
-
-}} // namespace detail::buffer
-#endif // DOXYGEN_NO_DETAIL
-
-
-
-}} // namespace boost::geometry
-
-#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_INPUT_HPP
diff --git a/boost/geometry/algorithms/detail/buffer/turn_in_original_visitor.hpp b/boost/geometry/algorithms/detail/buffer/turn_in_original_visitor.hpp
new file mode 100644
index 0000000..05fc6df
--- /dev/null
+++ b/boost/geometry/algorithms/detail/buffer/turn_in_original_visitor.hpp
@@ -0,0 +1,268 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_ORIGINAL_VISITOR
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_ORIGINAL_VISITOR
+
+
+#include <boost/core/ignore_unused.hpp>
+
+#include <boost/geometry/algorithms/expand.hpp>
+#include <boost/geometry/strategies/agnostic/point_in_poly_winding.hpp>
+#include <boost/geometry/strategies/buffer.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace buffer
+{
+
+struct original_get_box
+{
+ template <typename Box, typename Original>
+ static inline void apply(Box& total, Original const& original)
+ {
+ geometry::expand(total, original.m_box);
+ }
+};
+
+struct original_ovelaps_box
+{
+ template <typename Box, typename Original>
+ static inline bool apply(Box const& box, Original const& original)
+ {
+ return ! detail::disjoint::disjoint_box_box(box, original.m_box);
+ }
+};
+
+struct include_turn_policy
+{
+ template <typename Turn>
+ static inline bool apply(Turn const& turn)
+ {
+ return turn.location == location_ok;
+ }
+};
+
+struct turn_in_original_ovelaps_box
+{
+ template <typename Box, typename Turn>
+ static inline bool apply(Box const& box, Turn const& turn)
+ {
+ if (turn.location != location_ok || turn.within_original)
+ {
+ // Skip all points already processed
+ return false;
+ }
+
+ return ! geometry::detail::disjoint::disjoint_point_box(
+ turn.robust_point, box);
+ }
+};
+
+//! Check if specified is in range of specified iterators
+//! Return value of strategy (true if we can bail out)
+template
+<
+ typename Strategy,
+ typename State,
+ typename Point,
+ typename Iterator
+>
+inline bool point_in_range(Strategy& strategy, State& state,
+ Point const& point, Iterator begin, Iterator end)
+{
+ boost::ignore_unused(strategy);
+
+ Iterator it = begin;
+ for (Iterator previous = it++; it != end; ++previous, ++it)
+ {
+ if (! strategy.apply(point, *previous, *it, state))
+ {
+ // We're probably on the boundary
+ return false;
+ }
+ }
+ return true;
+}
+
+template
+<
+ typename Strategy,
+ typename State,
+ typename Point,
+ typename CoordinateType,
+ typename Iterator
+>
+inline bool point_in_section(Strategy& strategy, State& state,
+ Point const& point, CoordinateType const& point_y,
+ Iterator begin, Iterator end,
+ int direction)
+{
+ if (direction == 0)
+ {
+ // Not a monotonic section, or no change in Y-direction
+ return point_in_range(strategy, state, point, begin, end);
+ }
+
+ // We're in a monotonic section in y-direction
+ Iterator it = begin;
+
+ for (Iterator previous = it++; it != end; ++previous, ++it)
+ {
+ // Depending on sections.direction we can quit for this section
+ CoordinateType const previous_y = geometry::get<1>(*previous);
+
+ if (direction == 1 && point_y < previous_y)
+ {
+ // Section goes upwards, y increases, point is is below section
+ return true;
+ }
+ else if (direction == -1 && point_y > previous_y)
+ {
+ // Section goes downwards, y decreases, point is above section
+ return true;
+ }
+
+ if (! strategy.apply(point, *previous, *it, state))
+ {
+ // We're probably on the boundary
+ return false;
+ }
+ }
+ return true;
+}
+
+
+template <typename Point, typename Original>
+inline int point_in_original(Point const& point, Original const& original)
+{
+ typedef strategy::within::winding<Point> strategy_type;
+
+ typename strategy_type::state_type state;
+ strategy_type strategy;
+
+ if (boost::size(original.m_sections) == 0
+ || boost::size(original.m_ring) - boost::size(original.m_sections) < 16)
+ {
+ // There are no sections, or it does not profit to walk over sections
+ // instead of over points. Boundary of 16 is arbitrary but can influence
+ // performance
+ point_in_range(strategy, state, point,
+ original.m_ring.begin(), original.m_ring.end());
+ return strategy.result(state);
+ }
+
+ typedef typename Original::sections_type sections_type;
+ typedef typename boost::range_iterator<sections_type const>::type iterator_type;
+ typedef typename boost::range_value<sections_type const>::type section_type;
+ typedef typename geometry::coordinate_type<Point>::type coordinate_type;
+
+ coordinate_type const point_y = geometry::get<1>(point);
+
+ // Walk through all monotonic sections of this original
+ for (iterator_type it = boost::begin(original.m_sections);
+ it != boost::end(original.m_sections);
+ ++it)
+ {
+ section_type const& section = *it;
+
+ if (! section.duplicate
+ && section.begin_index < section.end_index
+ && point_y >= geometry::get<min_corner, 1>(section.bounding_box)
+ && point_y <= geometry::get<max_corner, 1>(section.bounding_box))
+ {
+ // y-coordinate of point overlaps with section
+ if (! point_in_section(strategy, state, point, point_y,
+ boost::begin(original.m_ring) + section.begin_index,
+ boost::begin(original.m_ring) + section.end_index + 1,
+ section.directions[0]))
+ {
+ // We're probably on the boundary
+ break;
+ }
+ }
+ }
+
+ return strategy.result(state);
+}
+
+
+template <typename Turns>
+class turn_in_original_visitor
+{
+public:
+ turn_in_original_visitor(Turns& turns)
+ : m_mutable_turns(turns)
+ {}
+
+ template <typename Turn, typename Original>
+ inline void apply(Turn const& turn, Original const& original, bool first = true)
+ {
+ boost::ignore_unused_variable_warning(first);
+
+ if (turn.location != location_ok || turn.within_original)
+ {
+ // Skip all points already processed
+ return;
+ }
+
+ if (geometry::disjoint(turn.robust_point, original.m_box))
+ {
+ // Skip all disjoint
+ return;
+ }
+
+ int const code = point_in_original(turn.robust_point, original);
+
+ if (code == -1)
+ {
+ return;
+ }
+
+ Turn& mutable_turn = m_mutable_turns[turn.turn_index];
+
+ if (code == 0)
+ {
+ // On border of original: always discard
+ mutable_turn.location = location_discard;
+ }
+
+ // Point is inside an original ring
+ if (original.m_is_interior)
+ {
+ mutable_turn.count_in_original--;
+ }
+ else if (original.m_has_interiors)
+ {
+ mutable_turn.count_in_original++;
+ }
+ else
+ {
+ // It is an exterior ring and there are no interior rings.
+ // Then we are completely ready with this turn
+ mutable_turn.within_original = true;
+ mutable_turn.count_in_original = 1;
+ }
+ }
+
+private :
+ Turns& m_mutable_turns;
+};
+
+
+}} // namespace detail::buffer
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_ORIGINAL_VISITOR
diff --git a/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp b/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp
index c02f56d..8803efd 100644
--- a/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp
+++ b/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp
@@ -9,19 +9,23 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_PIECE_VISITOR
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_PIECE_VISITOR
+
+#include <boost/core/ignore_unused.hpp>
+
#include <boost/range.hpp>
#include <boost/geometry/arithmetic/dot_product.hpp>
+#include <boost/geometry/algorithms/assign.hpp>
+#include <boost/geometry/algorithms/comparable_distance.hpp>
#include <boost/geometry/algorithms/equals.hpp>
#include <boost/geometry/algorithms/expand.hpp>
#include <boost/geometry/algorithms/detail/disjoint/point_box.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
#include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
#include <boost/geometry/policies/compare.hpp>
#include <boost/geometry/strategies/buffer.hpp>
-#include <boost/geometry/geometries/linestring.hpp>
-#include <boost/geometry/algorithms/comparable_distance.hpp>
namespace boost { namespace geometry
{
@@ -31,6 +35,33 @@ namespace boost { namespace geometry
namespace detail { namespace buffer
{
+struct piece_get_box
+{
+ template <typename Box, typename Piece>
+ static inline void apply(Box& total, Piece const& piece)
+ {
+ geometry::expand(total, piece.robust_envelope);
+ }
+};
+
+struct piece_ovelaps_box
+{
+ template <typename Box, typename Piece>
+ static inline bool apply(Box const& box, Piece const& piece)
+ {
+ if (piece.type == strategy::buffer::buffered_flat_end
+ || piece.type == strategy::buffer::buffered_concave)
+ {
+ // Turns cannot be inside a flat end (though they can be on border)
+ // Neither we need to check if they are inside concave helper pieces
+
+ // Skip all pieces not used as soon as possible
+ return false;
+ }
+
+ return ! geometry::detail::disjoint::disjoint_box_box(box, piece.robust_envelope);
+ }
+};
struct turn_get_box
{
@@ -46,96 +77,422 @@ struct turn_ovelaps_box
template <typename Box, typename Turn>
static inline bool apply(Box const& box, Turn const& turn)
{
- return ! dispatch::disjoint
- <
- typename Turn::robust_point_type,
- Box
- >::apply(turn.robust_point, box);
+ return ! geometry::detail::disjoint::disjoint_point_box(turn.robust_point, box);
}
};
-template <typename Turns, typename Pieces>
-class turn_in_piece_visitor
+
+enum analyse_result
{
- Turns& m_turns; // because partition is currently operating on const input only
- Pieces const& m_pieces; // to check for piece-type
+ analyse_unknown,
+ analyse_continue,
+ analyse_disjoint,
+ analyse_within,
+ analyse_on_original_boundary,
+ analyse_on_offsetted,
+ analyse_near_offsetted
+};
- typedef boost::long_long_type calculation_type;
+template <typename Point>
+inline bool in_box(Point const& previous,
+ Point const& current, Point const& point)
+{
+ // Get its box (TODO: this can be prepared-on-demand later)
+ typedef geometry::model::box<Point> box_type;
+ box_type box;
+ geometry::assign_inverse(box);
+ geometry::expand(box, previous);
+ geometry::expand(box, current);
+
+ return geometry::covered_by(point, box);
+}
+
+template <typename Point, typename Turn>
+inline analyse_result check_segment(Point const& previous,
+ Point const& current, Turn const& turn,
+ bool from_monotonic)
+{
+ typedef typename strategy::side::services::default_strategy
+ <
+ typename cs_tag<Point>::type
+ >::type side_strategy;
+ typedef typename geometry::coordinate_type<Point>::type coordinate_type;
+
+ coordinate_type const twice_area
+ = side_strategy::template side_value
+ <
+ coordinate_type,
+ coordinate_type
+ >(previous, current, turn.robust_point);
- template <typename Point>
- static inline bool projection_on_segment(Point const& subject, Point const& p, Point const& q)
+ if (twice_area == 0)
{
- typedef Point vector_type;
- typedef typename geometry::coordinate_type<Point>::type coordinate_type;
+ // Collinear, only on segment if it is covered by its bbox
+ if (in_box(previous, current, turn.robust_point))
+ {
+ return analyse_on_offsetted;
+ }
+ }
+ else if (twice_area < 0)
+ {
+ // It is in the triangle right-of the segment where the
+ // segment is the hypothenusa. Check if it is close
+ // (within rounding-area)
+ if (twice_area * twice_area < geometry::comparable_distance(previous, current)
+ && in_box(previous, current, turn.robust_point))
+ {
+ return analyse_near_offsetted;
+ }
+ else if (from_monotonic)
+ {
+ return analyse_within;
+ }
+ }
+ else if (twice_area > 0 && from_monotonic)
+ {
+ // Left of segment
+ return analyse_disjoint;
+ }
+
+ // Not monotonic, on left or right side: continue analysing
+ return analyse_continue;
+}
- vector_type v = q;
- vector_type w = subject;
- subtract_point(v, p);
- subtract_point(w, p);
- coordinate_type const zero = coordinate_type();
- coordinate_type const c1 = dot_product(w, v);
+class analyse_turn_wrt_point_piece
+{
+public :
+ template <typename Turn, typename Piece>
+ static inline analyse_result apply(Turn const& turn, Piece const& piece)
+ {
+ typedef typename Piece::section_type section_type;
+ typedef typename Turn::robust_point_type point_type;
+ typedef typename geometry::coordinate_type<point_type>::type coordinate_type;
- if (c1 < zero)
+ coordinate_type const point_y = geometry::get<1>(turn.robust_point);
+
+ typedef strategy::within::winding<point_type> strategy_type;
+
+ typename strategy_type::state_type state;
+ strategy_type strategy;
+ boost::ignore_unused(strategy);
+
+ for (std::size_t s = 0; s < piece.sections.size(); s++)
{
- return false;
+ section_type const& section = piece.sections[s];
+ // If point within vertical range of monotonic section:
+ if (! section.duplicate
+ && section.begin_index < section.end_index
+ && point_y >= geometry::get<min_corner, 1>(section.bounding_box) - 1
+ && point_y <= geometry::get<max_corner, 1>(section.bounding_box) + 1)
+ {
+ for (int i = section.begin_index + 1; i <= section.end_index; i++)
+ {
+ point_type const& previous = piece.robust_ring[i - 1];
+ point_type const& current = piece.robust_ring[i];
+
+ analyse_result code = check_segment(previous, current, turn, false);
+ if (code != analyse_continue)
+ {
+ return code;
+ }
+
+ // Get the state (to determine it is within), we don't have
+ // to cover the on-segment case (covered above)
+ strategy.apply(turn.robust_point, previous, current, state);
+ }
+ }
}
- coordinate_type const c2 = dot_product(v, v);
- if (c2 < c1)
+
+ int const code = strategy.result(state);
+ if (code == 1)
{
- return false;
+ return analyse_within;
+ }
+ else if (code == -1)
+ {
+ return analyse_disjoint;
}
- return true;
+ // Should normally not occur - on-segment is covered
+ return analyse_unknown;
}
- template <typename Point, typename Piece>
- inline bool on_offsetted(Point const& point, Piece const& piece) const
+};
+
+class analyse_turn_wrt_piece
+{
+ template <typename Point, typename Turn>
+ static inline analyse_result check_helper_segment(Point const& s1,
+ Point const& s2, Turn const& turn,
+ bool is_original,
+ Point const& offsetted)
{
typedef typename strategy::side::services::default_strategy
<
typename cs_tag<Point>::type
>::type side_strategy;
- geometry::equal_to<Point> comparator;
+
+ switch(side_strategy::apply(s1, s2, turn.robust_point))
+ {
+ case 1 :
+ return analyse_disjoint; // left of segment
+ case 0 :
+ {
+ // If is collinear, either on segment or before/after
+ typedef geometry::model::box<Point> box_type;
+
+ box_type box;
+ geometry::assign_inverse(box);
+ geometry::expand(box, s1);
+ geometry::expand(box, s2);
+
+ if (geometry::covered_by(turn.robust_point, box))
+ {
+ // It is on the segment
+ if (! is_original
+ && geometry::comparable_distance(turn.robust_point, offsetted) <= 1)
+ {
+ // It is close to the offsetted-boundary, take
+ // any rounding-issues into account
+ return analyse_near_offsetted;
+ }
+
+ // Points on helper-segments are considered as within
+ // Points on original boundary are processed differently
+ return is_original
+ ? analyse_on_original_boundary
+ : analyse_within;
+ }
+
+ // It is collinear but not on the segment. Because these
+ // segments are convex, it is outside
+ // Unless the offsetted ring is collinear or concave w.r.t.
+ // helper-segment but that scenario is not yet supported
+ return analyse_disjoint;
+ }
+ break;
+ }
+
+ // right of segment
+ return analyse_continue;
+ }
+
+ template <typename Turn, typename Piece>
+ static inline analyse_result check_helper_segments(Turn const& turn, Piece const& piece)
+ {
+ typedef typename Turn::robust_point_type point_type;
+ geometry::equal_to<point_type> comparator;
+
+ point_type points[4];
+
+ int helper_count = piece.robust_ring.size() - piece.offsetted_count;
+ if (helper_count == 4)
+ {
+ for (int i = 0; i < 4; i++)
+ {
+ points[i] = piece.robust_ring[piece.offsetted_count + i];
+ }
+ }
+ else if (helper_count == 3)
+ {
+ // Triangular piece, assign points but assign second twice
+ for (int i = 0; i < 4; i++)
+ {
+ int index = i < 2 ? i : i - 1;
+ points[i] = piece.robust_ring[piece.offsetted_count + index];
+ }
+ }
+ else
+ {
+ // Some pieces (e.g. around points) do not have helper segments.
+ // Others should have 3 (join) or 4 (side)
+ return analyse_continue;
+ }
+
+ // First check point-equality
+ point_type const& point = turn.robust_point;
+ if (comparator(point, points[0]) || comparator(point, points[3]))
+ {
+ return analyse_on_offsetted;
+ }
+ if (comparator(point, points[1]) || comparator(point, points[2]))
+ {
+ return analyse_on_original_boundary;
+ }
+
+ // Right side of the piece
+ analyse_result result
+ = check_helper_segment(points[0], points[1], turn,
+ false, points[0]);
+ if (result != analyse_continue)
+ {
+ return result;
+ }
+
+ // Left side of the piece
+ result = check_helper_segment(points[2], points[3], turn,
+ false, points[3]);
+ if (result != analyse_continue)
+ {
+ return result;
+ }
+
+ if (! comparator(points[1], points[2]))
+ {
+ // Side of the piece at side of original geometry
+ result = check_helper_segment(points[1], points[2], turn,
+ true, point);
+ if (result != analyse_continue)
+ {
+ return result;
+ }
+ }
+
+ // We are within the \/ or |_| shaped piece, where the top is the
+ // offsetted ring.
+ if (! geometry::covered_by(point, piece.robust_offsetted_envelope))
+ {
+ // Not in offsetted-area. This makes a cheap check possible
+ typedef typename strategy::side::services::default_strategy
+ <
+ typename cs_tag<point_type>::type
+ >::type side_strategy;
+
+ switch(side_strategy::apply(points[3], points[0], point))
+ {
+ case 1 : return analyse_disjoint;
+ case -1 : return analyse_within;
+ case 0 : return analyse_disjoint;
+ }
+ }
+
+ return analyse_continue;
+ }
+
+ template <typename Turn, typename Piece, typename Compare>
+ static inline analyse_result check_monotonic(Turn const& turn, Piece const& piece, Compare const& compare)
+ {
+ typedef typename Piece::piece_robust_ring_type ring_type;
+ typedef typename ring_type::const_iterator it_type;
+ it_type end = piece.robust_ring.begin() + piece.offsetted_count;
+ it_type it = std::lower_bound(piece.robust_ring.begin(),
+ end,
+ turn.robust_point,
+ compare);
+
+ if (it != end
+ && it != piece.robust_ring.begin())
+ {
+ // iterator points to point larger than point
+ // w.r.t. specified direction, and prev points to a point smaller
+ // We now know if it is inside/outside
+ it_type prev = it - 1;
+ return check_segment(*prev, *it, turn, true);
+ }
+ return analyse_continue;
+ }
+
+public :
+ template <typename Turn, typename Piece>
+ static inline analyse_result apply(Turn const& turn, Piece const& piece)
+ {
+ typedef typename Turn::robust_point_type point_type;
+ analyse_result code = check_helper_segments(turn, piece);
+ if (code != analyse_continue)
+ {
+ return code;
+ }
+
+ geometry::equal_to<point_type> comparator;
+
+ if (piece.offsetted_count > 8)
+ {
+ // If the offset contains some points and is monotonic, we try
+ // to avoid walking all points linearly.
+ // We try it only once.
+ if (piece.is_monotonic_increasing[0])
+ {
+ code = check_monotonic(turn, piece, geometry::less<point_type, 0>());
+ if (code != analyse_continue) return code;
+ }
+ else if (piece.is_monotonic_increasing[1])
+ {
+ code = check_monotonic(turn, piece, geometry::less<point_type, 1>());
+ if (code != analyse_continue) return code;
+ }
+ else if (piece.is_monotonic_decreasing[0])
+ {
+ code = check_monotonic(turn, piece, geometry::greater<point_type, 0>());
+ if (code != analyse_continue) return code;
+ }
+ else if (piece.is_monotonic_decreasing[1])
+ {
+ code = check_monotonic(turn, piece, geometry::greater<point_type, 1>());
+ if (code != analyse_continue) return code;
+ }
+ }
+
+ // It is small or not monotonic, walk linearly through offset
+ // TODO: this will be combined with winding strategy
for (int i = 1; i < piece.offsetted_count; i++)
{
- Point const& previous = piece.robust_ring[i - 1];
- Point const& current = piece.robust_ring[i];
+ point_type const& previous = piece.robust_ring[i - 1];
+ point_type const& current = piece.robust_ring[i];
- // The robust ring contains duplicates, avoid applying side on them (will be 0)
+ // The robust ring can contain duplicates
+ // (on which any side or side-value would return 0)
if (! comparator(previous, current))
{
- int const side = side_strategy::apply(previous, current, point);
- if (side == 0)
+ code = check_segment(previous, current, turn, false);
+ if (code != analyse_continue)
{
- // Collinear, check if projection falls on it
- if (projection_on_segment(point, previous, current))
- {
- return true;
- }
+ return code;
}
}
}
- return false;
+
+ return analyse_unknown;
}
- template <typename Point, typename Piece>
- static inline
- calculation_type comparable_distance_from_offsetted(Point const& point,
- Piece const& piece)
+};
+
+
+template <typename Turns, typename Pieces>
+class turn_in_piece_visitor
+{
+ Turns& m_turns; // because partition is currently operating on const input only
+ Pieces const& m_pieces; // to check for piece-type
+
+ template <typename Operation, typename Piece>
+ inline bool skip(Operation const& op, Piece const& piece) const
{
- // TODO: pass subrange to dispatch to avoid making copy
- geometry::model::linestring<Point> ls;
- std::copy(piece.robust_ring.begin(),
- piece.robust_ring.begin() + piece.offsetted_count,
- std::back_inserter(ls));
- typename default_comparable_distance_result<Point, Point>::type
- const comp = geometry::comparable_distance(point, ls);
-
- return static_cast<calculation_type>(comp);
+ if (op.piece_index == piece.index)
+ {
+ return true;
+ }
+ Piece const& pc = m_pieces[op.piece_index];
+ if (pc.left_index == piece.index || pc.right_index == piece.index)
+ {
+ if (pc.type == strategy::buffer::buffered_flat_end)
+ {
+ // If it is a flat end, don't compare against its neighbor:
+ // it will always be located on one of the helper segments
+ return true;
+ }
+ if (pc.type == strategy::buffer::buffered_concave)
+ {
+ // If it is concave, the same applies: the IP will be
+ // located on one of the helper segments
+ return true;
+ }
+ }
+
+ return false;
}
+
public:
inline turn_in_piece_visitor(Turns& turns, Pieces const& pieces)
@@ -157,81 +514,55 @@ public:
if (piece.type == strategy::buffer::buffered_flat_end
|| piece.type == strategy::buffer::buffered_concave)
{
- // Turns cannot be inside a flat end (though they can be on border)
- // Neither we need to check if they are inside concave helper pieces
+ // Turns cannot be located within flat-end or concave pieces
return;
}
- bool neighbour = false;
- for (int i = 0; i < 2; i++)
- {
- // Don't compare against one of the two source-pieces
- if (turn.operations[i].piece_index == piece.index)
- {
- return;
- }
-
- typename boost::range_value<Pieces>::type const& pc
- = m_pieces[turn.operations[i].piece_index];
- if (pc.left_index == piece.index
- || pc.right_index == piece.index)
- {
- if (pc.type == strategy::buffer::buffered_flat_end)
- {
- // If it is a flat end, don't compare against its neighbor:
- // it will always be located on one of the helper segments
- return;
- }
- neighbour = true;
- }
- }
-
- int geometry_code = detail::within::point_in_geometry(turn.robust_point, piece.robust_ring);
-
- if (geometry_code == -1)
+ if (! geometry::covered_by(turn.robust_point, piece.robust_envelope))
{
+ // Easy check: if the turn is not in the envelope, we can safely return
return;
}
- if (geometry_code == 0 && neighbour)
+
+ if (skip(turn.operations[0], piece) || skip(turn.operations[1], piece))
{
return;
}
+ // TODO: mutable_piece to make some on-demand preparations in analyse
+ analyse_result analyse_code =
+ piece.type == geometry::strategy::buffer::buffered_point
+ ? analyse_turn_wrt_point_piece::apply(turn, piece)
+ : analyse_turn_wrt_piece::apply(turn, piece);
+
Turn& mutable_turn = m_turns[turn.turn_index];
- if (geometry_code == 0)
+ switch(analyse_code)
{
- // If it is on the border and they are not neighbours, it should be
- // on the offsetted ring
-
- if (! on_offsetted(turn.robust_point, piece))
- {
- // It is on the border but not on the offsetted ring.
- // Then it is somewhere on the helper-segments
- // Classify it as "within"
- geometry_code = 1;
- mutable_turn.count_on_helper++; // can still become "near_offsetted"
- }
- else
- {
+ case analyse_disjoint :
+ return;
+ case analyse_on_offsetted :
mutable_turn.count_on_offsetted++; // value is not used anymore
- }
+ return;
+ case analyse_on_original_boundary :
+ mutable_turn.count_on_original_boundary++;
+ return;
+ case analyse_within :
+ mutable_turn.count_within++;
+ return;
+ case analyse_near_offsetted :
+ mutable_turn.count_within_near_offsetted++;
+ return;
+ default :
+ break;
}
+ // TODO: this point_in_geometry is a performance-bottleneck here and
+ // will be replaced completely by extending analyse_piece functionality
+ int geometry_code = detail::within::point_in_geometry(turn.robust_point, piece.robust_ring);
+
if (geometry_code == 1)
{
- calculation_type const distance
- = comparable_distance_from_offsetted(turn.robust_point, piece);
- if (distance >= 4)
- {
- // This is too far from the border, it counts as "really within"
- mutable_turn.count_within++;
- }
- else
- {
- // Other points count as still "on border" because they might be
- // travelled through, but not used as starting point
- mutable_turn.count_within_near_offsetted++;
- }
+ mutable_turn.count_within++;
}
}
};
diff --git a/boost/geometry/algorithms/detail/closest_feature/geometry_to_range.hpp b/boost/geometry/algorithms/detail/closest_feature/geometry_to_range.hpp
index c7558b4..04fa9ee 100644
--- a/boost/geometry/algorithms/detail/closest_feature/geometry_to_range.hpp
+++ b/boost/geometry/algorithms/detail/closest_feature/geometry_to_range.hpp
@@ -63,8 +63,7 @@ private:
>::apply(geometry, *it_min, strategy);
// check if other elements in the range are closer
- RangeIterator it = first;
- for (++it; it != last; ++it)
+ for (RangeIterator it = ++first; it != last; ++it)
{
Distance dist = dispatch::distance
<
diff --git a/boost/geometry/algorithms/detail/closest_feature/range_to_range.hpp b/boost/geometry/algorithms/detail/closest_feature/range_to_range.hpp
index 9024876..ceba59b 100644
--- a/boost/geometry/algorithms/detail/closest_feature/range_to_range.hpp
+++ b/boost/geometry/algorithms/detail/closest_feature/range_to_range.hpp
@@ -60,6 +60,7 @@ private:
BOOST_ASSERT( queries_first != queries_last );
Distance const zero = Distance(0);
+ dist_min = zero;
// create -- packing algorithm
rtree_type rt(rtree_first, rtree_last);
diff --git a/boost/geometry/algorithms/detail/comparable_distance/interface.hpp b/boost/geometry/algorithms/detail/comparable_distance/interface.hpp
index 1a57c8f..c443a54 100644
--- a/boost/geometry/algorithms/detail/comparable_distance/interface.hpp
+++ b/boost/geometry/algorithms/detail/comparable_distance/interface.hpp
@@ -232,13 +232,13 @@ struct comparable_distance
template
<
- BOOST_VARIANT_ENUM_PARAMS(typename A),
- BOOST_VARIANT_ENUM_PARAMS(typename B)
+ BOOST_VARIANT_ENUM_PARAMS(typename T1),
+ BOOST_VARIANT_ENUM_PARAMS(typename T2)
>
struct comparable_distance
<
- boost::variant<BOOST_VARIANT_ENUM_PARAMS(A)>,
- boost::variant<BOOST_VARIANT_ENUM_PARAMS(B)>
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>
>
{
template <typename Strategy>
@@ -246,8 +246,8 @@ struct comparable_distance
<
typename comparable_distance_result
<
- boost::variant<BOOST_VARIANT_ENUM_PARAMS(A)>,
- boost::variant<BOOST_VARIANT_ENUM_PARAMS(B)>,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>,
Strategy
>::type
>
@@ -279,12 +279,12 @@ struct comparable_distance
template <typename Strategy>
static inline typename comparable_distance_result
<
- boost::variant<BOOST_VARIANT_ENUM_PARAMS(A)>,
- boost::variant<BOOST_VARIANT_ENUM_PARAMS(B)>,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>,
Strategy
>::type
- apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(A)> const& geometry1,
- boost::variant<BOOST_VARIANT_ENUM_PARAMS(B)> const& geometry2,
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2,
Strategy const& strategy)
{
return apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2);
diff --git a/boost/geometry/algorithms/detail/course.hpp b/boost/geometry/algorithms/detail/course.hpp
index e1a74c0..3742494 100644
--- a/boost/geometry/algorithms/detail/course.hpp
+++ b/boost/geometry/algorithms/detail/course.hpp
@@ -14,10 +14,7 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_COURSE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_COURSE_HPP
-#include <boost/geometry/core/cs.hpp>
-#include <boost/geometry/core/access.hpp>
-#include <boost/geometry/core/radian_access.hpp>
-#include <boost/geometry/util/math.hpp>
+#include <boost/geometry/algorithms/detail/azimuth.hpp>
namespace boost { namespace geometry
{
@@ -27,25 +24,12 @@ namespace detail
{
/// Calculate course (bearing) between two points.
+///
+/// NOTE: left for convenience and temporary backward compatibility
template <typename ReturnType, typename Point1, typename Point2>
inline ReturnType course(Point1 const& p1, Point2 const& p2)
{
- // http://williams.best.vwh.net/avform.htm#Crs
- ReturnType dlon = get_as_radian<0>(p2) - get_as_radian<0>(p1);
- ReturnType cos_p2lat = cos(get_as_radian<1>(p2));
-
- // An optimization which should kick in often for Boxes
- //if ( math::equals(dlon, ReturnType(0)) )
- //if ( get<0>(p1) == get<0>(p2) )
- //{
- // return - sin(get_as_radian<1>(p1)) * cos_p2lat);
- //}
-
- // "An alternative formula, not requiring the pre-computation of d"
- // In the formula below dlon is used as "d"
- return atan2(sin(dlon) * cos_p2lat,
- cos(get_as_radian<1>(p1)) * sin(get_as_radian<1>(p2))
- - sin(get_as_radian<1>(p1)) * cos_p2lat * cos(dlon));
+ return azimuth<ReturnType>(p1, p2);
}
} // namespace detail
diff --git a/boost/geometry/algorithms/detail/disjoint/box_box.hpp b/boost/geometry/algorithms/detail/disjoint/box_box.hpp
index ccff979..84671f2 100644
--- a/boost/geometry/algorithms/detail/disjoint/box_box.hpp
+++ b/boost/geometry/algorithms/detail/disjoint/box_box.hpp
@@ -74,7 +74,7 @@ struct box_box<Box1, Box2, DimensionCount, DimensionCount>
/*!
- \brief Internal utility function to detect of boxes are disjoint
+ \brief Internal utility function to detect if boxes are disjoint
\note Is used from other algorithms, declared separately
to avoid circular references
*/
diff --git a/boost/geometry/algorithms/detail/disjoint/implementation.hpp b/boost/geometry/algorithms/detail/disjoint/implementation.hpp
index 0c8079b..d482c4a 100644
--- a/boost/geometry/algorithms/detail/disjoint/implementation.hpp
+++ b/boost/geometry/algorithms/detail/disjoint/implementation.hpp
@@ -26,6 +26,7 @@
#include <boost/geometry/algorithms/detail/disjoint/linear_areal.hpp>
#include <boost/geometry/algorithms/detail/disjoint/linear_linear.hpp>
#include <boost/geometry/algorithms/detail/disjoint/point_geometry.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/multipoint_geometry.hpp>
#include <boost/geometry/algorithms/detail/disjoint/point_point.hpp>
#include <boost/geometry/algorithms/detail/disjoint/point_box.hpp>
#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
diff --git a/boost/geometry/algorithms/detail/disjoint/interface.hpp b/boost/geometry/algorithms/detail/disjoint/interface.hpp
index ec9057b..96d6881 100644
--- a/boost/geometry/algorithms/detail/disjoint/interface.hpp
+++ b/boost/geometry/algorithms/detail/disjoint/interface.hpp
@@ -23,8 +23,8 @@
#include <cstddef>
-#include <boost/variant/static_visitor.hpp>
#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/static_visitor.hpp>
#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
diff --git a/boost/geometry/algorithms/detail/disjoint/linear_areal.hpp b/boost/geometry/algorithms/detail/disjoint/linear_areal.hpp
index eefd351..6a48b68 100644
--- a/boost/geometry/algorithms/detail/disjoint/linear_areal.hpp
+++ b/boost/geometry/algorithms/detail/disjoint/linear_areal.hpp
@@ -5,8 +5,8 @@
// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
-// This file was modified by Oracle on 2013-2014.
-// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates.
+// This file was modified by Oracle on 2013-2015.
+// Modifications copyright (c) 2013-2015, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
@@ -31,16 +31,20 @@
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tag_cast.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/covered_by.hpp>
#include <boost/geometry/algorithms/not_implemented.hpp>
-#include <boost/geometry/algorithms/detail/point_on_border.hpp>
#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp>
+#include <boost/geometry/algorithms/detail/check_iterator_range.hpp>
+#include <boost/geometry/algorithms/detail/point_on_border.hpp>
+
+#include <boost/geometry/algorithms/detail/disjoint/multirange_geometry.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.hpp>
#include <boost/geometry/algorithms/detail/disjoint/point_box.hpp>
#include <boost/geometry/algorithms/detail/disjoint/segment_box.hpp>
-#include <boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.hpp>
#include <boost/geometry/algorithms/dispatch/disjoint.hpp>
@@ -48,25 +52,59 @@
namespace boost { namespace geometry
{
-
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace disjoint
{
+template <typename Geometry1, typename Geometry2,
+ typename Tag1 = typename tag<Geometry1>::type,
+ typename Tag1OrMulti = typename tag_cast<Tag1, multi_tag>::type>
+struct disjoint_no_intersections_policy
+{
+ static inline bool apply(Geometry1 const& g1, Geometry2 const& g2)
+ {
+ typedef typename point_type<Geometry1>::type point1_type;
+ point1_type p;
+ geometry::point_on_border(p, g1);
+ return !geometry::covered_by(p, g2);
+ }
+};
-template<typename Geometry1, typename Geometry2>
+template <typename Geometry1, typename Geometry2, typename Tag1>
+struct disjoint_no_intersections_policy<Geometry1, Geometry2, Tag1, multi_tag>
+{
+ static inline bool apply(Geometry1 const& g1, Geometry2 const& g2)
+ {
+ // TODO: use partition or rtree on g2
+ typedef typename boost::range_iterator<Geometry1 const>::type iterator;
+ for ( iterator it = boost::begin(g1) ; it != boost::end(g1) ; ++it )
+ {
+ typedef typename boost::range_value<Geometry1 const>::type value_type;
+ if ( ! disjoint_no_intersections_policy<value_type const, Geometry2>
+ ::apply(*it, g2) )
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+};
+
+
+template<typename Geometry1, typename Geometry2,
+ typename NoIntersectionsPolicy
+ = disjoint_no_intersections_policy<Geometry1, Geometry2> >
struct disjoint_linear_areal
{
static inline bool apply(Geometry1 const& g1, Geometry2 const& g2)
{
// if there are intersections - return false
if ( !disjoint_linear<Geometry1, Geometry2>::apply(g1, g2) )
+ {
return false;
+ }
- typedef typename point_type<Geometry1>::type point1_type;
- point1_type p;
- geometry::point_on_border(p, g1);
- return !geometry::covered_by(p, g2);
+ return NoIntersectionsPolicy::apply(g1, g2);
}
};
@@ -88,38 +126,28 @@ template <typename Segment, typename Polygon>
class disjoint_segment_areal<Segment, Polygon, polygon_tag>
{
private:
- template <typename RingIterator>
- static inline bool check_interior_rings(RingIterator first,
- RingIterator beyond,
- Segment const& segment)
- {
- for (RingIterator it = first; it != beyond; ++it)
- {
- if ( !disjoint_range_segment_or_box
- <
- typename std::iterator_traits
- <
- RingIterator
- >::value_type,
- closure<Polygon>::value,
- Segment
- >::apply(*it, segment) )
- {
- return false;
- }
- }
- return true;
- }
-
-
template <typename InteriorRings>
static inline
bool check_interior_rings(InteriorRings const& interior_rings,
Segment const& segment)
{
- return check_interior_rings(boost::begin(interior_rings),
- boost::end(interior_rings),
- segment);
+ typedef typename boost::range_value<InteriorRings>::type ring_type;
+
+ typedef unary_disjoint_geometry_to_query_geometry
+ <
+ Segment,
+ disjoint_range_segment_or_box
+ <
+ ring_type, closure<ring_type>::value, Segment
+ >
+ > unary_predicate_type;
+
+ return check_iterator_range
+ <
+ unary_predicate_type
+ >::apply(boost::begin(interior_rings),
+ boost::end(interior_rings),
+ unary_predicate_type(segment));
}
@@ -155,7 +183,7 @@ struct disjoint_segment_areal<Segment, MultiPolygon, multi_polygon_tag>
static inline
bool apply(Segment const& segment, MultiPolygon const& multipolygon)
{
- return disjoint_multirange_segment_or_box
+ return multirange_constant_size_geometry
<
MultiPolygon, Segment
>::apply(multipolygon, segment);
diff --git a/boost/geometry/algorithms/detail/disjoint/linear_linear.hpp b/boost/geometry/algorithms/detail/disjoint/linear_linear.hpp
index ad84d71..91f985e 100644
--- a/boost/geometry/algorithms/detail/disjoint/linear_linear.hpp
+++ b/boost/geometry/algorithms/detail/disjoint/linear_linear.hpp
@@ -98,11 +98,10 @@ struct assign_disjoint_policy
typename Info,
typename Point1,
typename Point2,
- typename IntersectionInfo,
- typename DirInfo
+ typename IntersectionInfo
>
static inline void apply(Info& , Point1 const& , Point2 const&,
- IntersectionInfo const&, DirInfo const&)
+ IntersectionInfo const&)
{}
};
@@ -115,28 +114,42 @@ struct disjoint_linear
{
typedef typename geometry::point_type<Geometry1>::type point_type;
typedef detail::no_rescale_policy rescale_policy_type;
+ typedef typename geometry::segment_ratio_type
+ <
+ point_type, rescale_policy_type
+ >::type segment_ratio_type;
typedef overlay::turn_info
- <
- point_type,
- typename segment_ratio_type<point_type, rescale_policy_type>::type
- > turn_info;
- std::deque<turn_info> turns;
+ <
+ point_type,
+ segment_ratio_type,
+ typename detail::get_turns::turn_operation_type
+ <
+ Geometry1, Geometry2, segment_ratio_type
+ >::type
+ > turn_info_type;
- static const bool reverse1 = overlay::do_reverse<geometry::point_order<Geometry1>::value>::value; // should be false
- static const bool reverse2 = overlay::do_reverse<geometry::point_order<Geometry2>::value>::value; // should be false
+ std::deque<turn_info_type> turns;
// Specify two policies:
// 1) Stop at any intersection
// 2) In assignment, include also degenerate points (which are normally skipped)
- disjoint_interrupt_policy policy;
- rescale_policy_type robust_policy;
- geometry::get_turns
+ disjoint_interrupt_policy interrupt_policy;
+ dispatch::get_turns
<
- reverse1, reverse2,
- assign_disjoint_policy
- >(geometry1, geometry2, robust_policy, turns, policy);
+ typename geometry::tag<Geometry1>::type,
+ typename geometry::tag<Geometry2>::type,
+ Geometry1,
+ Geometry2,
+ overlay::do_reverse<geometry::point_order<Geometry1>::value>::value, // should be false
+ overlay::do_reverse<geometry::point_order<Geometry2>::value>::value, // should be false
+ detail::get_turns::get_turn_info_type
+ <
+ Geometry1, Geometry2, assign_disjoint_policy
+ >
+ >::apply(0, geometry1, 1, geometry2,
+ rescale_policy_type(), turns, interrupt_policy);
- return !policy.has_intersections;
+ return !interrupt_policy.has_intersections;
}
};
diff --git a/boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.hpp b/boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.hpp
index d181726..8d82f7c 100644
--- a/boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.hpp
+++ b/boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.hpp
@@ -32,6 +32,7 @@
#include <boost/geometry/views/closeable_view.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/multirange_geometry.hpp>
#include <boost/geometry/algorithms/dispatch/disjoint.hpp>
@@ -44,34 +45,6 @@ namespace detail { namespace disjoint
{
-template <typename MultiRange, typename SegmentOrBox>
-struct disjoint_multirange_segment_or_box
-{
- static inline
- bool apply(MultiRange const& multirange, SegmentOrBox const& segment_or_box)
- {
- typedef typename boost::range_iterator
- <
- MultiRange const
- >::type const_iterator;
-
- for (const_iterator it = boost::begin(multirange);
- it != boost::end(multirange); ++it)
- {
- if ( !dispatch::disjoint
- <
- typename boost::range_value<MultiRange>::type,
- SegmentOrBox
- >::apply(*it, segment_or_box) )
- {
- return false;
- }
- }
- return true;
- }
-};
-
-
template
<
typename Range,
@@ -160,7 +133,7 @@ template <typename MultiLinestring, typename SegmentOrBox>
struct disjoint_linear_segment_or_box
<
MultiLinestring, SegmentOrBox, multi_linestring_tag
- > : disjoint_multirange_segment_or_box<MultiLinestring, SegmentOrBox>
+ > : multirange_constant_size_geometry<MultiLinestring, SegmentOrBox>
{};
diff --git a/boost/geometry/algorithms/detail/disjoint/multipoint_geometry.hpp b/boost/geometry/algorithms/detail/disjoint/multipoint_geometry.hpp
new file mode 100644
index 0000000..7d1bb05
--- /dev/null
+++ b/boost/geometry/algorithms/detail/disjoint/multipoint_geometry.hpp
@@ -0,0 +1,162 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_MULTIPOINT_GEOMETRY_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_MULTIPOINT_GEOMETRY_HPP
+
+#include <algorithm>
+#include <vector>
+
+#include <boost/assert.hpp>
+#include <boost/range.hpp>
+
+#include <boost/geometry/algorithms/detail/check_iterator_range.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/multirange_geometry.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/point_point.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/point_geometry.hpp>
+#include <boost/geometry/algorithms/detail/relate/less.hpp>
+
+#include <boost/geometry/algorithms/dispatch/disjoint.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace disjoint
+{
+
+template<typename MultiPoint1, typename MultiPoint2>
+class multipoint_multipoint
+{
+private:
+ template <typename Iterator>
+ class unary_disjoint_predicate
+ : detail::relate::less
+ {
+ private:
+ typedef detail::relate::less base_type;
+
+ public:
+ unary_disjoint_predicate(Iterator first, Iterator last)
+ : base_type(), m_first(first), m_last(last)
+ {}
+
+ template <typename Point>
+ inline bool apply(Point const& point) const
+ {
+ return !std::binary_search(m_first,
+ m_last,
+ point,
+ static_cast<base_type const&>(*this));
+ }
+
+ private:
+ Iterator m_first, m_last;
+ };
+
+public:
+ static inline bool apply(MultiPoint1 const& multipoint1,
+ MultiPoint2 const& multipoint2)
+ {
+ BOOST_ASSERT( boost::size(multipoint1) <= boost::size(multipoint2) );
+
+ typedef typename boost::range_value<MultiPoint1>::type point1_type;
+
+ std::vector<point1_type> points1(boost::begin(multipoint1),
+ boost::end(multipoint1));
+
+ std::sort(points1.begin(), points1.end(), detail::relate::less());
+
+ typedef unary_disjoint_predicate
+ <
+ typename std::vector<point1_type>::const_iterator
+ > predicate_type;
+
+ return check_iterator_range
+ <
+ predicate_type
+ >::apply(boost::begin(multipoint2),
+ boost::end(multipoint2),
+ predicate_type(points1.begin(), points1.end()));
+ }
+};
+
+
+}} // namespace detail::disjoint
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template<typename Point, typename MultiPoint, std::size_t DimensionCount>
+struct disjoint
+ <
+ Point, MultiPoint, DimensionCount, point_tag, multi_point_tag, false
+ > : detail::disjoint::multirange_constant_size_geometry<MultiPoint, Point>
+{};
+
+
+template<typename MultiPoint, typename Segment, std::size_t DimensionCount>
+struct disjoint
+ <
+ MultiPoint, Segment, DimensionCount, multi_point_tag, segment_tag, false
+ > : detail::disjoint::multirange_constant_size_geometry<MultiPoint, Segment>
+{};
+
+
+template<typename MultiPoint, typename Box, std::size_t DimensionCount>
+struct disjoint
+ <
+ MultiPoint, Box, DimensionCount, multi_point_tag, box_tag, false
+ > : detail::disjoint::multirange_constant_size_geometry<MultiPoint, Box>
+{};
+
+
+template<typename MultiPoint1, typename MultiPoint2, std::size_t DimensionCount>
+struct disjoint
+ <
+ MultiPoint1, MultiPoint2, DimensionCount,
+ multi_point_tag, multi_point_tag, false
+ >
+{
+ static inline bool apply(MultiPoint1 const& multipoint1,
+ MultiPoint2 const& multipoint2)
+ {
+ if ( boost::size(multipoint2) < boost::size(multipoint1) )
+ {
+ return detail::disjoint::multipoint_multipoint
+ <
+ MultiPoint2, MultiPoint1
+ >::apply(multipoint2, multipoint1);
+ }
+
+ return detail::disjoint::multipoint_multipoint
+ <
+ MultiPoint1, MultiPoint2
+ >::apply(multipoint1, multipoint2);
+ }
+};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_MULTIPOINT_GEOMETRY_HPP
diff --git a/boost/geometry/algorithms/detail/disjoint/multirange_geometry.hpp b/boost/geometry/algorithms/detail/disjoint/multirange_geometry.hpp
new file mode 100644
index 0000000..78a683e
--- /dev/null
+++ b/boost/geometry/algorithms/detail/disjoint/multirange_geometry.hpp
@@ -0,0 +1,85 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2014, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_MULTIRANGE_GEOMETRY_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_MULTIRANGE_GEOMETRY_HPP
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/algorithms/detail/check_iterator_range.hpp>
+#include <boost/geometry/algorithms/dispatch/disjoint.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace disjoint
+{
+
+
+template <typename Geometry, typename BinaryPredicate>
+class unary_disjoint_geometry_to_query_geometry
+{
+public:
+ unary_disjoint_geometry_to_query_geometry(Geometry const& geometry)
+ : m_geometry(geometry)
+ {}
+
+ template <typename QueryGeometry>
+ inline bool apply(QueryGeometry const& query_geometry) const
+ {
+ return BinaryPredicate::apply(query_geometry, m_geometry);
+ }
+
+private:
+ Geometry const& m_geometry;
+};
+
+
+template<typename MultiRange, typename ConstantSizeGeometry>
+struct multirange_constant_size_geometry
+{
+ static inline bool apply(MultiRange const& multirange,
+ ConstantSizeGeometry const& constant_size_geometry)
+ {
+ typedef unary_disjoint_geometry_to_query_geometry
+ <
+ ConstantSizeGeometry,
+ dispatch::disjoint
+ <
+ typename boost::range_value<MultiRange>::type,
+ ConstantSizeGeometry
+ >
+ > unary_predicate_type;
+
+ return detail::check_iterator_range
+ <
+ unary_predicate_type
+ >::apply(boost::begin(multirange), boost::end(multirange),
+ unary_predicate_type(constant_size_geometry));
+ }
+
+ static inline bool apply(ConstantSizeGeometry const& constant_size_geometry,
+ MultiRange const& multirange)
+ {
+ return apply(multirange, constant_size_geometry);
+ }
+};
+
+
+}} // namespace detail::disjoint
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_MULTIRANGE_GEOMETRY_HPP
diff --git a/boost/geometry/algorithms/detail/disjoint/point_box.hpp b/boost/geometry/algorithms/detail/disjoint/point_box.hpp
index ea6609a..12213db 100644
--- a/boost/geometry/algorithms/detail/disjoint/point_box.hpp
+++ b/boost/geometry/algorithms/detail/disjoint/point_box.hpp
@@ -70,8 +70,21 @@ struct point_box<Point, Box, DimensionCount, DimensionCount>
}
};
+/*!
+ \brief Internal utility function to detect if point/box are disjoint
+ */
+template <typename Point, typename Box>
+inline bool disjoint_point_box(Point const& point, Box const& box)
+{
+ return detail::disjoint::point_box
+ <
+ Point, Box,
+ 0, dimension<Point>::type::value
+ >::apply(point, box);
+}
+
-}} // namespace detail::equals
+}} // namespace detail::disjoint
#endif // DOXYGEN_NO_DETAIL
diff --git a/boost/geometry/algorithms/detail/distance/geometry_to_segment_or_box.hpp b/boost/geometry/algorithms/detail/distance/geometry_to_segment_or_box.hpp
index 04d1095..57257db 100644
--- a/boost/geometry/algorithms/detail/distance/geometry_to_segment_or_box.hpp
+++ b/boost/geometry/algorithms/detail/distance/geometry_to_segment_or_box.hpp
@@ -35,6 +35,8 @@
#include <boost/geometry/algorithms/detail/distance/is_comparable.hpp>
+#include <boost/geometry/util/condition.hpp>
+
namespace boost { namespace geometry
{
@@ -215,7 +217,7 @@ public:
// consider all distances of the points in the geometry to the
// segment or box
- comparable_return_type cd_min1;
+ comparable_return_type cd_min1(0);
point_iterator_type pit_min;
seg_or_box_iterator_type it_min1 = seg_or_box_points.begin();
seg_or_box_iterator_type it_min2 = ++seg_or_box_points.begin();
@@ -246,7 +248,7 @@ public:
// consider all distances of the points in the segment or box to the
// segments of the geometry
- comparable_return_type cd_min2;
+ comparable_return_type cd_min2(0);
segment_iterator_type sit_min;
typename std::vector<segment_or_box_point>::const_iterator it_min;
@@ -271,7 +273,7 @@ public:
}
}
- if (is_comparable<Strategy>::value)
+ if (BOOST_GEOMETRY_CONDITION(is_comparable<Strategy>::value))
{
return (std::min)(cd_min1, cd_min2);
}
diff --git a/boost/geometry/algorithms/detail/distance/interface.hpp b/boost/geometry/algorithms/detail/distance/interface.hpp
index 9b377f5..fa8cbd6 100644
--- a/boost/geometry/algorithms/detail/distance/interface.hpp
+++ b/boost/geometry/algorithms/detail/distance/interface.hpp
@@ -260,13 +260,13 @@ struct distance<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
template
<
- BOOST_VARIANT_ENUM_PARAMS(typename A),
- BOOST_VARIANT_ENUM_PARAMS(typename B)
+ BOOST_VARIANT_ENUM_PARAMS(typename T1),
+ BOOST_VARIANT_ENUM_PARAMS(typename T2)
>
struct distance
<
- boost::variant<BOOST_VARIANT_ENUM_PARAMS(A)>,
- boost::variant<BOOST_VARIANT_ENUM_PARAMS(B)>
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>
>
{
template <typename Strategy>
@@ -274,8 +274,8 @@ struct distance
<
typename distance_result
<
- boost::variant<BOOST_VARIANT_ENUM_PARAMS(A)>,
- boost::variant<BOOST_VARIANT_ENUM_PARAMS(B)>,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>,
Strategy
>::type
>
@@ -304,12 +304,12 @@ struct distance
template <typename Strategy>
static inline typename distance_result
<
- boost::variant<BOOST_VARIANT_ENUM_PARAMS(A)>,
- boost::variant<BOOST_VARIANT_ENUM_PARAMS(B)>,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>,
Strategy
>::type
- apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(A)> const& geometry1,
- boost::variant<BOOST_VARIANT_ENUM_PARAMS(B)> const& geometry2,
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2,
Strategy const& strategy)
{
return apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2);
diff --git a/boost/geometry/algorithms/detail/distance/multipoint_to_geometry.hpp b/boost/geometry/algorithms/detail/distance/multipoint_to_geometry.hpp
index 5f2c6e3..ccd3aa4 100644
--- a/boost/geometry/algorithms/detail/distance/multipoint_to_geometry.hpp
+++ b/boost/geometry/algorithms/detail/distance/multipoint_to_geometry.hpp
@@ -18,7 +18,7 @@
#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/strategies/tags.hpp>
-#include <boost/geometry/algorithms/within.hpp>
+#include <boost/geometry/algorithms/covered_by.hpp>
#include <boost/geometry/algorithms/dispatch/distance.hpp>
@@ -113,16 +113,16 @@ template <typename MultiPoint, typename Areal, typename Strategy>
class multipoint_to_areal
{
private:
- struct within_areal
+ struct not_covered_by_areal
{
- within_areal(Areal const& areal)
+ not_covered_by_areal(Areal const& areal)
: m_areal(areal)
{}
template <typename Point>
inline bool apply(Point const& point) const
{
- return geometry::within(point, m_areal);
+ return !geometry::covered_by(point, m_areal);
}
Areal const& m_areal;
@@ -140,27 +140,26 @@ public:
Areal const& areal,
Strategy const& strategy)
{
- within_areal predicate(areal);
+ not_covered_by_areal predicate(areal);
if (check_iterator_range
<
- within_areal, false
+ not_covered_by_areal, false
>::apply(boost::begin(multipoint),
boost::end(multipoint),
predicate))
{
- return 0;
+ return detail::distance::point_or_segment_range_to_geometry_rtree
+ <
+ typename boost::range_iterator<MultiPoint const>::type,
+ Areal,
+ Strategy
+ >::apply(boost::begin(multipoint),
+ boost::end(multipoint),
+ areal,
+ strategy);
}
-
- return detail::distance::point_or_segment_range_to_geometry_rtree
- <
- typename boost::range_iterator<MultiPoint const>::type,
- Areal,
- Strategy
- >::apply(boost::begin(multipoint),
- boost::end(multipoint),
- areal,
- strategy);
+ return 0;
}
static inline return_type apply(Areal const& areal,
diff --git a/boost/geometry/algorithms/detail/distance/segment_to_box.hpp b/boost/geometry/algorithms/detail/distance/segment_to_box.hpp
index f64a3e9..79d9adb 100644
--- a/boost/geometry/algorithms/detail/distance/segment_to_box.hpp
+++ b/boost/geometry/algorithms/detail/distance/segment_to_box.hpp
@@ -28,6 +28,7 @@
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/util/calculation_type.hpp>
+#include <boost/geometry/util/condition.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/strategies/distance.hpp>
@@ -151,7 +152,7 @@ public:
}
}
- if (is_comparable<Strategy>::value)
+ if (BOOST_GEOMETRY_CONDITION(is_comparable<Strategy>::value))
{
return cd[imin];
}
diff --git a/boost/geometry/algorithms/detail/distance/segment_to_segment.hpp b/boost/geometry/algorithms/detail/distance/segment_to_segment.hpp
index 2dcde64..bdf056d 100644
--- a/boost/geometry/algorithms/detail/distance/segment_to_segment.hpp
+++ b/boost/geometry/algorithms/detail/distance/segment_to_segment.hpp
@@ -18,6 +18,8 @@
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/util/condition.hpp>
+
#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/strategies/tags.hpp>
@@ -96,7 +98,7 @@ public:
std::size_t imin = std::distance(boost::addressof(d[0]),
std::min_element(d, d + 4));
- if (is_comparable<Strategy>::value)
+ if (BOOST_GEOMETRY_CONDITION(is_comparable<Strategy>::value))
{
return d[imin];
}
diff --git a/boost/geometry/algorithms/detail/equals/collect_vectors.hpp b/boost/geometry/algorithms/detail/equals/collect_vectors.hpp
index 5bcb5ff..dc1cd74 100644
--- a/boost/geometry/algorithms/detail/equals/collect_vectors.hpp
+++ b/boost/geometry/algorithms/detail/equals/collect_vectors.hpp
@@ -17,7 +17,6 @@
#include <boost/numeric/conversion/cast.hpp>
-#include <boost/range.hpp>
#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
@@ -28,7 +27,7 @@
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/util/math.hpp>
-
+#include <boost/geometry/util/range.hpp>
namespace boost { namespace geometry
@@ -159,7 +158,7 @@ struct range_collect_vectors
if ( collected_count > 1 )
{
typedef typename boost::range_iterator<Collection>::type c_iterator;
- c_iterator first = collection.begin() + c_old_size;
+ c_iterator first = range::pos(collection, c_old_size);
if ( first->same_direction(collection.back()) )
{
diff --git a/boost/geometry/algorithms/detail/flattening.hpp b/boost/geometry/algorithms/detail/flattening.hpp
new file mode 100644
index 0000000..8ed5fd9
--- /dev/null
+++ b/boost/geometry/algorithms/detail/flattening.hpp
@@ -0,0 +1,69 @@
+// Boost.Geometry
+
+// 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_FLATTENING_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_FLATTENING_HPP
+
+#include <boost/geometry/core/radius.hpp>
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/algorithms/not_implemented.hpp>
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace detail_dispatch
+{
+
+template <typename ResultType, typename Geometry, typename Tag = typename tag<Geometry>::type>
+struct flattening
+ : not_implemented<Tag>
+{};
+
+template <typename ResultType, typename Geometry>
+struct flattening<ResultType, Geometry, srs_sphere_tag>
+{
+ static inline ResultType apply(Geometry const& /*geometry*/)
+ {
+ return ResultType(0);
+ }
+};
+
+template <typename ResultType, typename Geometry>
+struct flattening<ResultType, Geometry, srs_spheroid_tag>
+{
+ static inline ResultType apply(Geometry const& geometry)
+ {
+ return ResultType(get_radius<0>(geometry) - get_radius<2>(geometry))
+ / ResultType(get_radius<0>(geometry));
+ }
+};
+
+} // namespace detail_dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail
+{
+
+template <typename ResultType, typename Geometry>
+ResultType flattening(Geometry const& geometry)
+{
+ return detail_dispatch::flattening<ResultType, Geometry>::apply(geometry);
+}
+
+} // namespace detail
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_FLATTENING_HPP
diff --git a/boost/geometry/algorithms/detail/intersection/interface.hpp b/boost/geometry/algorithms/detail/intersection/interface.hpp
index 323ab7c..d57535e 100644
--- a/boost/geometry/algorithms/detail/intersection/interface.hpp
+++ b/boost/geometry/algorithms/detail/intersection/interface.hpp
@@ -223,8 +223,8 @@ struct intersection<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
};
-template <BOOST_VARIANT_ENUM_PARAMS(typename A), BOOST_VARIANT_ENUM_PARAMS(typename B)>
-struct intersection<variant<BOOST_VARIANT_ENUM_PARAMS(A)>, variant<BOOST_VARIANT_ENUM_PARAMS(B)> >
+template <BOOST_VARIANT_ENUM_PARAMS(typename T1), BOOST_VARIANT_ENUM_PARAMS(typename T2)>
+struct intersection<variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, variant<BOOST_VARIANT_ENUM_PARAMS(T2)> >
{
template <typename GeometryOut>
struct visitor: static_visitor<bool>
@@ -255,8 +255,8 @@ struct intersection<variant<BOOST_VARIANT_ENUM_PARAMS(A)>, variant<BOOST_VARIANT
template <typename GeometryOut>
static inline bool
apply(
- const variant<BOOST_VARIANT_ENUM_PARAMS(A)>& geometry1,
- const variant<BOOST_VARIANT_ENUM_PARAMS(B)>& geometry2,
+ const variant<BOOST_VARIANT_ENUM_PARAMS(T1)>& geometry1,
+ const variant<BOOST_VARIANT_ENUM_PARAMS(T2)>& geometry2,
GeometryOut& geometry_out)
{
return apply_visitor(visitor<GeometryOut>(geometry_out), geometry1, geometry2);
diff --git a/boost/geometry/algorithms/detail/is_simple/areal.hpp b/boost/geometry/algorithms/detail/is_simple/areal.hpp
index 9a1a165..623632c 100644
--- a/boost/geometry/algorithms/detail/is_simple/areal.hpp
+++ b/boost/geometry/algorithms/detail/is_simple/areal.hpp
@@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2014, Oracle and/or its affiliates.
+// Copyright (c) 2014-2015, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
@@ -19,6 +19,7 @@
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/detail/check_iterator_range.hpp>
+#include <boost/geometry/algorithms/detail/is_simple/failure_policy.hpp>
#include <boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp>
#include <boost/geometry/algorithms/dispatch/is_simple.hpp>
@@ -38,11 +39,12 @@ struct is_simple_ring
{
static inline bool apply(Ring const& ring)
{
+ simplicity_failure_policy policy;
return
!detail::is_valid::has_duplicates
<
Ring, geometry::closure<Ring>::value
- >::apply(ring);
+ >::apply(ring, policy);
}
};
diff --git a/boost/geometry/algorithms/detail/is_simple/debug_print_boundary_points.hpp b/boost/geometry/algorithms/detail/is_simple/debug_print_boundary_points.hpp
index 75c37c6..196d89b 100644
--- a/boost/geometry/algorithms/detail/is_simple/debug_print_boundary_points.hpp
+++ b/boost/geometry/algorithms/detail/is_simple/debug_print_boundary_points.hpp
@@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2014, Oracle and/or its affiliates.
+// Copyright (c) 2014-2015, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
@@ -18,6 +18,8 @@
#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/util/range.hpp>
@@ -26,7 +28,8 @@
#include <boost/geometry/policies/compare.hpp>
#include <boost/geometry/algorithms/equals.hpp>
-#endif
+#include <boost/geometry/algorithms/not_implemented.hpp>
+#endif // BOOST_GEOMETRY_TEST_DEBUG
namespace boost { namespace geometry
@@ -37,39 +40,67 @@ namespace detail { namespace is_simple
#ifdef BOOST_GEOMETRY_TEST_DEBUG
-template <typename MultiLinestring>
-inline void debug_print_boundary_points(MultiLinestring const& multilinestring)
+template <typename Linear, typename Tag = typename tag<Linear>::type>
+struct debug_boundary_points_printer
+ : not_implemented<Linear>
+{};
+
+template <typename Linestring>
+struct debug_boundary_points_printer<Linestring, linestring_tag>
{
- typedef typename point_type<MultiLinestring>::type point_type;
- typedef std::vector<point_type> point_vector;
+ static inline void apply(Linestring const& linestring)
+ {
+ std::cout << "boundary points: ";
+ std::cout << " " << geometry::dsv(range::front(linestring));
+ std::cout << " " << geometry::dsv(range::back(linestring));
+ std::cout << std::endl << std::endl;
+ }
+};
- point_vector boundary_points;
- for (typename boost::range_iterator<MultiLinestring const>::type it
- = boost::begin(multilinestring);
- it != boost::end(multilinestring); ++it)
+template <typename MultiLinestring>
+struct debug_boundary_points_printer<MultiLinestring, multi_linestring_tag>
+{
+ static inline void apply(MultiLinestring const& multilinestring)
{
- if ( boost::size(*it) > 1
- && !geometry::equals(range::front(*it), range::back(*it)) )
+ typedef typename point_type<MultiLinestring>::type point_type;
+ typedef std::vector<point_type> point_vector;
+
+ point_vector boundary_points;
+ for (typename boost::range_iterator<MultiLinestring const>::type it
+ = boost::begin(multilinestring);
+ it != boost::end(multilinestring); ++it)
{
- boundary_points.push_back( range::front(*it) );
- boundary_points.push_back( range::back(*it) );
+ if ( boost::size(*it) > 1
+ && !geometry::equals(range::front(*it), range::back(*it)) )
+ {
+ boundary_points.push_back( range::front(*it) );
+ boundary_points.push_back( range::back(*it) );
+ }
}
- }
- std::sort(boundary_points.begin(), boundary_points.end(),
- geometry::less<point_type>());
+ std::sort(boundary_points.begin(), boundary_points.end(),
+ geometry::less<point_type>());
- std::cout << "boundary points: ";
- for (typename point_vector::const_iterator pit = boundary_points.begin();
- pit != boundary_points.end(); ++pit)
- {
- std::cout << " " << geometry::dsv(*pit);
+ std::cout << "boundary points: ";
+ for (typename point_vector::const_iterator
+ pit = boundary_points.begin();
+ pit != boundary_points.end(); ++pit)
+ {
+ std::cout << " " << geometry::dsv(*pit);
+ }
+ std::cout << std::endl << std::endl;
}
- std::cout << std::endl << std::endl;
+};
+
+
+template <typename Linear>
+inline void debug_print_boundary_points(Linear const& linear)
+{
+ debug_boundary_points_printer<Linear>::apply(linear);
}
#else
-template <typename MultiLinestring>
-inline void debug_print_boundary_points(MultiLinestring const&)
+template <typename Linear>
+inline void debug_print_boundary_points(Linear const&)
{
}
#endif // BOOST_GEOMETRY_TEST_DEBUG
diff --git a/boost/geometry/algorithms/detail/is_simple/failure_policy.hpp b/boost/geometry/algorithms/detail/is_simple/failure_policy.hpp
new file mode 100644
index 0000000..6504edd
--- /dev/null
+++ b/boost/geometry/algorithms/detail/is_simple/failure_policy.hpp
@@ -0,0 +1,53 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2015, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// Licensed under the Boost Software License version 1.0.
+// http://www.boost.org/users/license.html
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_FAILURE_POLICY_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_FAILURE_POLICY_HPP
+
+#include <boost/geometry/algorithms/validity_failure_type.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace is_simple
+{
+
+
+struct simplicity_failure_policy
+{
+ template <validity_failure_type Failure>
+ static inline bool apply()
+ {
+ return Failure == no_failure;
+ }
+
+ template <validity_failure_type Failure, typename Data>
+ static inline bool apply(Data const&)
+ {
+ return apply<Failure>();
+ }
+
+ template <validity_failure_type Failure, typename Data1, typename Data2>
+ static inline bool apply(Data1 const&, Data2 const&)
+ {
+ return apply<Failure>();
+ }
+};
+
+
+}} // namespace detail::is_simple
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_FAILURE_POLICY_HPP
diff --git a/boost/geometry/algorithms/detail/is_simple/interface.hpp b/boost/geometry/algorithms/detail/is_simple/interface.hpp
index 4239664..fd84826 100644
--- a/boost/geometry/algorithms/detail/is_simple/interface.hpp
+++ b/boost/geometry/algorithms/detail/is_simple/interface.hpp
@@ -10,8 +10,8 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_INTERFACE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_INTERFACE_HPP
-#include <boost/variant/static_visitor.hpp>
#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/static_visitor.hpp>
#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
diff --git a/boost/geometry/algorithms/detail/is_simple/linear.hpp b/boost/geometry/algorithms/detail/is_simple/linear.hpp
index f2efcb3..4f3e875 100644
--- a/boost/geometry/algorithms/detail/is_simple/linear.hpp
+++ b/boost/geometry/algorithms/detail/is_simple/linear.hpp
@@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2014, Oracle and/or its affiliates.
+// Copyright (c) 2014-2015, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
@@ -19,6 +19,7 @@
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/util/range.hpp>
@@ -29,8 +30,10 @@
#include <boost/geometry/algorithms/equals.hpp>
#include <boost/geometry/algorithms/intersects.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/algorithms/detail/check_iterator_range.hpp>
+#include <boost/geometry/algorithms/detail/signed_index_type.hpp>
#include <boost/geometry/algorithms/detail/disjoint/linear_linear.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
@@ -40,6 +43,7 @@
#include <boost/geometry/algorithms/detail/is_valid/has_spikes.hpp>
#include <boost/geometry/algorithms/detail/is_simple/debug_print_boundary_points.hpp>
+#include <boost/geometry/algorithms/detail/is_simple/failure_policy.hpp>
#include <boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp>
#include <boost/geometry/algorithms/dispatch/is_simple.hpp>
@@ -54,108 +58,211 @@ namespace detail { namespace is_simple
{
-template <typename Linestring, bool CheckSelfIntersections = true>
-struct is_simple_linestring
+template <typename Turn>
+inline bool check_segment_indices(Turn const& turn,
+ signed_index_type last_index)
{
- static inline bool apply(Linestring const& linestring)
+ return
+ (turn.operations[0].seg_id.segment_index == 0
+ && turn.operations[1].seg_id.segment_index == last_index)
+ ||
+ (turn.operations[0].seg_id.segment_index == 0
+ && turn.operations[1].seg_id.segment_index == last_index);
+}
+
+
+template <typename Geometry, typename Tag = typename tag<Geometry>::type>
+class is_acceptable_turn
+ : not_implemented<Geometry>
+{};
+
+template <typename Linestring>
+class is_acceptable_turn<Linestring, linestring_tag>
+{
+public:
+ is_acceptable_turn(Linestring const& linestring)
+ : m_linestring(linestring)
+ , m_is_closed(geometry::equals(range::front(linestring),
+ range::back(linestring)))
+ {}
+
+ template <typename Turn>
+ inline bool apply(Turn const& turn) const
{
- return !detail::is_valid::has_duplicates
- <
- Linestring, closed
- >::apply(linestring)
- && !detail::is_valid::has_spikes
- <
- Linestring, closed
- >::apply(linestring)
- && !(CheckSelfIntersections && geometry::intersects(linestring));
+ BOOST_ASSERT(boost::size(m_linestring) > 1);
+ return m_is_closed
+ && turn.method == overlay::method_none
+ && check_segment_indices(turn, boost::size(m_linestring) - 2)
+ && turn.operations[0].fraction.is_zero();
}
-};
-
+private:
+ Linestring const& m_linestring;
+ bool const m_is_closed;
+};
template <typename MultiLinestring>
-class is_simple_multilinestring
+class is_acceptable_turn<MultiLinestring, multi_linestring_tag>
{
private:
- class is_acceptable_turn
+ typedef typename boost::range_value<MultiLinestring>::type linestring_type;
+ typedef is_acceptable_turn<linestring_type> base_type;
+
+ template <typename Point, typename Linestring>
+ static inline bool is_boundary_point_of(Point const& point,
+ Linestring const& linestring)
{
- private:
- template <typename Point, typename Linestring>
- static inline bool is_boundary_point_of(Point const& point,
- Linestring const& linestring)
- {
- BOOST_ASSERT( boost::size(linestring) > 1 );
- return
- !geometry::equals(range::front(linestring),
- range::back(linestring))
- &&
- ( geometry::equals(point, range::front(linestring))
- || geometry::equals(point, range::back(linestring)) );
- }
+ BOOST_ASSERT(boost::size(linestring) > 1);
+ return
+ ! geometry::equals(range::front(linestring),
+ range::back(linestring))
+ &&
+ (geometry::equals(point, range::front(linestring))
+ || geometry::equals(point, range::back(linestring)));
+ }
+
+ template <typename Turn, typename Linestring>
+ static inline bool is_closing_point_of(Turn const& turn,
+ Linestring const& linestring)
+ {
+ BOOST_ASSERT(boost::size(linestring) > 1);
+ return
+ turn.method == overlay::method_none
+ &&
+ check_segment_indices(turn, boost::size(linestring) - 2)
+ &&
+ geometry::equals(range::front(linestring), range::back(linestring))
+ &&
+ turn.operations[0].fraction.is_zero();
+ ;
+ }
+
+ template <typename Linestring1, typename Linestring2>
+ static inline bool have_same_boundary_points(Linestring1 const& ls1,
+ Linestring2 const& ls2)
+ {
+ return
+ geometry::equals(range::front(ls1), range::front(ls2))
+ ?
+ geometry::equals(range::back(ls1), range::back(ls2))
+ :
+ (geometry::equals(range::front(ls1), range::back(ls2))
+ &&
+ geometry::equals(range::back(ls1), range::front(ls2)))
+ ;
+ }
+
+public:
+ is_acceptable_turn(MultiLinestring const& multilinestring)
+ : m_multilinestring(multilinestring)
+ {}
+
+ template <typename Turn>
+ inline bool apply(Turn const& turn) const
+ {
+ linestring_type const& ls1 =
+ range::at(m_multilinestring, turn.operations[0].seg_id.multi_index);
- template <typename Linestring1, typename Linestring2>
- static inline bool have_same_boundary_points(Linestring1 const& ls1,
- Linestring2 const& ls2)
+ linestring_type const& ls2 =
+ range::at(m_multilinestring, turn.operations[1].seg_id.multi_index);
+
+ if (turn.operations[0].seg_id.multi_index
+ == turn.operations[1].seg_id.multi_index)
{
- return
- geometry::equals(range::front(ls1), range::front(ls2))
- ?
- geometry::equals(range::back(ls1), range::back(ls2))
- :
- (geometry::equals(range::front(ls1), range::back(ls2))
- &&
- geometry::equals(range::back(ls1), range::front(ls2))
- )
- ;
+ return is_closing_point_of(turn, ls1);
}
- public:
- is_acceptable_turn(MultiLinestring const& multilinestring)
- : m_multilinestring(multilinestring)
- {}
+ return
+ is_boundary_point_of(turn.point, ls1)
+ && is_boundary_point_of(turn.point, ls2)
+ &&
+ ( boost::size(ls1) != 2
+ || boost::size(ls2) != 2
+ || ! have_same_boundary_points(ls1, ls2) );
+ }
- template <typename Turn>
- inline bool apply(Turn const& turn) const
- {
- typedef typename boost::range_value
+private:
+ MultiLinestring const& m_multilinestring;
+};
+
+
+template <typename Linear>
+inline bool has_self_intersections(Linear const& linear)
+{
+ typedef typename point_type<Linear>::type point_type;
+
+ // compute self turns
+ typedef detail::overlay::turn_info
+ <
+ point_type,
+ geometry::segment_ratio
<
- MultiLinestring
- >::type linestring;
-
- linestring const& ls1 =
- range::at(m_multilinestring,
- turn.operations[0].seg_id.multi_index);
-
- linestring const& ls2 =
- range::at(m_multilinestring,
- turn.operations[1].seg_id.multi_index);
-
- return
- is_boundary_point_of(turn.point, ls1)
- && is_boundary_point_of(turn.point, ls2)
- &&
- ( boost::size(ls1) != 2
- || boost::size(ls2) != 2
- || !have_same_boundary_points(ls1, ls2) );
- }
+ typename geometry::coordinate_type<point_type>::type
+ >
+ > turn_info;
- private:
- MultiLinestring const& m_multilinestring;
- };
+ std::deque<turn_info> turns;
+ typedef detail::overlay::get_turn_info
+ <
+ detail::disjoint::assign_disjoint_policy
+ > turn_policy;
-public:
- static inline bool apply(MultiLinestring const& multilinestring)
+ is_acceptable_turn<Linear> predicate(linear);
+ detail::overlay::predicate_based_interrupt_policy
+ <
+ is_acceptable_turn<Linear>
+ > interrupt_policy(predicate);
+
+ detail::self_get_turn_points::get_turns
+ <
+ turn_policy
+ >::apply(linear,
+ detail::no_rescale_policy(),
+ turns,
+ interrupt_policy);
+
+ detail::is_valid::debug_print_turns(turns.begin(), turns.end());
+ debug_print_boundary_points(linear);
+
+ return interrupt_policy.has_intersections;
+}
+
+
+template <typename Linestring, bool CheckSelfIntersections = true>
+struct is_simple_linestring
+{
+ static inline bool apply(Linestring const& linestring)
{
- typedef typename boost::range_value<MultiLinestring>::type linestring;
- typedef typename point_type<MultiLinestring>::type point_type;
- typedef point_type point;
+ simplicity_failure_policy policy;
+ return ! detail::is_valid::has_duplicates
+ <
+ Linestring, closed
+ >::apply(linestring, policy)
+ && ! detail::is_valid::has_spikes
+ <
+ Linestring, closed
+ >::apply(linestring, policy)
+ && ! (CheckSelfIntersections && has_self_intersections(linestring));
+ }
+};
+template <typename MultiLinestring>
+struct is_simple_multilinestring
+{
+ static inline bool apply(MultiLinestring const& multilinestring)
+ {
// check each of the linestrings for simplicity
- if ( !detail::check_iterator_range
+ // but do not compute self-intersections yet; these will be
+ // computed for the entire multilinestring
+ if ( ! detail::check_iterator_range
<
- is_simple_linestring<linestring>,
+ is_simple_linestring
+ <
+ typename boost::range_value<MultiLinestring>::type,
+ false // do not compute self-intersections
+ >,
false // do not allow empty multilinestring
>::apply(boost::begin(multilinestring),
boost::end(multilinestring))
@@ -164,44 +271,8 @@ public:
return false;
}
-
- // compute self turns
- typedef detail::overlay::turn_info
- <
- point_type,
- geometry::segment_ratio
- <
- typename geometry::coordinate_type<point>::type
- >
- > turn_info;
-
- std::deque<turn_info> turns;
-
- typedef detail::overlay::get_turn_info
- <
- detail::disjoint::assign_disjoint_policy
- > turn_policy;
-
- is_acceptable_turn predicate(multilinestring);
- detail::overlay::predicate_based_interrupt_policy
- <
- is_acceptable_turn
- > interrupt_policy(predicate);
-
- detail::self_get_turn_points::get_turns
- <
- turn_policy
- >::apply(multilinestring,
- detail::no_rescale_policy(),
- turns,
- interrupt_policy);
-
- detail::is_valid::debug_print_turns(turns.begin(), turns.end());
- debug_print_boundary_points(multilinestring);
-
- return !interrupt_policy.has_intersections;
+ return ! has_self_intersections(multilinestring);
}
-
};
diff --git a/boost/geometry/algorithms/detail/is_simple/multipoint.hpp b/boost/geometry/algorithms/detail/is_simple/multipoint.hpp
index d996eb6..71c9e6b 100644
--- a/boost/geometry/algorithms/detail/is_simple/multipoint.hpp
+++ b/boost/geometry/algorithms/detail/is_simple/multipoint.hpp
@@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2014, Oracle and/or its affiliates.
+// Copyright (c) 2014-2015, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
@@ -21,6 +21,7 @@
#include <boost/geometry/policies/compare.hpp>
#include <boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp>
+#include <boost/geometry/algorithms/detail/is_simple/failure_policy.hpp>
#include <boost/geometry/algorithms/dispatch/is_simple.hpp>
@@ -48,7 +49,11 @@ struct is_simple_multipoint
std::sort(boost::begin(mp), boost::end(mp),
geometry::less<typename point_type<MultiPoint>::type>());
- return !detail::is_valid::has_duplicates<MultiPoint, closed>::apply(mp);
+ simplicity_failure_policy policy;
+ return !detail::is_valid::has_duplicates
+ <
+ MultiPoint, closed
+ >::apply(mp, policy);
}
};
diff --git a/boost/geometry/algorithms/detail/is_valid/box.hpp b/boost/geometry/algorithms/detail/is_valid/box.hpp
index f82b3f9..139502a 100644
--- a/boost/geometry/algorithms/detail/is_valid/box.hpp
+++ b/boost/geometry/algorithms/detail/is_valid/box.hpp
@@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2014, Oracle and/or its affiliates.
+// Copyright (c) 2014-2015, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
@@ -16,6 +16,7 @@
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
+#include <boost/geometry/algorithms/validity_failure_type.hpp>
#include <boost/geometry/algorithms/dispatch/is_valid.hpp>
@@ -30,15 +31,22 @@ namespace detail { namespace is_valid
template <typename Box, std::size_t I>
struct has_valid_corners
{
- static inline bool apply(Box const& box)
+ template <typename VisitPolicy>
+ static inline bool apply(Box const& box, VisitPolicy& visitor)
{
- if ( geometry::get<geometry::max_corner, I-1>(box)
- <=
- geometry::get<geometry::min_corner, I-1>(box) )
+ if (math::equals(geometry::get<geometry::min_corner, I-1>(box),
+ geometry::get<geometry::max_corner, I-1>(box)))
{
- return false;
+ return
+ visitor.template apply<failure_wrong_topological_dimension>();
}
- return has_valid_corners<Box, I-1>::apply(box);
+ else if (geometry::get<geometry::min_corner, I-1>(box)
+ >
+ geometry::get<geometry::max_corner, I-1>(box))
+ {
+ return visitor.template apply<failure_wrong_corner_order>();
+ }
+ return has_valid_corners<Box, I-1>::apply(box, visitor);
}
};
@@ -46,9 +54,10 @@ struct has_valid_corners
template <typename Box>
struct has_valid_corners<Box, 0>
{
- static inline bool apply(Box const&)
+ template <typename VisitPolicy>
+ static inline bool apply(Box const&, VisitPolicy& visitor)
{
- return true;
+ return visitor.template apply<no_failure>();
}
};
diff --git a/boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp b/boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp
index 6824921..ab99a99 100644
--- a/boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp
+++ b/boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp
@@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2014, Oracle and/or its affiliates.
+// Copyright (c) 2014-2015, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
@@ -25,33 +25,47 @@ namespace detail { namespace is_valid
{
#ifdef BOOST_GEOMETRY_TEST_DEBUG
+template <typename Turn>
+inline void debug_print_turn(Turn const& turn)
+{
+ std::cout << " ["
+ << geometry::method_char(turn.method)
+ << ","
+ << geometry::operation_char(turn.operations[0].operation)
+ << "/"
+ << geometry::operation_char(turn.operations[1].operation)
+ << " {"
+ << turn.operations[0].seg_id.multi_index
+ << ", "
+ << turn.operations[1].seg_id.multi_index
+ << "} {"
+ << turn.operations[0].seg_id.ring_index
+ << ", "
+ << turn.operations[1].seg_id.ring_index
+ << "} {"
+ << turn.operations[0].seg_id.segment_index
+ << ", "
+ << turn.operations[1].seg_id.segment_index
+ << "} "
+ << geometry::dsv(turn.point)
+ << "]";
+}
+
template <typename TurnIterator>
inline void debug_print_turns(TurnIterator first, TurnIterator beyond)
{
std::cout << "turns:";
for (TurnIterator tit = first; tit != beyond; ++tit)
{
- std::cout << " ["
- << geometry::method_char(tit->method)
- << ","
- << geometry::operation_char(tit->operations[0].operation)
- << "/"
- << geometry::operation_char(tit->operations[1].operation)
- << " {"
- << tit->operations[0].seg_id.multi_index
- << ", "
- << tit->operations[1].seg_id.multi_index
- << "} {"
- << tit->operations[0].seg_id.ring_index
- << ", "
- << tit->operations[1].seg_id.ring_index
- << "} "
- << geometry::dsv(tit->point)
- << "]";
+ debug_print_turn(*tit);
}
std::cout << std::endl << std::endl;
}
#else
+template <typename Turn>
+inline void debug_print_turn(Turn const&)
+{}
+
template <typename TurnIterator>
inline void debug_print_turns(TurnIterator, TurnIterator)
{}
diff --git a/boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp b/boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp
index 6f1c263..a10e0fe 100644
--- a/boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp
+++ b/boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp
@@ -50,8 +50,8 @@ struct debug_validity_phase<Polygon, polygon_tag>
std::cout << "computing and analyzing turns..." << std::endl;
break;
case 4:
- std::cout << "checking if holes are inside the exterior ring..."
- << std::endl;
+ std::cout << "checking if interior rings are inside "
+ << "the exterior ring..." << std::endl;
break;
case 5:
std::cout << "checking connectivity of interior..." << std::endl;
diff --git a/boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp b/boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp
index dd0922b..5878841 100644
--- a/boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp
+++ b/boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp
@@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2014, Oracle and/or its affiliates.
+// Copyright (c) 2014-2015, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
@@ -15,8 +15,10 @@
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/policies/compare.hpp>
+#include <boost/geometry/policies/is_valid/default_policy.hpp>
#include <boost/geometry/views/closeable_view.hpp>
+#include <boost/geometry/algorithms/validity_failure_type.hpp>
namespace boost { namespace geometry
@@ -30,7 +32,8 @@ namespace detail { namespace is_valid
template <typename Range, closure_selector Closure>
struct has_duplicates
{
- static inline bool apply(Range const& range)
+ template <typename VisitPolicy>
+ static inline bool apply(Range const& range, VisitPolicy& visitor)
{
typedef typename closeable_view<Range const, Closure>::type view_type;
typedef typename boost::range_iterator<view_type const>::type iterator;
@@ -39,7 +42,7 @@ struct has_duplicates
if ( boost::size(view) < 2 )
{
- return false;
+ return ! visitor.template apply<no_failure>();
}
geometry::equal_to<typename boost::range_value<Range>::type> equal;
@@ -50,10 +53,10 @@ struct has_duplicates
{
if ( equal(*it, *next) )
{
- return true;
+ return ! visitor.template apply<failure_duplicate_points>(*it);
}
}
- return false;
+ return ! visitor.template apply<no_failure>();
}
};
diff --git a/boost/geometry/algorithms/detail/is_valid/has_spikes.hpp b/boost/geometry/algorithms/detail/is_valid/has_spikes.hpp
index 9b95017..090c026 100644
--- a/boost/geometry/algorithms/detail/is_valid/has_spikes.hpp
+++ b/boost/geometry/algorithms/detail/is_valid/has_spikes.hpp
@@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2014, Oracle and/or its affiliates.
+// Copyright (c) 2014-2015, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
@@ -13,15 +13,22 @@
#include <algorithm>
#include <boost/range.hpp>
+#include <boost/type_traits/is_same.hpp>
#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/policies/is_valid/default_policy.hpp>
#include <boost/geometry/util/range.hpp>
#include <boost/geometry/views/closeable_view.hpp>
#include <boost/geometry/algorithms/equals.hpp>
+#include <boost/geometry/algorithms/validity_failure_type.hpp>
#include <boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp>
+#include <boost/geometry/io/dsv/write.hpp>
namespace boost { namespace geometry
@@ -60,7 +67,7 @@ struct not_equal_to
template <typename OtherPoint>
inline bool operator()(OtherPoint const& other) const
{
- return !geometry::equals(other, m_point);
+ return ! geometry::equals(other, m_point);
}
};
@@ -69,13 +76,17 @@ struct not_equal_to
template <typename Range, closure_selector Closure>
struct has_spikes
{
- static inline bool apply(Range const& range)
+ template <typename VisitPolicy>
+ static inline bool apply(Range const& range, VisitPolicy& visitor)
{
typedef not_equal_to<typename point_type<Range>::type> not_equal;
typedef typename closeable_view<Range const, Closure>::type view_type;
typedef typename boost::range_iterator<view_type const>::type iterator;
+ bool const is_linear
+ = boost::is_same<typename tag<Range>::type, linestring_tag>::value;
+
view_type const view(range);
iterator prev = boost::begin(view);
@@ -85,7 +96,7 @@ struct has_spikes
{
// the range has only one distinct point, so it
// cannot have a spike
- return false;
+ return ! visitor.template apply<no_failure>();
}
iterator next = std::find_if(cur, boost::end(view), not_equal(*cur));
@@ -93,7 +104,7 @@ struct has_spikes
{
// the range has only two distinct points, so it
// cannot have a spike
- return false;
+ return ! visitor.template apply<no_failure>();
}
while ( next != boost::end(view) )
@@ -102,7 +113,8 @@ struct has_spikes
*next,
*cur) )
{
- return true;
+ return
+ ! visitor.template apply<failure_spikes>(is_linear, *cur);
}
prev = cur;
cur = next;
@@ -120,10 +132,18 @@ struct has_spikes
not_equal(range::back(view)));
iterator next =
std::find_if(cur, boost::end(view), not_equal(*cur));
- return detail::point_is_spike_or_equal(*prev, *next, *cur);
+ if (detail::point_is_spike_or_equal(*prev, *next, *cur))
+ {
+ return
+ ! visitor.template apply<failure_spikes>(is_linear, *cur);
+ }
+ else
+ {
+ return ! visitor.template apply<no_failure>();
+ }
}
- return false;
+ return ! visitor.template apply<no_failure>();
}
};
diff --git a/boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp b/boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp
index 220a67b..ecbc478 100644
--- a/boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp
+++ b/boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp
@@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2014, Oracle and/or its affiliates.
+// Copyright (c) 2014-2015, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
@@ -10,6 +10,11 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_VALID_SELF_TURNS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_VALID_SELF_TURNS_HPP
+#include <vector>
+
+#include <boost/assert.hpp>
+#include <boost/range.hpp>
+
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/policies/predicate_based_interrupt_policy.hpp>
@@ -22,7 +27,6 @@
#include <boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp>
-
namespace boost { namespace geometry
{
@@ -64,8 +68,10 @@ public:
> turn_type;
// returns true if all turns are valid
- template <typename Turns>
- static inline bool apply(Geometry const& geometry, Turns& turns)
+ template <typename Turns, typename VisitPolicy>
+ static inline bool apply(Geometry const& geometry,
+ Turns& turns,
+ VisitPolicy& visitor)
{
rescale_policy_type robust_policy
= geometry::get_rescale_policy<rescale_policy_type>(geometry);
@@ -80,7 +86,23 @@ public:
turns,
interrupt_policy);
- return !interrupt_policy.has_intersections;
+ if (interrupt_policy.has_intersections)
+ {
+ BOOST_ASSERT(! boost::empty(turns));
+ return visitor.template apply<failure_self_intersections>(turns);
+ }
+ else
+ {
+ return visitor.template apply<no_failure>();
+ }
+ }
+
+ // returns true if all turns are valid
+ template <typename VisitPolicy>
+ static inline bool apply(Geometry const& geometry, VisitPolicy& visitor)
+ {
+ std::vector<turn_type> turns;
+ return apply(geometry, turns, visitor);
}
};
diff --git a/boost/geometry/algorithms/detail/is_valid/interface.hpp b/boost/geometry/algorithms/detail/is_valid/interface.hpp
index 4b232fd..f83b09c 100644
--- a/boost/geometry/algorithms/detail/is_valid/interface.hpp
+++ b/boost/geometry/algorithms/detail/is_valid/interface.hpp
@@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2014, Oracle and/or its affiliates.
+// Copyright (c) 2014-2015, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
@@ -10,13 +10,19 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_INTERFACE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_INTERFACE_HPP
-#include <boost/variant/static_visitor.hpp>
+#include <sstream>
+#include <string>
+
#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/static_visitor.hpp>
#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/algorithms/dispatch/is_valid.hpp>
+#include <boost/geometry/policies/is_valid/default_policy.hpp>
+#include <boost/geometry/policies/is_valid/failing_reason_policy.hpp>
+#include <boost/geometry/policies/is_valid/failure_type_policy.hpp>
namespace boost { namespace geometry
@@ -28,48 +34,123 @@ namespace resolve_variant {
template <typename Geometry>
struct is_valid
{
- static inline bool apply(Geometry const& geometry)
+ template <typename VisitPolicy>
+ static inline bool apply(Geometry const& geometry, VisitPolicy& visitor)
{
concept::check<Geometry const>();
- return dispatch::is_valid<Geometry>::apply(geometry);
+ return dispatch::is_valid<Geometry>::apply(geometry, visitor);
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct is_valid<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
{
+ template <typename VisitPolicy>
struct visitor : boost::static_visitor<bool>
{
+ visitor(VisitPolicy& policy) : m_policy(policy) {}
+
template <typename Geometry>
bool operator()(Geometry const& geometry) const
{
- return is_valid<Geometry>::apply(geometry);
+ return is_valid<Geometry>::apply(geometry, m_policy);
}
+
+ VisitPolicy& m_policy;
};
+ template <typename VisitPolicy>
static inline bool
- apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry)
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
+ VisitPolicy& policy_visitor)
{
- return boost::apply_visitor(visitor(), geometry);
+ return boost::apply_visitor(visitor<VisitPolicy>(policy_visitor),
+ geometry);
}
};
} // namespace resolve_variant
+// Undocumented for now
+template <typename Geometry, typename VisitPolicy>
+inline bool is_valid(Geometry const& geometry, VisitPolicy& visitor)
+{
+ return resolve_variant::is_valid<Geometry>::apply(geometry, visitor);
+}
+
+
/*!
\brief \brief_check{is valid (in the OGC sense)}
\ingroup is_valid
\tparam Geometry \tparam_geometry
\param geometry \param_geometry
-\return \return_check{is valid (in the OGC sense)}
+\return \return_check{is valid (in the OGC sense);
+ furthermore, the following geometries are considered valid:
+ multi-geometries with no elements,
+ linear geometries containing spikes,
+ areal geometries with duplicate (consecutive) points}
\qbk{[include reference/algorithms/is_valid.qbk]}
*/
template <typename Geometry>
inline bool is_valid(Geometry const& geometry)
{
- return resolve_variant::is_valid<Geometry>::apply(geometry);
+ is_valid_default_policy<> policy_visitor;
+ return is_valid(geometry, policy_visitor);
+}
+
+
+/*!
+\brief \brief_check{is valid (in the OGC sense)}
+\ingroup is_valid
+\tparam Geometry \tparam_geometry
+\param geometry \param_geometry
+\param failure An enumeration value indicating that the geometry is
+ valid or not, and if not valid indicating the reason why
+\return \return_check{is valid (in the OGC sense);
+ furthermore, the following geometries are considered valid:
+ multi-geometries with no elements,
+ linear geometries containing spikes,
+ areal geometries with duplicate (consecutive) points}
+
+\qbk{distinguish,with failure value}
+\qbk{[include reference/algorithms/is_valid_with_failure.qbk]}
+*/
+template <typename Geometry>
+inline bool is_valid(Geometry const& geometry, validity_failure_type& failure)
+{
+ failure_type_policy<> policy_visitor;
+ bool result = is_valid(geometry, policy_visitor);
+ failure = policy_visitor.failure();
+ return result;
+}
+
+
+/*!
+\brief \brief_check{is valid (in the OGC sense)}
+\ingroup is_valid
+\tparam Geometry \tparam_geometry
+\param geometry \param_geometry
+\param message A string containing a message stating if the geometry
+ is valid or not, and if not valid a reason why
+\return \return_check{is valid (in the OGC sense);
+ furthermore, the following geometries are considered valid:
+ multi-geometries with no elements,
+ linear geometries containing spikes,
+ areal geometries with duplicate (consecutive) points}
+
+\qbk{distinguish,with message}
+\qbk{[include reference/algorithms/is_valid_with_message.qbk]}
+*/
+template <typename Geometry>
+inline bool is_valid(Geometry const& geometry, std::string& message)
+{
+ std::ostringstream stream;
+ failing_reason_policy<> policy_visitor(stream);
+ bool result = is_valid(geometry, policy_visitor);
+ message = stream.str();
+ return result;
}
diff --git a/boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp b/boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp
index f9d9267..0d80d6f 100644
--- a/boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp
+++ b/boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp
@@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2014, Oracle and/or its affiliates.
+// Copyright (c) 2014-2015, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
@@ -72,6 +72,16 @@ template <typename Geometry, typename Tag = typename tag<Geometry>::type>
struct is_acceptable_turn
{};
+template <typename Ring>
+struct is_acceptable_turn<Ring, ring_tag>
+{
+ template <typename Turn>
+ static inline bool apply(Turn const&)
+ {
+ return false;
+ }
+};
+
template <typename Polygon>
class is_acceptable_turn<Polygon, polygon_tag>
{
diff --git a/boost/geometry/algorithms/detail/is_valid/linear.hpp b/boost/geometry/algorithms/detail/is_valid/linear.hpp
index 244df9b..6924356 100644
--- a/boost/geometry/algorithms/detail/is_valid/linear.hpp
+++ b/boost/geometry/algorithms/detail/is_valid/linear.hpp
@@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2014, Oracle and/or its affiliates.
+// Copyright (c) 2014-2015, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
@@ -21,6 +21,7 @@
#include <boost/geometry/util/range.hpp>
#include <boost/geometry/algorithms/equals.hpp>
+#include <boost/geometry/algorithms/validity_failure_type.hpp>
#include <boost/geometry/algorithms/detail/check_iterator_range.hpp>
#include <boost/geometry/algorithms/detail/is_valid/has_spikes.hpp>
#include <boost/geometry/algorithms/detail/num_distinct_consecutive_points.hpp>
@@ -36,11 +37,18 @@ namespace detail { namespace is_valid
{
-template <typename Linestring, bool AllowSpikes>
+template <typename Linestring>
struct is_valid_linestring
{
- static inline bool apply(Linestring const& linestring)
+ template <typename VisitPolicy>
+ static inline bool apply(Linestring const& linestring,
+ VisitPolicy& visitor)
{
+ if (boost::size(linestring) < 2)
+ {
+ return visitor.template apply<failure_few_points>();
+ }
+
std::size_t num_distinct = detail::num_distinct_consecutive_points
<
Linestring,
@@ -49,14 +57,17 @@ struct is_valid_linestring
not_equal_to<typename point_type<Linestring>::type>
>::apply(linestring);
- if ( num_distinct < 2u )
+ if (num_distinct < 2u)
{
- return false;
+ return
+ visitor.template apply<failure_wrong_topological_dimension>();
}
- return num_distinct == 2u
- || AllowSpikes
- || !has_spikes<Linestring, closed>::apply(linestring);
+ if (num_distinct == 2u)
+ {
+ return visitor.template apply<no_failure>();
+ }
+ return ! has_spikes<Linestring, closed>::apply(linestring, visitor);
}
};
@@ -84,9 +95,11 @@ namespace dispatch
// By default, spikes are disallowed
//
// Reference: OGC 06-103r4 (6.1.6.1)
-template <typename Linestring, bool AllowSpikes>
-struct is_valid<Linestring, linestring_tag, AllowSpikes>
- : detail::is_valid::is_valid_linestring<Linestring, AllowSpikes>
+template <typename Linestring, bool AllowEmptyMultiGeometries>
+struct is_valid
+ <
+ Linestring, linestring_tag, AllowEmptyMultiGeometries
+ > : detail::is_valid::is_valid_linestring<Linestring>
{};
@@ -96,21 +109,47 @@ struct is_valid<Linestring, linestring_tag, AllowSpikes>
// are on the boundaries of both elements.
//
// Reference: OGC 06-103r4 (6.1.8.1; Fig. 9)
-template <typename MultiLinestring, bool AllowSpikes>
-struct is_valid<MultiLinestring, multi_linestring_tag, AllowSpikes>
+template <typename MultiLinestring, bool AllowEmptyMultiGeometries>
+class is_valid
+ <
+ MultiLinestring, multi_linestring_tag, AllowEmptyMultiGeometries
+ >
{
- static inline bool apply(MultiLinestring const& multilinestring)
+private:
+ template <typename VisitPolicy>
+ struct per_linestring
+ {
+ per_linestring(VisitPolicy& policy) : m_policy(policy) {}
+
+ template <typename Linestring>
+ inline bool apply(Linestring const& linestring) const
+ {
+ return detail::is_valid::is_valid_linestring
+ <
+ Linestring
+ >::apply(linestring, m_policy);
+ }
+
+ VisitPolicy& m_policy;
+ };
+
+public:
+ template <typename VisitPolicy>
+ static inline bool apply(MultiLinestring const& multilinestring,
+ VisitPolicy& visitor)
{
+ if (AllowEmptyMultiGeometries && boost::empty(multilinestring))
+ {
+ return visitor.template apply<no_failure>();
+ }
+
return detail::check_iterator_range
<
- detail::is_valid::is_valid_linestring
- <
- typename boost::range_value<MultiLinestring>::type,
- AllowSpikes
- >,
- false // do not allow empty multilinestring
+ per_linestring<VisitPolicy>,
+ false // do not check for empty multilinestring (done above)
>::apply(boost::begin(multilinestring),
- boost::end(multilinestring));
+ boost::end(multilinestring),
+ per_linestring<VisitPolicy>(visitor));
}
};
diff --git a/boost/geometry/algorithms/detail/is_valid/multipolygon.hpp b/boost/geometry/algorithms/detail/is_valid/multipolygon.hpp
index 3d0ebb5..9362bfca 100644
--- a/boost/geometry/algorithms/detail/is_valid/multipolygon.hpp
+++ b/boost/geometry/algorithms/detail/is_valid/multipolygon.hpp
@@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2014, Oracle and/or its affiliates.
+// Copyright (c) 2014-2015, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
@@ -25,6 +25,7 @@
#include <boost/geometry/geometries/box.hpp>
+#include <boost/geometry/algorithms/validity_failure_type.hpp>
#include <boost/geometry/algorithms/within.hpp>
#include <boost/geometry/algorithms/detail/check_iterator_range.hpp>
@@ -49,12 +50,11 @@ namespace detail { namespace is_valid
{
-template <typename MultiPolygon, bool AllowDuplicates>
+template <typename MultiPolygon, bool AllowEmptyMultiGeometries>
class is_valid_multipolygon
: is_valid_polygon
<
typename boost::range_value<MultiPolygon>::type,
- AllowDuplicates,
true // check only the validity of rings
>
{
@@ -62,18 +62,23 @@ private:
typedef is_valid_polygon
<
typename boost::range_value<MultiPolygon>::type,
- AllowDuplicates,
true
> base;
- template <typename PolygonIterator, typename TurnIterator>
+ template
+ <
+ typename PolygonIterator,
+ typename TurnIterator,
+ typename VisitPolicy
+ >
static inline
bool are_polygon_interiors_disjoint(PolygonIterator polygons_first,
PolygonIterator polygons_beyond,
TurnIterator turns_first,
- TurnIterator turns_beyond)
+ TurnIterator turns_beyond,
+ VisitPolicy& visitor)
{
// collect all polygons that have turns
std::set<signed_index_type> multi_indices;
@@ -89,22 +94,29 @@ private:
for (PolygonIterator it = polygons_first; it != polygons_beyond;
++it, ++multi_index)
{
- if ( multi_indices.find(multi_index) == multi_indices.end() )
+ if (multi_indices.find(multi_index) == multi_indices.end())
{
polygon_iterators.push_back(it);
}
}
- typename base::item_visitor visitor;
+ typename base::item_visitor_type item_visitor;
geometry::partition
<
geometry::model::box<typename point_type<MultiPolygon>::type>,
typename base::expand_box,
typename base::overlaps_box
- >::apply(polygon_iterators, visitor);
+ >::apply(polygon_iterators, item_visitor);
- return !visitor.items_overlap;
+ if (item_visitor.items_overlap)
+ {
+ return visitor.template apply<failure_intersecting_interiors>();
+ }
+ else
+ {
+ return visitor.template apply<no_failure>();
+ }
}
@@ -132,11 +144,17 @@ private:
template <typename Predicate>
struct has_property_per_polygon
{
- template <typename PolygonIterator, typename TurnIterator>
+ template
+ <
+ typename PolygonIterator,
+ typename TurnIterator,
+ typename VisitPolicy
+ >
static inline bool apply(PolygonIterator polygons_first,
PolygonIterator polygons_beyond,
TurnIterator turns_first,
- TurnIterator turns_beyond)
+ TurnIterator turns_beyond,
+ VisitPolicy& visitor)
{
signed_index_type multi_index = 0;
for (PolygonIterator it = polygons_first; it != polygons_beyond;
@@ -157,9 +175,10 @@ private:
turns_beyond,
turns_beyond);
- if ( !Predicate::apply(*it,
+ if (! Predicate::apply(*it,
filtered_turns_first,
- filtered_turns_beyond) )
+ filtered_turns_beyond,
+ visitor))
{
return false;
}
@@ -170,49 +189,82 @@ private:
- template <typename PolygonIterator, typename TurnIterator>
+ template
+ <
+ typename PolygonIterator,
+ typename TurnIterator,
+ typename VisitPolicy
+ >
static inline bool have_holes_inside(PolygonIterator polygons_first,
PolygonIterator polygons_beyond,
TurnIterator turns_first,
- TurnIterator turns_beyond)
+ TurnIterator turns_beyond,
+ VisitPolicy& visitor)
{
return has_property_per_polygon
<
typename base::has_holes_inside
>::apply(polygons_first, polygons_beyond,
- turns_first, turns_beyond);
+ turns_first, turns_beyond, visitor);
}
- template <typename PolygonIterator, typename TurnIterator>
+ template
+ <
+ typename PolygonIterator,
+ typename TurnIterator,
+ typename VisitPolicy
+ >
static inline bool have_connected_interior(PolygonIterator polygons_first,
PolygonIterator polygons_beyond,
TurnIterator turns_first,
- TurnIterator turns_beyond)
+ TurnIterator turns_beyond,
+ VisitPolicy& visitor)
{
return has_property_per_polygon
<
typename base::has_connected_interior
>::apply(polygons_first, polygons_beyond,
- turns_first, turns_beyond);
+ turns_first, turns_beyond, visitor);
}
+ template <typename VisitPolicy>
+ struct per_polygon
+ {
+ per_polygon(VisitPolicy& policy) : m_policy(policy) {}
+
+ template <typename Polygon>
+ inline bool apply(Polygon const& polygon) const
+ {
+ return base::apply(polygon, m_policy);
+ }
+
+ VisitPolicy& m_policy;
+ };
public:
- static inline bool apply(MultiPolygon const& multipolygon)
+ template <typename VisitPolicy>
+ static inline bool apply(MultiPolygon const& multipolygon,
+ VisitPolicy& visitor)
{
typedef debug_validity_phase<MultiPolygon> debug_phase;
+ if (AllowEmptyMultiGeometries && boost::empty(multipolygon))
+ {
+ return visitor.template apply<no_failure>();
+ }
+
// check validity of all polygons ring
debug_phase::apply(1);
- if ( !detail::check_iterator_range
+ if (! detail::check_iterator_range
<
- base,
- false // do not allow empty multi-polygons
+ per_polygon<VisitPolicy>,
+ false // do not check for empty multipolygon (done above)
>::apply(boost::begin(multipolygon),
- boost::end(multipolygon)) )
+ boost::end(multipolygon),
+ per_polygon<VisitPolicy>(visitor)))
{
return false;
}
@@ -224,10 +276,11 @@ public:
typedef has_valid_self_turns<MultiPolygon> has_valid_turns;
std::deque<typename has_valid_turns::turn_type> turns;
- bool has_invalid_turns = !has_valid_turns::apply(multipolygon, turns);
+ bool has_invalid_turns =
+ ! has_valid_turns::apply(multipolygon, turns, visitor);
debug_print_turns(turns.begin(), turns.end());
- if ( has_invalid_turns )
+ if (has_invalid_turns)
{
return false;
}
@@ -237,10 +290,11 @@ public:
// exterior and not one inside the other
debug_phase::apply(3);
- if ( !have_holes_inside(boost::begin(multipolygon),
+ if (! have_holes_inside(boost::begin(multipolygon),
boost::end(multipolygon),
turns.begin(),
- turns.end()) )
+ turns.end(),
+ visitor))
{
return false;
}
@@ -249,10 +303,11 @@ public:
// check that each polygon's interior is connected
debug_phase::apply(4);
- if ( !have_connected_interior(boost::begin(multipolygon),
+ if (! have_connected_interior(boost::begin(multipolygon),
boost::end(multipolygon),
turns.begin(),
- turns.end()) )
+ turns.end(),
+ visitor))
{
return false;
}
@@ -263,7 +318,8 @@ public:
return are_polygon_interiors_disjoint(boost::begin(multipolygon),
boost::end(multipolygon),
turns.begin(),
- turns.end());
+ turns.end(),
+ visitor);
}
};
@@ -282,9 +338,14 @@ namespace dispatch
// that the MultiPolygon is also valid.
//
// Reference (for validity of MultiPolygons): OGC 06-103r4 (6.1.14)
-template <typename MultiPolygon, bool AllowSpikes, bool AllowDuplicates>
-struct is_valid<MultiPolygon, multi_polygon_tag, AllowSpikes, AllowDuplicates>
- : detail::is_valid::is_valid_multipolygon<MultiPolygon, AllowDuplicates>
+template <typename MultiPolygon, bool AllowEmptyMultiGeometries>
+struct is_valid
+ <
+ MultiPolygon, multi_polygon_tag, AllowEmptyMultiGeometries
+ > : detail::is_valid::is_valid_multipolygon
+ <
+ MultiPolygon, AllowEmptyMultiGeometries
+ >
{};
diff --git a/boost/geometry/algorithms/detail/is_valid/pointlike.hpp b/boost/geometry/algorithms/detail/is_valid/pointlike.hpp
index 8a4818e..8e5ebaa 100644
--- a/boost/geometry/algorithms/detail/is_valid/pointlike.hpp
+++ b/boost/geometry/algorithms/detail/is_valid/pointlike.hpp
@@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2014, Oracle and/or its affiliates.
+// Copyright (c) 2014-2015, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
@@ -14,6 +14,7 @@
#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/algorithms/validity_failure_type.hpp>
#include <boost/geometry/algorithms/dispatch/is_valid.hpp>
@@ -30,9 +31,10 @@ namespace dispatch
template <typename Point>
struct is_valid<Point, point_tag>
{
- static inline bool apply(Point const&)
+ template <typename VisitPolicy>
+ static inline bool apply(Point const&, VisitPolicy& visitor)
{
- return true;
+ return visitor.template apply<no_failure>();
}
};
@@ -42,12 +44,24 @@ struct is_valid<Point, point_tag>
// (have identical coordinate values in X and Y)
//
// Reference: OGC 06-103r4 (6.1.5)
-template <typename MultiPoint>
-struct is_valid<MultiPoint, multi_point_tag>
+template <typename MultiPoint, bool AllowEmptyMultiGeometries>
+struct is_valid<MultiPoint, multi_point_tag, AllowEmptyMultiGeometries>
{
- static inline bool apply(MultiPoint const& multipoint)
+ template <typename VisitPolicy>
+ static inline bool apply(MultiPoint const& multipoint,
+ VisitPolicy& visitor)
{
- return boost::size(multipoint) > 0;
+ if (AllowEmptyMultiGeometries || boost::size(multipoint) > 0)
+ {
+ // we allow empty multi-geometries, so an empty multipoint
+ // is considered valid
+ return visitor.template apply<no_failure>();
+ }
+ else
+ {
+ // we do not allow an empty multipoint
+ return visitor.template apply<failure_few_points>();
+ }
}
};
diff --git a/boost/geometry/algorithms/detail/is_valid/polygon.hpp b/boost/geometry/algorithms/detail/is_valid/polygon.hpp
index 3a91999..17eefd2 100644
--- a/boost/geometry/algorithms/detail/is_valid/polygon.hpp
+++ b/boost/geometry/algorithms/detail/is_valid/polygon.hpp
@@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2014, Oracle and/or its affiliates.
+// Copyright (c) 2014-2015, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
@@ -26,6 +26,7 @@
#include <boost/geometry/core/ring_type.hpp>
#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/util/condition.hpp>
#include <boost/geometry/util/range.hpp>
#include <boost/geometry/geometries/box.hpp>
@@ -36,6 +37,7 @@
#include <boost/geometry/algorithms/disjoint.hpp>
#include <boost/geometry/algorithms/expand.hpp>
#include <boost/geometry/algorithms/num_interior_rings.hpp>
+#include <boost/geometry/algorithms/validity_failure_type.hpp>
#include <boost/geometry/algorithms/within.hpp>
#include <boost/geometry/algorithms/detail/check_iterator_range.hpp>
@@ -62,51 +64,58 @@ namespace detail { namespace is_valid
{
-template
-<
- typename Polygon,
- bool AllowDuplicates,
- bool CheckRingValidityOnly = false
->
+template <typename Polygon, bool CheckRingValidityOnly = false>
class is_valid_polygon
{
protected:
typedef debug_validity_phase<Polygon> debug_phase;
+ template <typename VisitPolicy>
+ struct per_ring
+ {
+ per_ring(VisitPolicy& policy) : m_policy(policy) {}
+
+ template <typename Ring>
+ inline bool apply(Ring const& ring) const
+ {
+ return detail::is_valid::is_valid_ring
+ <
+ Ring, false, true
+ >::apply(ring, m_policy);
+ }
+ VisitPolicy& m_policy;
+ };
- template <typename InteriorRings>
- static bool has_valid_interior_rings(InteriorRings const& interior_rings)
+ template <typename InteriorRings, typename VisitPolicy>
+ static bool has_valid_interior_rings(InteriorRings const& interior_rings,
+ VisitPolicy& visitor)
{
return
detail::check_iterator_range
<
- detail::is_valid::is_valid_ring
- <
- typename boost::range_value<InteriorRings>::type,
- AllowDuplicates,
- false, // do not check self-intersections
- true // indicate that the ring is interior
- >
+ per_ring<VisitPolicy>,
+ true // allow for empty interior ring range
>::apply(boost::begin(interior_rings),
- boost::end(interior_rings));
+ boost::end(interior_rings),
+ per_ring<VisitPolicy>(visitor));
}
struct has_valid_rings
{
- static inline bool apply(Polygon const& polygon)
+ template <typename VisitPolicy>
+ static inline bool apply(Polygon const& polygon, VisitPolicy& visitor)
{
typedef typename ring_type<Polygon>::type ring_type;
// check validity of exterior ring
debug_phase::apply(1);
- if ( !detail::is_valid::is_valid_ring
+ if (! detail::is_valid::is_valid_ring
<
ring_type,
- AllowDuplicates,
false // do not check self intersections
- >::apply(exterior_ring(polygon)) )
+ >::apply(exterior_ring(polygon), visitor))
{
return false;
}
@@ -114,12 +123,13 @@ protected:
// check validity of interior rings
debug_phase::apply(2);
- return has_valid_interior_rings(geometry::interior_rings(polygon));
+ return has_valid_interior_rings(geometry::interior_rings(polygon),
+ visitor);
}
};
- // structs from partition -- start
+ // structs for partition -- start
struct expand_box
{
template <typename Box, typename Iterator>
@@ -135,24 +145,24 @@ protected:
template <typename Box, typename Iterator>
static inline bool apply(Box const& box, Iterator const& it)
{
- return !geometry::disjoint(*it, box);
+ return ! geometry::disjoint(*it, box);
}
};
- struct item_visitor
+ struct item_visitor_type
{
bool items_overlap;
- item_visitor() : items_overlap(false) {}
+ item_visitor_type() : items_overlap(false) {}
template <typename Item1, typename Item2>
inline void apply(Item1 const& item1, Item2 const& item2)
{
- if ( !items_overlap
- && (geometry::within(*points_begin(*item1), *item2)
- || geometry::within(*points_begin(*item2), *item1))
- )
+ if (! items_overlap
+ && (geometry::within(*points_begin(*item1), *item2)
+ || geometry::within(*points_begin(*item2), *item1))
+ )
{
items_overlap = true;
}
@@ -165,27 +175,29 @@ protected:
<
typename RingIterator,
typename ExteriorRing,
- typename TurnIterator
+ typename TurnIterator,
+ typename VisitPolicy
>
static inline bool are_holes_inside(RingIterator rings_first,
RingIterator rings_beyond,
ExteriorRing const& exterior_ring,
TurnIterator turns_first,
- TurnIterator turns_beyond)
+ TurnIterator turns_beyond,
+ VisitPolicy& visitor)
{
// collect the interior ring indices that have turns with the
// exterior ring
std::set<signed_index_type> ring_indices;
for (TurnIterator tit = turns_first; tit != turns_beyond; ++tit)
{
- if ( tit->operations[0].seg_id.ring_index == -1 )
+ if (tit->operations[0].seg_id.ring_index == -1)
{
- BOOST_ASSERT( tit->operations[1].seg_id.ring_index != -1 );
+ BOOST_ASSERT(tit->operations[1].seg_id.ring_index != -1);
ring_indices.insert(tit->operations[1].seg_id.ring_index);
}
- else if ( tit->operations[1].seg_id.ring_index == -1 )
+ else if (tit->operations[1].seg_id.ring_index == -1)
{
- BOOST_ASSERT( tit->operations[0].seg_id.ring_index != -1 );
+ BOOST_ASSERT(tit->operations[0].seg_id.ring_index != -1);
ring_indices.insert(tit->operations[0].seg_id.ring_index);
}
}
@@ -196,10 +208,10 @@ protected:
{
// do not examine interior rings that have turns with the
// exterior ring
- if ( ring_indices.find(ring_index) == ring_indices.end()
- && !geometry::covered_by(range::front(*it), exterior_ring) )
+ if (ring_indices.find(ring_index) == ring_indices.end()
+ && ! geometry::covered_by(range::front(*it), exterior_ring))
{
- return false;
+ return visitor.template apply<failure_interior_rings_outside>();
}
}
@@ -216,7 +228,7 @@ protected:
for (RingIterator it = rings_first; it != rings_beyond;
++it, ++ring_index)
{
- if ( ring_indices.find(ring_index) == ring_indices.end() )
+ if (ring_indices.find(ring_index) == ring_indices.end())
{
ring_iterators.push_back(it);
}
@@ -224,47 +236,59 @@ protected:
// call partition to check is interior rings are disjoint from
// each other
- item_visitor visitor;
+ item_visitor_type item_visitor;
geometry::partition
<
geometry::model::box<typename point_type<Polygon>::type>,
expand_box,
overlaps_box
- >::apply(ring_iterators, visitor);
+ >::apply(ring_iterators, item_visitor);
- return !visitor.items_overlap;
+ if (item_visitor.items_overlap)
+ {
+ return visitor.template apply<failure_nested_interior_rings>();
+ }
+ else
+ {
+ return visitor.template apply<no_failure>();
+ }
}
template
<
typename InteriorRings,
typename ExteriorRing,
- typename TurnIterator
+ typename TurnIterator,
+ typename VisitPolicy
>
static inline bool are_holes_inside(InteriorRings const& interior_rings,
ExteriorRing const& exterior_ring,
TurnIterator first,
- TurnIterator beyond)
+ TurnIterator beyond,
+ VisitPolicy& visitor)
{
return are_holes_inside(boost::begin(interior_rings),
boost::end(interior_rings),
exterior_ring,
first,
- beyond);
+ beyond,
+ visitor);
}
struct has_holes_inside
{
- template <typename TurnIterator>
+ template <typename TurnIterator, typename VisitPolicy>
static inline bool apply(Polygon const& polygon,
TurnIterator first,
- TurnIterator beyond)
+ TurnIterator beyond,
+ VisitPolicy& visitor)
{
return are_holes_inside(geometry::interior_rings(polygon),
geometry::exterior_ring(polygon),
first,
- beyond);
+ beyond,
+ visitor);
}
};
@@ -273,10 +297,11 @@ protected:
struct has_connected_interior
{
- template <typename TurnIterator>
+ template <typename TurnIterator, typename VisitPolicy>
static inline bool apply(Polygon const& polygon,
TurnIterator first,
- TurnIterator beyond)
+ TurnIterator beyond,
+ VisitPolicy& visitor)
{
typedef typename std::iterator_traits
<
@@ -299,19 +324,27 @@ protected:
debug_print_complement_graph(std::cout, g);
- return !g.has_cycles();
+ if (g.has_cycles())
+ {
+ return visitor.template apply<failure_disconnected_interior>();
+ }
+ else
+ {
+ return visitor.template apply<no_failure>();
+ }
}
};
public:
- static inline bool apply(Polygon const& polygon)
+ template <typename VisitPolicy>
+ static inline bool apply(Polygon const& polygon, VisitPolicy& visitor)
{
- if ( !has_valid_rings::apply(polygon) )
+ if (! has_valid_rings::apply(polygon, visitor))
{
return false;
}
- if ( CheckRingValidityOnly )
+ if (BOOST_GEOMETRY_CONDITION(CheckRingValidityOnly))
{
return true;
}
@@ -322,10 +355,11 @@ public:
typedef has_valid_self_turns<Polygon> has_valid_turns;
std::deque<typename has_valid_turns::turn_type> turns;
- bool has_invalid_turns = !has_valid_turns::apply(polygon, turns);
+ bool has_invalid_turns
+ = ! has_valid_turns::apply(polygon, turns, visitor);
debug_print_turns(turns.begin(), turns.end());
- if ( has_invalid_turns )
+ if (has_invalid_turns)
{
return false;
}
@@ -333,7 +367,9 @@ public:
// check if all interior rings are inside the exterior ring
debug_phase::apply(4);
- if ( !has_holes_inside::apply(polygon, turns.begin(), turns.end()) )
+ if (! has_holes_inside::apply(polygon,
+ turns.begin(), turns.end(),
+ visitor))
{
return false;
}
@@ -343,7 +379,8 @@ public:
return has_connected_interior::apply(polygon,
turns.begin(),
- turns.end());
+ turns.end(),
+ visitor);
}
};
@@ -361,9 +398,11 @@ namespace dispatch
// A Polygon is always a simple geometric object provided that it is valid.
//
// Reference (for validity of Polygons): OGC 06-103r4 (6.1.11.1)
-template <typename Polygon, bool AllowSpikes, bool AllowDuplicates>
-struct is_valid<Polygon, polygon_tag, AllowSpikes, AllowDuplicates>
- : detail::is_valid::is_valid_polygon<Polygon, AllowDuplicates>
+template <typename Polygon, bool AllowEmptyMultiGeometries>
+struct is_valid
+ <
+ Polygon, polygon_tag, AllowEmptyMultiGeometries
+ > : detail::is_valid::is_valid_polygon<Polygon>
{};
diff --git a/boost/geometry/algorithms/detail/is_valid/ring.hpp b/boost/geometry/algorithms/detail/is_valid/ring.hpp
index c88df79..c663a96 100644
--- a/boost/geometry/algorithms/detail/is_valid/ring.hpp
+++ b/boost/geometry/algorithms/detail/is_valid/ring.hpp
@@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2014, Oracle and/or its affiliates.
+// Copyright (c) 2014-2015, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
@@ -10,6 +10,8 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_RING_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_RING_HPP
+#include <deque>
+
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/point_order.hpp>
@@ -19,16 +21,22 @@
#include <boost/geometry/algorithms/equals.hpp>
-#include <boost/geometry/views/reversible_view.hpp>
#include <boost/geometry/views/closeable_view.hpp>
#include <boost/geometry/algorithms/area.hpp>
#include <boost/geometry/algorithms/intersects.hpp>
+#include <boost/geometry/algorithms/validity_failure_type.hpp>
+#include <boost/geometry/algorithms/detail/num_distinct_consecutive_points.hpp>
#include <boost/geometry/algorithms/detail/is_valid/has_spikes.hpp>
#include <boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp>
+#include <boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp>
#include <boost/geometry/strategies/area.hpp>
+#ifdef BOOST_GEOMETRY_TEST_DEBUG
+#include <boost/geometry/io/dsv/write.hpp>
+#endif
+
namespace boost { namespace geometry
{
@@ -42,18 +50,27 @@ namespace detail { namespace is_valid
template <typename Ring, closure_selector Closure /* open */>
struct is_topologically_closed
{
- static inline bool apply(Ring const&)
+ template <typename VisitPolicy>
+ static inline bool apply(Ring const&, VisitPolicy& visitor)
{
- return true;
+ return visitor.template apply<no_failure>();
}
};
template <typename Ring>
struct is_topologically_closed<Ring, closed>
{
- static inline bool apply(Ring const& ring)
+ template <typename VisitPolicy>
+ static inline bool apply(Ring const& ring, VisitPolicy& visitor)
{
- return geometry::equals(range::front(ring), range::back(ring));
+ if (geometry::equals(range::front(ring), range::back(ring)))
+ {
+ return visitor.template apply<no_failure>();
+ }
+ else
+ {
+ return visitor.template apply<failure_not_closed>();
+ }
}
};
@@ -92,7 +109,8 @@ struct is_properly_oriented
typedef typename default_area_result<Ring>::type area_result_type;
- static inline bool apply(Ring const& ring)
+ template <typename VisitPolicy>
+ static inline bool apply(Ring const& ring, VisitPolicy& visitor)
{
typename ring_area_predicate
<
@@ -101,7 +119,14 @@ struct is_properly_oriented
// Check area
area_result_type const zero = area_result_type();
- return predicate(ring_area_type::apply(ring, strategy_type()), zero);
+ if (predicate(ring_area_type::apply(ring, strategy_type()), zero))
+ {
+ return visitor.template apply<no_failure>();
+ }
+ else
+ {
+ return visitor.template apply<failure_wrong_orientation>();
+ }
}
};
@@ -110,41 +135,60 @@ struct is_properly_oriented
template
<
typename Ring,
- bool AllowDuplicates,
bool CheckSelfIntersections = true,
bool IsInteriorRing = false
>
struct is_valid_ring
{
- static inline bool apply(Ring const& ring)
+ template <typename VisitPolicy>
+ static inline bool apply(Ring const& ring, VisitPolicy& visitor)
{
// return invalid if any of the following condition holds:
// (a) the ring's size is below the minimal one
- // (b) the ring is not topologically closed
- // (c) the ring has spikes
- // (d) the ring has duplicate points (if AllowDuplicates is false)
- // (e) the boundary of the ring has self-intersections
- // (f) the order of the points is inconsistent with the defined order
+ // (b) the ring consists of at most two distinct points
+ // (c) the ring is not topologically closed
+ // (d) the ring has spikes
+ // (e) the ring has duplicate points (if AllowDuplicates is false)
+ // (f) the boundary of the ring has self-intersections
+ // (g) the order of the points is inconsistent with the defined order
//
// Note: no need to check if the area is zero. If this is the
// case, then the ring must have at least two spikes, which is
// checked by condition (c).
closure_selector const closure = geometry::closure<Ring>::value;
+ typedef typename closeable_view<Ring const, closure>::type view_type;
+
+ if (boost::size(ring)
+ < core_detail::closure::minimum_ring_size<closure>::value)
+ {
+ return visitor.template apply<failure_few_points>();
+ }
+
+ view_type const view(ring);
+ if (detail::num_distinct_consecutive_points
+ <
+ view_type, 4u, true,
+ not_equal_to<typename point_type<Ring>::type>
+ >::apply(view)
+ < 4u)
+ {
+ return
+ visitor.template apply<failure_wrong_topological_dimension>();
+ }
return
- ( boost::size(ring)
- >= core_detail::closure::minimum_ring_size<closure>::value )
- && is_topologically_closed<Ring, closure>::apply(ring)
- && (AllowDuplicates || !has_duplicates<Ring, closure>::apply(ring))
- && !has_spikes<Ring, closure>::apply(ring)
- && !(CheckSelfIntersections && geometry::intersects(ring))
- && is_properly_oriented<Ring, IsInteriorRing>::apply(ring);
+ is_topologically_closed<Ring, closure>::apply(ring, visitor)
+ && ! has_duplicates<Ring, closure>::apply(ring, visitor)
+ && ! has_spikes<Ring, closure>::apply(ring, visitor)
+ && (! CheckSelfIntersections
+ || has_valid_self_turns<Ring>::apply(ring, visitor))
+ && is_properly_oriented<Ring, IsInteriorRing>::apply(ring, visitor);
}
};
-}} // namespace dispatch
+}} // namespace detail::is_valid
#endif // DOXYGEN_NO_DETAIL
@@ -158,9 +202,11 @@ namespace dispatch
// 6.1.7.1, for the definition of LinearRing)
//
// Reference (for polygon validity): OGC 06-103r4 (6.1.11.1)
-template <typename Ring, bool AllowSpikes, bool AllowDuplicates>
-struct is_valid<Ring, ring_tag, AllowSpikes, AllowDuplicates>
- : detail::is_valid::is_valid_ring<Ring, AllowDuplicates>
+template <typename Ring, bool AllowEmptyMultiGeometries>
+struct is_valid
+ <
+ Ring, ring_tag, AllowEmptyMultiGeometries
+ > : detail::is_valid::is_valid_ring<Ring>
{};
diff --git a/boost/geometry/algorithms/detail/is_valid/segment.hpp b/boost/geometry/algorithms/detail/is_valid/segment.hpp
index 486289d..0b60890 100644
--- a/boost/geometry/algorithms/detail/is_valid/segment.hpp
+++ b/boost/geometry/algorithms/detail/is_valid/segment.hpp
@@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2014, Oracle and/or its affiliates.
+// Copyright (c) 2014-2015, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
@@ -15,6 +15,7 @@
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/algorithms/equals.hpp>
+#include <boost/geometry/algorithms/validity_failure_type.hpp>
#include <boost/geometry/algorithms/dispatch/is_valid.hpp>
@@ -40,13 +41,22 @@ namespace dispatch
template <typename Segment>
struct is_valid<Segment, segment_tag>
{
- static inline bool apply(Segment const& segment)
+ template <typename VisitPolicy>
+ static inline bool apply(Segment const& segment, VisitPolicy& visitor)
{
typename point_type<Segment>::type p[2];
detail::assign_point_from_index<0>(segment, p[0]);
detail::assign_point_from_index<1>(segment, p[1]);
- return !geometry::equals(p[0], p[1]);
+ if(! geometry::equals(p[0], p[1]))
+ {
+ return visitor.template apply<no_failure>();
+ }
+ else
+ {
+ return
+ visitor.template apply<failure_wrong_topological_dimension>();
+ }
}
};
diff --git a/boost/geometry/algorithms/detail/not.hpp b/boost/geometry/algorithms/detail/not.hpp
index abc3a4e..43e71e2 100644
--- a/boost/geometry/algorithms/detail/not.hpp
+++ b/boost/geometry/algorithms/detail/not.hpp
@@ -1,8 +1,13 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
-// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
-// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
+
+// This file was modified by Oracle on 2015.
+// Modifications copyright (c) 2015, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -32,10 +37,12 @@ namespace detail
\param geometry2 \param_geometry
\return Negation of the result of the policy
*/
-template <typename Geometry1, typename Geometry2, typename Policy>
+template <typename Policy>
struct not_
{
- static inline bool apply(Geometry1 const &geometry1, Geometry2 const& geometry2)
+ template <typename Geometry1, typename Geometry2>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2)
{
return ! Policy::apply(geometry1, geometry2);
}
diff --git a/boost/geometry/algorithms/detail/occupation_info.hpp b/boost/geometry/algorithms/detail/occupation_info.hpp
index d90f3cf..002c946 100644
--- a/boost/geometry/algorithms/detail/occupation_info.hpp
+++ b/boost/geometry/algorithms/detail/occupation_info.hpp
@@ -57,6 +57,12 @@ class occupation_info
public :
typedef std::vector<AngleInfo> collection_type;
+ int count;
+
+ inline occupation_info()
+ : count(0)
+ {}
+
template <typename RobustPoint>
inline void add(RobustPoint const& incoming_point,
RobustPoint const& outgoing_point,
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
index d44db17..285edfd 100644
--- a/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp
+++ b/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp
@@ -20,6 +20,7 @@
#include <boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp>
#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
+#include <boost/geometry/util/condition.hpp>
#include <boost/geometry/util/range.hpp>
@@ -42,7 +43,7 @@ inline bool points_equal_or_close(Point1 const& point1,
return true;
}
- if (! RobustPolicy::enabled)
+ if (BOOST_GEOMETRY_CONDITION(! RobustPolicy::enabled))
{
return false;
}
@@ -127,7 +128,7 @@ inline void clean_closing_dups_and_spikes(Range& range,
iterator_type first = boost::begin(range);
iterator_type second = first + 1;
iterator_type ultimate = boost::end(range) - 1;
- if (closed)
+ if (BOOST_GEOMETRY_CONDITION(closed))
{
ultimate--;
}
@@ -137,7 +138,7 @@ inline void clean_closing_dups_and_spikes(Range& range,
if (point_is_spike_or_equal(*second, *ultimate, *first, robust_policy))
{
range::erase(range, first);
- if (closed)
+ if (BOOST_GEOMETRY_CONDITION(closed))
{
// Remove closing last point
range::resize(range, boost::size(range) - 1);
diff --git a/boost/geometry/algorithms/detail/overlay/assign_parents.hpp b/boost/geometry/algorithms/detail/overlay/assign_parents.hpp
index 67b48cc..178f382 100644
--- a/boost/geometry/algorithms/detail/overlay/assign_parents.hpp
+++ b/boost/geometry/algorithms/detail/overlay/assign_parents.hpp
@@ -18,11 +18,6 @@
#include <boost/geometry/geometries/box.hpp>
-#ifdef BOOST_GEOMETRY_TIME_OVERLAY
-# include <boost/timer.hpp>
-#endif
-
-
namespace boost { namespace geometry
{
@@ -186,11 +181,6 @@ inline void assign_parents(Geometry1 const& geometry1,
typedef std::vector<helper> vector_type;
typedef typename boost::range_iterator<vector_type const>::type vector_iterator_type;
-#ifdef BOOST_GEOMETRY_TIME_OVERLAY
- boost::timer timer;
-#endif
-
-
std::size_t count_total = ring_map.size();
std::size_t count_positive = 0;
std::size_t index_positive = 0; // only used if count_positive>0
@@ -226,10 +216,6 @@ inline void assign_parents(Geometry1 const& geometry1,
}
}
-#ifdef BOOST_GEOMETRY_TIME_OVERLAY
- std::cout << " ap: created helper vector: " << timer.elapsed() << std::endl;
-#endif
-
if (! check_for_orientation)
{
if (count_positive == count_total)
@@ -272,11 +258,6 @@ inline void assign_parents(Geometry1 const& geometry1,
<
box_type, ring_info_helper_get_box, ring_info_helper_ovelaps_box
>::apply(vector, visitor);
-
-#ifdef BOOST_GEOMETRY_TIME_OVERLAY
- std::cout << " ap: quadradic loop: " << timer.elapsed() << std::endl;
- std::cout << " ap: check_for_orientation " << check_for_orientation << std::endl;
-#endif
}
if (check_for_orientation)
diff --git a/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp b/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp
index 20a6d7f..13e0a5a 100644
--- a/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp
+++ b/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp
@@ -11,6 +11,7 @@
#include <boost/array.hpp>
+#include <boost/assert.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/range.hpp>
@@ -21,8 +22,7 @@
#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>
+#include <boost/geometry/views/detail/normalized_view.hpp>
namespace boost { namespace geometry
@@ -37,41 +37,24 @@ namespace detail { namespace copy_segments
template <typename Range, bool Reverse, typename SegmentIdentifier, typename PointOut>
struct copy_segment_point_range
{
- typedef typename closeable_view
- <
- Range const,
- closure<Range>::value
- >::type cview_type;
-
- typedef typename reversible_view
- <
- cview_type const,
- Reverse ? iterate_reverse : iterate_forward
- >::type rview_type;
-
static inline bool apply(Range const& range,
SegmentIdentifier const& seg_id, bool second,
PointOut& point)
{
+ detail::normalized_view<Range const> view(range);
+
+ signed_index_type const n = boost::size(view);
signed_index_type index = seg_id.segment_index;
if (second)
{
index++;
- if (index >= int(boost::size(range)))
+ if (index >= n)
{
index = 0;
}
}
- // Exception?
- if (index >= int(boost::size(range)))
- {
- return false;
- }
-
- cview_type cview(range);
- rview_type view(cview);
-
+ BOOST_ASSERT(index >= 0 && index < n);
geometry::convert(*(boost::begin(view) + index), point);
return true;
@@ -323,6 +306,8 @@ inline bool copy_segment_point(Geometry1 const& geometry1, Geometry2 const& geom
concept::check<Geometry1 const>();
concept::check<Geometry2 const>();
+ BOOST_ASSERT(seg_id.source_index == 0 || seg_id.source_index == 1);
+
if (seg_id.source_index == 0)
{
return dispatch::copy_segment_point
diff --git a/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp b/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp
index 9484479..7ed93f5 100644
--- a/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp
+++ b/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp
@@ -56,13 +56,13 @@ struct indexed_turn_operation
TurnOperation const* subject;
inline indexed_turn_operation(std::size_t ti, std::size_t oi,
- TurnOperation const& s,
+ TurnOperation const& sub,
segment_identifier const& oid)
: turn_index(ti)
, operation_index(oi)
, discarded(false)
, other_seg_id(&oid)
- , subject(&s)
+ , subject(boost::addressof(sub))
{}
};
@@ -114,6 +114,12 @@ private :
typedef typename geometry::point_type<Geometry1>::type point_type;
+ inline bool default_order(Indexed const& left, Indexed const& right) const
+ {
+ // We've nothing to sort on. Take the indexes
+ return left.turn_index < right.turn_index;
+ }
+
inline bool consider_relative_order(Indexed const& left,
Indexed const& right) const
{
@@ -148,7 +154,12 @@ private :
// 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;
+ if (side_rj_s != side_sj_r)
+ {
+ return side_rj_s < side_sj_r;
+ }
+
+ return default_order(left, right);
}
public :
@@ -157,30 +168,32 @@ 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;
+ if (! (left.subject->seg_id == right.subject->seg_id))
+ {
+ return left.subject->seg_id < right.subject->seg_id;
+ }
+
+ // Both left and right are located on the SAME segment.
- if (sl == sr)
+ if (! (left.subject->fraction == right.subject->fraction))
{
- // Both left and right are located on the SAME segment.
- if (left.subject->fraction == right.subject->fraction)
- {
- // 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.subject->fraction < right.subject->fraction;
+ }
- // 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 sl == sr
- ? left.subject->fraction < right.subject->fraction
- : sl < sr;
+
+ // If that is not the case, cluster it later on.
+ // Indicate that this is necessary.
+ *m_clustered = true;
+
+ return default_order(left, right);
}
};
diff --git a/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp b/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp
index 85378e0..7bcc0b9 100644
--- a/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp
+++ b/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp
@@ -35,6 +35,23 @@
namespace boost { namespace geometry
{
+#if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW)
+class inconsistent_turns_exception : public geometry::exception
+{
+public:
+
+ inline inconsistent_turns_exception() {}
+
+ virtual ~inconsistent_turns_exception() throw()
+ {}
+
+ virtual char const* what() const throw()
+ {
+ return "Boost.Geometry Inconsistent Turns exception";
+ }
+};
+#endif
+
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace overlay
@@ -304,7 +321,14 @@ public:
oit);
}
- BOOST_ASSERT( enter_count == 0 );
+#if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW)
+ if (enter_count != 0)
+ {
+ throw inconsistent_turns_exception();
+ }
+#else
+ BOOST_ASSERT(enter_count == 0);
+#endif
return process_end(entered, linestring,
current_segment_id, current_piece,
diff --git a/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp
index 240b6de..b3b1a06 100644
--- a/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp
+++ b/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp
@@ -2,6 +2,11 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// This file was modified by Oracle on 2015.
+// Modifications copyright (c) 2015 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)
@@ -11,6 +16,8 @@
#include <boost/assert.hpp>
+#include <boost/core/ignore_unused.hpp>
+
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/strategies/intersection.hpp>
@@ -104,17 +111,19 @@ struct base_turn_handler
template <typename TurnInfo, typename IntersectionInfo>
static inline void assign_point(TurnInfo& ti,
method_type method,
- IntersectionInfo const& info, int index)
+ IntersectionInfo const& info, unsigned int index)
{
ti.method = method;
- BOOST_ASSERT(index >= 0 && unsigned(index) < info.count); // TODO remove this
+
+ BOOST_ASSERT(index < info.count);
+
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)
+ static inline unsigned int non_opposite_to_index(IntersectionInfo const& info)
{
return info.fractions[0].robust_rb < info.fractions[1].robust_rb
? 1 : 0;
@@ -132,7 +141,7 @@ struct touch_interior : public base_turn_handler
// Index: 0, P is the interior, Q is touching and vice versa
template
<
- int Index,
+ unsigned int Index,
typename Point1,
typename Point2,
typename IntersectionInfo,
@@ -155,8 +164,9 @@ struct touch_interior : public base_turn_handler
// 2) Important is: if q_k goes to LEFT, RIGHT, COLLINEAR
// and, if LEFT/COLL, if it is lying LEFT or RIGHT w.r.t. q_i
- static int const index_p = Index;
- static int const index_q = 1 - Index;
+ BOOST_STATIC_ASSERT(Index <= 1);
+ static unsigned int const index_p = Index;
+ static unsigned int const index_q = 1 - Index;
int const side_qi_p = dir_info.sides.template get<index_q, 0>();
int const side_qk_p = side.qk_wrt_p1();
@@ -166,7 +176,7 @@ struct touch_interior : public base_turn_handler
// Q crosses P from left->right or from right->left (test "ML1")
// Union: folow P (left->right) or Q (right->left)
// Intersection: other turn
- int index = side_qk_p == -1 ? index_p : index_q;
+ unsigned int index = side_qk_p == -1 ? index_p : index_q;
ti.operations[index].operation = operation_union;
ti.operations[1 - index].operation = operation_intersection;
return;
@@ -193,7 +203,7 @@ struct touch_interior : public base_turn_handler
// or Q turns right on the right side of P (test "MR2")
// Union: take left turn (Q if Q turns left, P if Q turns right)
// Intersection: other turn
- int index = side_qk_q == 1 ? index_q : index_p;
+ unsigned int index = side_qk_q == 1 ? index_q : index_p;
ti.operations[index].operation = operation_union;
ti.operations[1 - index].operation = operation_intersection;
}
@@ -215,10 +225,10 @@ struct touch_interior : public base_turn_handler
// Opposite direction, which is never travelled.
// If Q turns left, P continues for intersection
// If Q turns right, P continues for union
- ti.operations[Index].operation = side_qk_q == 1
+ ti.operations[index_p].operation = side_qk_q == 1
? operation_intersection
: operation_union;
- ti.operations[1 - Index].operation = operation_blocked;
+ ti.operations[index_q].operation = operation_blocked;
}
}
else
@@ -503,27 +513,25 @@ struct equal_opposite : public base_turn_handler
typename Point1,
typename Point2,
typename OutputIterator,
- typename IntersectionInfo,
- typename DirInfo
+ typename IntersectionInfo
>
static inline void apply(Point1 const& pi, Point2 const& qi,
/* by value: */ TurnInfo tp,
OutputIterator& out,
- IntersectionInfo const& intersection_info,
- DirInfo const& dir_info)
+ IntersectionInfo const& intersection_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++)
+ for (unsigned int i = 0; i < 2; i++)
{
tp.operations[i].operation = operation_opposite;
}
- for (unsigned int i = 0; i < intersection_info.count; i++)
+ for (unsigned int i = 0; i < intersection_info.i_info().count; i++)
{
- assign_point(tp, method_none, intersection_info, i);
- AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info);
+ assign_point(tp, method_none, intersection_info.i_info(), i);
+ AssignPolicy::apply(tp, pi, qi, intersection_info);
*out++ = tp;
}
}
@@ -653,7 +661,7 @@ private :
template
<
- int Index,
+ unsigned int Index,
typename Point1,
typename Point2,
typename IntersectionInfo
@@ -663,8 +671,9 @@ private :
Point2 const& , Point2 const& , int side_rk_s,
TurnInfo& tp, IntersectionInfo const& intersection_info)
{
- boost::ignore_unused_variable_warning(handle_robustness);
- boost::ignore_unused_variable_warning(side_rk_s);
+ BOOST_STATIC_ASSERT(Index <= 1);
+
+ boost::ignore_unused(handle_robustness, side_rk_s);
operation_type blocked = operation_blocked;
switch(side_rk_r)
@@ -715,7 +724,6 @@ public:
typename Point2,
typename OutputIterator,
typename IntersectionInfo,
- typename DirInfo,
typename SidePolicy
>
static inline void apply(
@@ -727,10 +735,9 @@ public:
OutputIterator& out,
IntersectionInfo const& intersection_info,
- DirInfo const& dir_info,
SidePolicy const& side)
{
- apply(pi, pj, pk, qi, qj, qk, tp_model, out, intersection_info, dir_info, side, empty_transformer);
+ apply(pi, pj, pk, qi, qj, qk, tp_model, out, intersection_info, side, empty_transformer);
}
public:
@@ -740,7 +747,6 @@ public:
typename Point2,
typename OutputIterator,
typename IntersectionInfo,
- typename DirInfo,
typename SidePolicy,
typename TurnTransformer
>
@@ -752,50 +758,52 @@ public:
TurnInfo const& tp_model,
OutputIterator& out,
- IntersectionInfo const& intersection_info,
- DirInfo const& dir_info,
+ IntersectionInfo const& info,
SidePolicy const& side,
TurnTransformer turn_transformer,
bool const is_pk_valid = true, bool const is_qk_valid = true)
{
TurnInfo tp = tp_model;
+ int const p_arrival = info.d_info().arrival[0];
+ int const q_arrival = info.d_info().arrival[1];
+
// If P arrives within Q, there is a turn dependent on P
- if ( dir_info.arrival[0] == 1
+ if ( p_arrival == 1
&& is_pk_valid
- && set_tp<0>(pi, pj, pk, side.pk_wrt_p1(), true, qi, qj, side.pk_wrt_q1(), tp, intersection_info) )
+ && set_tp<0>(pi, pj, pk, side.pk_wrt_p1(), true, qi, qj, side.pk_wrt_q1(), tp, info.i_info()) )
{
turn_transformer(tp);
- AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info);
+ AssignPolicy::apply(tp, pi, qi, info);
*out++ = tp;
}
// If Q arrives within P, there is a turn dependent on Q
- if ( dir_info.arrival[1] == 1
+ if ( q_arrival == 1
&& is_qk_valid
- && set_tp<1>(qi, qj, qk, side.qk_wrt_q1(), false, pi, pj, side.qk_wrt_p1(), tp, intersection_info) )
+ && set_tp<1>(qi, qj, qk, side.qk_wrt_q1(), false, pi, pj, side.qk_wrt_p1(), tp, info.i_info()) )
{
turn_transformer(tp);
- AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info);
+ AssignPolicy::apply(tp, pi, qi, 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))
+ if ((q_arrival == -1 && p_arrival == 0)
+ || (p_arrival == -1 && q_arrival == 0))
{
- for (int i = 0; i < 2; i++)
+ for (unsigned int i = 0; i < 2; i++)
{
tp.operations[i].operation = operation_opposite;
}
- for (unsigned int i = 0; i < intersection_info.count; i++)
+ for (unsigned int i = 0; i < info.i_info().count; i++)
{
- assign_point(tp, method_collinear, intersection_info, i);
- AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info);
+ assign_point(tp, method_collinear, info.i_info(), i);
+ AssignPolicy::apply(tp, pi, qi, info);
*out++ = tp;
}
}
@@ -833,7 +841,7 @@ struct crosses : public base_turn_handler
// Intersection: take Q
// Otherwise: vice versa
int const side_qi_p1 = dir_info.sides.template get<1, 0>();
- int const index = side_qi_p1 == 1 ? 0 : 1;
+ unsigned int const index = side_qi_p1 == 1 ? 0 : 1;
ti.operations[index].operation = operation_union;
ti.operations[1 - index].operation = operation_intersection;
}
@@ -867,10 +875,9 @@ struct assign_null_policy
typename Info,
typename Point1,
typename Point2,
- typename IntersectionInfo,
- typename DirInfo
+ typename IntersectionInfo
>
- static inline void apply(Info& , Point1 const& , Point2 const&, IntersectionInfo const&, DirInfo const&)
+ static inline void apply(Info& , Point1 const& , Point2 const&, IntersectionInfo const&)
{}
};
@@ -933,7 +940,7 @@ struct get_turn_info
&& inters.i_info().count > 0)
{
only_convert::apply(tp, inters.i_info());
- AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+ AssignPolicy::apply(tp, pi, qi, inters);
*out++ = tp;
}
break;
@@ -968,7 +975,7 @@ struct get_turn_info
tp, inters.i_info(), inters.d_info(),
swapped_side_calc);
}
- AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+ AssignPolicy::apply(tp, pi, qi, inters);
*out++ = tp;
}
break;
@@ -976,7 +983,7 @@ struct get_turn_info
{
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());
+ AssignPolicy::apply(tp, pi, qi, inters);
*out++ = tp;
}
break;
@@ -985,7 +992,7 @@ struct get_turn_info
// Both touch (both arrive there)
touch<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
tp, inters.i_info(), inters.d_info(), inters.sides());
- AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+ AssignPolicy::apply(tp, pi, qi, inters);
*out++ = tp;
}
break;
@@ -997,7 +1004,7 @@ struct get_turn_info
// or collinear-and-ending at intersection point
equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
tp, inters.i_info(), inters.d_info(), inters.sides());
- AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+ AssignPolicy::apply(tp, pi, qi, inters);
*out++ = tp;
}
else
@@ -1007,7 +1014,7 @@ struct get_turn_info
TurnInfo,
AssignPolicy
>::apply(pi, qi,
- tp, out, inters.i_info(), inters.d_info());
+ tp, out, inters);
}
}
break;
@@ -1032,7 +1039,7 @@ struct get_turn_info
tp, inters.i_info(), inters.d_info(), inters.sides());
}
- AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+ AssignPolicy::apply(tp, pi, qi, inters);
*out++ = tp;
}
else
@@ -1042,7 +1049,7 @@ struct get_turn_info
TurnInfo,
AssignPolicy
>::apply(pi, pj, pk, qi, qj, qk,
- tp, out, inters.i_info(), inters.d_info(), inters.sides());
+ tp, out, inters, inters.sides());
}
}
break;
@@ -1052,7 +1059,7 @@ struct get_turn_info
if (AssignPolicy::include_degenerate)
{
only_convert::apply(tp, inters.i_info());
- AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+ AssignPolicy::apply(tp, pi, qi, inters);
*out++ = tp;
}
}
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
index ca1b9d9..4a3cacb 100644
--- a/boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp
+++ b/boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp
@@ -290,7 +290,7 @@ struct get_turn_info_for_endpoint
linear_intersections::ip_info const& ip_info,
TurnInfo const& tp_model,
IntersectionInfo const& inters,
- int ip_index,
+ unsigned int ip_index,
OutputIterator out)
{
#ifdef BOOST_GEOMETRY_DEBUG_GET_TURNS_LINEAR_LINEAR
@@ -396,7 +396,7 @@ struct get_turn_info_for_endpoint
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,
+ IntersectionInfo const& inters, unsigned int ip_index,
operation_type & op1, operation_type & op2)
{
boost::ignore_unused_variable_warning(i2);
@@ -535,7 +535,7 @@ struct get_turn_info_for_endpoint
typename OutputIterator>
static inline void assign(Point1 const& pi, Point2 const& qi,
IntersectionResult const& result,
- int ip_index,
+ unsigned int ip_index,
method_type method,
operation_type op0, operation_type op1,
turn_position pos0, turn_position pos1,
@@ -585,7 +585,9 @@ struct get_turn_info_for_endpoint
}
}
- AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
+ // TODO: this should get an intersection_info, which is unavailable here
+ // Because the assign_null policy accepts any structure, we pass the result instead for now
+ AssignPolicy::apply(tp, pi, qi, result);
*out++ = tp;
}
diff --git a/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp
index eead0d7..e0d7510 100644
--- a/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp
+++ b/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp
@@ -2,8 +2,8 @@
// 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.
+// This file was modified by Oracle on 2013, 2014, 2015.
+// Modifications copyright (c) 2013-2015 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
diff --git a/boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp
index 873567b..7194654 100644
--- a/boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp
+++ b/boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp
@@ -2,18 +2,20 @@
// 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.
+// This file was modified by Oracle on 2013, 2014, 2015.
+// Modifications copyright (c) 2013-2015 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)
-// 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/util/condition.hpp>
+
#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp>
@@ -28,6 +30,8 @@ namespace detail { namespace overlay {
template<typename AssignPolicy>
struct get_turn_info_linear_areal
{
+ // Currently only Linear spikes are handled
+ // Areal spikes are ignored
static const bool handle_spikes = true;
template
@@ -122,7 +126,7 @@ struct get_turn_info_linear_areal
calculate_spike_operation(tp.operations[0].operation,
inters, is_p_last);
- AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+ AssignPolicy::apply(tp, pi, qi, inters);
*out++ = tp;
}
@@ -135,7 +139,7 @@ struct get_turn_info_linear_areal
replace_operations_i(tp.operations[0].operation, tp.operations[1].operation);
- AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+ AssignPolicy::apply(tp, pi, qi, inters);
*out++ = tp;
}
break;
@@ -220,9 +224,9 @@ struct get_turn_info_linear_areal
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());
+ AssignPolicy::apply(tp, pi, qi, inters);
- if ( ! handle_spikes
+ if ( ! BOOST_GEOMETRY_CONDITION(handle_spikes)
|| ignore_spike
|| ! append_opposite_spikes<append_touches>( // for 'i' or 'c' i???
tp, inters, is_p_last, is_q_last, out) )
@@ -256,10 +260,10 @@ struct get_turn_info_linear_areal
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());
+ AssignPolicy::apply(tp, pi, qi, inters);
// conditionally handle spikes
- if ( ! handle_spikes
+ if ( ! BOOST_GEOMETRY_CONDITION(handle_spikes)
|| ! append_collinear_spikes(tp, inters, is_p_last, is_q_last,
method_touch, append_equal, out) )
{
@@ -273,7 +277,7 @@ struct get_turn_info_linear_areal
TurnInfo,
AssignPolicy
>::apply(pi, qi,
- tp, out, inters.i_info(), inters.d_info());
+ tp, out, inters);
}
}
}
@@ -319,10 +323,10 @@ struct get_turn_info_linear_areal
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());
+ AssignPolicy::apply(tp, pi, qi, inters);
// conditionally handle spikes
- if ( ! handle_spikes
+ if ( ! BOOST_GEOMETRY_CONDITION(handle_spikes)
|| ! append_collinear_spikes(tp, inters, is_p_last, is_q_last,
method_replace, version, out) )
{
@@ -336,7 +340,7 @@ struct get_turn_info_linear_areal
turn_transformer_ec<false> transformer(method_touch_interior);
// conditionally handle spikes
- if ( handle_spikes )
+ if ( BOOST_GEOMETRY_CONDITION(handle_spikes) )
{
append_opposite_spikes<append_collinear_opposite>(
tp, inters, is_p_last, is_q_last, out);
@@ -351,8 +355,9 @@ struct get_turn_info_linear_areal
TurnInfo,
AssignPolicy
>::apply(pi, pj, pk, qi, qj, qk,
- tp, out, inters.i_info(), inters.d_info(),
- inters.sides(), transformer);
+ tp, out, inters,
+ inters.sides(), transformer,
+ !is_p_last, true); // qk is always valid
}
}
}
@@ -360,7 +365,7 @@ struct get_turn_info_linear_areal
case '0' :
{
// degenerate points
- if (AssignPolicy::include_degenerate)
+ if ( BOOST_GEOMETRY_CONDITION(AssignPolicy::include_degenerate) )
{
only_convert::apply(tp, inters.i_info());
@@ -376,7 +381,7 @@ struct get_turn_info_linear_areal
}
// tp.operations[1].position = position_middle;
- AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+ AssignPolicy::apply(tp, pi, qi, inters);
*out++ = tp;
}
}
@@ -408,20 +413,37 @@ struct get_turn_info_linear_areal
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();
+
+ bool going_in = pk_q1 < 0; // Pk on the right
+ bool going_out = pk_q1 > 0; // Pk on the left
- if ( inters.sides().qk_wrt_q1() <= 0 ) // Q turning R or C
+ int const qk_q1 = inters.sides().qk_wrt_q1();
+
+ // special cases
+ if ( qk_q1 < 0 ) // Q turning R
{
- 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
+ // spike on the edge point
+ // if it's already known that the spike is going out this musn't be checked
+ if ( ! going_out
+ && equals::equals_point_point(inters.rpj(), inters.rqj()) )
+ {
+ int const pk_q2 = inters.sides().pk_wrt_q2();
+ 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
+ else if ( qk_q1 > 0 ) // Q turning L
{
- 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
+ // spike on the edge point
+ // if it's already known that the spike is going in this musn't be checked
+ if ( ! going_in
+ && equals::equals_point_point(inters.rpj(), inters.rqj()) )
+ {
+ int const pk_q2 = inters.sides().pk_wrt_q2();
+ 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 )
@@ -461,10 +483,16 @@ struct get_turn_info_linear_areal
&& 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();*/
+ /*bool is_q_spike = tp.operations[1].operation == operation_continue
+ && inters.is_spike_q();
+ // both are collinear spikes on the same IP, we can just follow both
+ if ( is_p_spike && is_q_spike )
+ {
+ return false;
+ }
+ // spike on Linear - it's turning back on the boundary of Areal
+ else*/
if ( is_p_spike )
{
tp.method = method;
@@ -477,7 +505,18 @@ struct get_turn_info_linear_areal
return true;
}
-
+ // spike on Areal - Linear is going outside
+ /*else if ( is_q_spike )
+ {
+ tp.method = method;
+ tp.operations[0].operation = operation_union;
+ tp.operations[1].operation = operation_continue;
+ *out++ = tp;
+ *out++ = tp;
+
+ return true;
+ }*/
+
return false;
}
@@ -492,48 +531,71 @@ struct get_turn_info_linear_areal
bool is_p_last, bool /*is_q_last*/,
OutIt out)
{
- bool is_p_spike = ( Version == append_touches ?
+ static const bool is_version_touches = (Version == append_touches);
+
+ bool is_p_spike = ( is_version_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();*/
+ /*bool is_q_spike = ( ( Version == append_touches
+ && tp.operations[1].operation == operation_continue )
+ || ( Version == append_collinear_opposite
+ && tp.operations[1].operation == operation_none ) )
+ && inters.is_spike_q();
- if ( is_p_spike && ( Version == append_touches || inters.d_info().arrival[0] == 1 ) )
+ if ( is_p_spike && is_q_spike )
{
- if ( Version == append_touches )
- {
- tp.operations[0].is_collinear = true;
- //tp.operations[1].is_collinear = false;
- tp.method = method_touch;
- }
- else
+ // u/u or nothing?
+ return false;
+ }
+ else*/
+ if ( is_p_spike )
+ {
+ if ( BOOST_GEOMETRY_CONDITION(is_version_touches)
+ || inters.d_info().arrival[0] == 1 )
{
- 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);
+ if ( BOOST_GEOMETRY_CONDITION(is_version_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;
- AssignPolicy::apply(tp, inters.pi(), inters.qi(), inters.i_info(), inters.d_info());
- }
+ BOOST_ASSERT(inters.i_info().count > 1);
+ base_turn_handler::assign_point(tp, method_touch_interior, inters.i_info(), 1);
- tp.operations[0].operation = operation_blocked;
+ AssignPolicy::apply(tp, inters.pi(), inters.qi(), inters);
+ }
+
+ 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;
+ }
+ }
+ /*else if ( is_q_spike )
+ {
+ tp.operations[0].is_collinear = true;
+ tp.method = is_version_touches ? method_touch : method_touch_interior;
+ tp.operations[0].operation = operation_continue;
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;
}
@@ -587,7 +649,7 @@ struct get_turn_info_linear_areal
operation_type & op1 = turn.operations[1].operation;
// NOTE: probably only if methods are WRT IPs, not segments!
- if ( IsFront
+ if ( BOOST_GEOMETRY_CONDITION(IsFront)
|| op0 == operation_intersection || op0 == operation_union
|| op1 == operation_intersection || op1 == operation_union )
{
@@ -666,7 +728,9 @@ struct get_turn_info_linear_areal
// 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
+ bool was_first_point_handled = false;
+ if ( BOOST_GEOMETRY_CONDITION(EnableFirst)
+ && is_p_first && ip0.is_pi && !ip0.is_qi ) // !q0i prevents duplication
{
TurnInfo tp = tp_model;
tp.operations[0].position = position_front;
@@ -735,14 +799,16 @@ struct get_turn_info_linear_areal
// here is_p_first_ip == true
tp.operations[0].is_collinear = false;
- AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+ AssignPolicy::apply(tp, pi, qi, inters);
*out++ = tp;
+
+ was_first_point_handled = true;
}
// ANALYSE AND ASSIGN LAST
// IP on the last point of Linear Geometry
- if ( EnableLast
+ if ( BOOST_GEOMETRY_CONDITION(EnableLast)
&& is_p_last
&& ( ip_count > 1 ? (ip1.is_pj && !ip1.is_qi) : (ip0.is_pj && !ip0.is_qi) ) ) // prevents duplication
{
@@ -783,13 +849,14 @@ struct get_turn_info_linear_areal
// equals<> or collinear<> will assign the second point,
// we'd like to assign the first one
- int ip_index = ip_count > 1 ? 1 : 0;
+ unsigned 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());
+ AssignPolicy::apply(tp, pi, qi, inters);
*out++ = tp;
- return true;
+ // don't ignore the first IP if the segment is opposite
+ return !( opposite && ip_count > 1 ) || was_first_point_handled;
}
// don't ignore anything for now
diff --git a/boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp
index 4f03848..1ec88e5 100644
--- a/boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp
+++ b/boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp
@@ -2,8 +2,8 @@
// 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.
+// This file was modified by Oracle on 2013, 2014, 2015.
+// Modifications copyright (c) 2013-2015 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
@@ -17,6 +17,8 @@
#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp>
+#include <boost/geometry/util/condition.hpp>
+
namespace boost { namespace geometry {
#ifndef DOXYGEN_NO_DETAIL
@@ -120,7 +122,7 @@ struct get_turn_info_linear_linear
tp.operations[0].operation,
tp.operations[1].operation);
- AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+ AssignPolicy::apply(tp, pi, qi, inters);
*out++ = tp;
}
}
@@ -132,7 +134,7 @@ struct get_turn_info_linear_linear
replace_operations_i(tp.operations[0].operation, tp.operations[1].operation);
- AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+ AssignPolicy::apply(tp, pi, qi, inters);
*out++ = tp;
}
break;
@@ -260,9 +262,9 @@ struct get_turn_info_linear_linear
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());
+ AssignPolicy::apply(tp, pi, qi, inters);
- if ( ! handle_spikes
+ if ( ! BOOST_GEOMETRY_CONDITION(handle_spikes)
|| ! append_opposite_spikes<append_touches>(tp, inters,
is_p_last, is_q_last,
out) )
@@ -293,18 +295,24 @@ struct get_turn_info_linear_linear
equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
tp, inters.i_info(), inters.d_info(), inters.sides());
+ operation_type spike_op
+ = ( tp.operations[0].operation != operation_continue
+ || tp.operations[1].operation != operation_continue ) ?
+ operation_union :
+ operation_continue;
+
// 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());
+ AssignPolicy::apply(tp, pi, qi, inters);
// conditionally handle spikes
- if ( ! handle_spikes
+ if ( ! BOOST_GEOMETRY_CONDITION(handle_spikes)
|| ! append_collinear_spikes(tp, inters,
is_p_last, is_q_last,
- method_touch, operation_union,
+ method_touch, spike_op,
out) )
{
*out++ = tp; // no spikes
@@ -318,7 +326,7 @@ struct get_turn_info_linear_linear
<
TurnInfo,
AssignPolicy
- >::apply(pi, qi, tp, out, inters.i_info(), inters.d_info());
+ >::apply(pi, qi, tp, out, inters);
}
}
}
@@ -351,7 +359,11 @@ struct get_turn_info_linear_linear
tp, inters.i_info(), inters.d_info(), inters.sides());
method_replace = method_touch;
- spike_op = operation_union;
+ if ( tp.operations[0].operation != operation_continue
+ || tp.operations[1].operation != operation_continue )
+ {
+ spike_op = operation_union;
+ }
}
else
{
@@ -367,10 +379,10 @@ struct get_turn_info_linear_linear
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());
+ AssignPolicy::apply(tp, pi, qi, inters);
// conditionally handle spikes
- if ( ! handle_spikes
+ if ( ! BOOST_GEOMETRY_CONDITION(handle_spikes)
|| ! append_collinear_spikes(tp, inters,
is_p_last, is_q_last,
method_replace, spike_op,
@@ -386,7 +398,7 @@ struct get_turn_info_linear_linear
turn_transformer_ec transformer(method_touch_interior);
// conditionally handle spikes
- if ( handle_spikes )
+ if ( BOOST_GEOMETRY_CONDITION(handle_spikes) )
{
append_opposite_spikes<append_collinear_opposite>(tp, inters,
is_p_last, is_q_last,
@@ -402,7 +414,7 @@ struct get_turn_info_linear_linear
TurnInfo,
AssignPolicy
>::apply(pi, pj, pk, qi, qj, qk,
- tp, out, inters.i_info(), inters.d_info(), inters.sides(),
+ tp, out, inters, inters.sides(),
transformer, !is_p_last, !is_q_last);
}
}
@@ -411,7 +423,7 @@ struct get_turn_info_linear_linear
case '0' :
{
// degenerate points
- if (AssignPolicy::include_degenerate)
+ if ( BOOST_GEOMETRY_CONDITION(AssignPolicy::include_degenerate) )
{
only_convert::apply(tp, inters.i_info());
@@ -437,7 +449,7 @@ struct get_turn_info_linear_linear
tp.operations[1].position = position_back;
}
- AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
+ AssignPolicy::apply(tp, pi, qi, inters);
*out++ = tp;
}
}
@@ -478,6 +490,14 @@ struct get_turn_info_linear_linear
if ( is_p_spike && is_q_spike )
{
+ if ( tp.method == method_equal
+ && tp.operations[0].operation == operation_continue
+ && tp.operations[1].operation == operation_continue )
+ {
+ // treat both non-opposite collinear spikes as no-spikes
+ return false;
+ }
+
tp.method = method;
tp.operations[0].operation = operation_blocked;
tp.operations[1].operation = operation_blocked;
@@ -527,13 +547,15 @@ struct get_turn_info_linear_linear
bool is_p_last, bool is_q_last,
OutIt out)
{
- bool is_p_spike = ( Version == append_touches ?
+ static const bool is_version_touches = (Version == append_touches);
+
+ bool is_p_spike = ( is_version_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 ?
+ bool is_q_spike = ( is_version_touches ?
( tp.operations[1].operation == operation_continue
|| tp.operations[1].operation == operation_intersection ) :
true )
@@ -542,9 +564,11 @@ struct get_turn_info_linear_linear
bool res = false;
- if ( is_p_spike && ( Version == append_touches || inters.d_info().arrival[0] == 1 ) )
+ if ( is_p_spike
+ && ( BOOST_GEOMETRY_CONDITION(is_version_touches)
+ || inters.d_info().arrival[0] == 1 ) )
{
- if ( Version == append_touches )
+ if ( BOOST_GEOMETRY_CONDITION(is_version_touches) )
{
tp.operations[0].is_collinear = true;
tp.operations[1].is_collinear = false;
@@ -560,8 +584,7 @@ struct get_turn_info_linear_linear
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());
+ AssignPolicy::apply(tp, inters.pi(), inters.qi(), inters);
}
tp.operations[0].operation = operation_blocked;
@@ -574,9 +597,11 @@ struct get_turn_info_linear_linear
res = true;
}
- if ( is_q_spike && ( Version == append_touches || inters.d_info().arrival[1] == 1 ) )
+ if ( is_q_spike
+ && ( BOOST_GEOMETRY_CONDITION(is_version_touches)
+ || inters.d_info().arrival[1] == 1 ) )
{
- if ( Version == append_touches )
+ if ( BOOST_GEOMETRY_CONDITION(is_version_touches) )
{
tp.operations[0].is_collinear = false;
tp.operations[1].is_collinear = true;
@@ -591,8 +616,7 @@ struct get_turn_info_linear_linear
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());
+ AssignPolicy::apply(tp, inters.pi(), inters.qi(), inters);
}
tp.operations[0].operation = operation_intersection;
diff --git a/boost/geometry/algorithms/detail/overlay/get_turns.hpp b/boost/geometry/algorithms/detail/overlay/get_turns.hpp
index a96538c..a5d8f3f 100644
--- a/boost/geometry/algorithms/detail/overlay/get_turns.hpp
+++ b/boost/geometry/algorithms/detail/overlay/get_turns.hpp
@@ -54,6 +54,7 @@
#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
#include <boost/geometry/algorithms/detail/partition.hpp>
#include <boost/geometry/algorithms/detail/recalculate.hpp>
+#include <boost/geometry/algorithms/detail/sections/section_box_policies.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp>
@@ -62,8 +63,7 @@
#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/section_functions.hpp>
#ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION
# include <sstream>
@@ -229,7 +229,7 @@ public :
// section 2: [--------------]
// section 1: |----|---|---|---|---|
for (prev1 = it1++, next1++;
- it1 != end1 && ! exceeding<0>(dir1, *prev1, sec2.bounding_box, robust_policy);
+ it1 != end1 && ! detail::section::exceeding<0>(dir1, *prev1, sec2.bounding_box, robust_policy);
++prev1, ++it1, ++index1, ++next1, ++ndi1)
{
ever_circling_iterator<range1_iterator> nd_next1(
@@ -247,7 +247,7 @@ public :
next2++;
for (prev2 = it2++, next2++;
- it2 != end2 && ! exceeding<0>(dir2, *prev2, sec1.bounding_box, robust_policy);
+ it2 != end2 && ! detail::section::exceeding<0>(dir2, *prev2, sec1.bounding_box, robust_policy);
++prev2, ++it2, ++index2, ++next2, ++ndi2)
{
bool skip = same_source;
@@ -299,8 +299,8 @@ public :
if (InterruptPolicy::enabled)
{
if (interrupt_policy.apply(
- std::make_pair(boost::begin(turns) + size_before,
- boost::end(turns))))
+ std::make_pair(range::pos(turns, size_before),
+ boost::end(turns))))
{
return false;
}
@@ -318,25 +318,6 @@ private :
typedef typename model::referring_segment<point1_type const> segment1_type;
typedef typename model::referring_segment<point2_type const> segment2_type;
-
- 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)
- {
- 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, typename RobustPolicy>
- static inline bool exceeding(int dir, Point const& point, Box const& box, RobustPolicy const& robust_policy)
- {
- 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, typename RobustPolicy>
static inline void advance_to_non_duplicate_next(Iterator& next,
RangeIterator const& it, Section const& section, RobustPolicy const& robust_policy)
@@ -387,7 +368,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, robust_policy);
+ for(; it != end && detail::section::preceding<0>(dir, *it, other_bounding_box, robust_policy);
prev = it++, index++, ndi++)
{}
// Go back one step because we want to start completely preceding
@@ -395,24 +376,6 @@ private :
}
};
-struct get_section_box
-{
- template <typename Box, typename InputItem>
- static inline void apply(Box& total, InputItem const& item)
- {
- geometry::expand(total, item.bounding_box);
- }
-};
-
-struct ovelaps_section_box
-{
- template <typename Box, typename InputItem>
- static inline bool apply(Box const& box, InputItem const& item)
- {
- return ! detail::disjoint::disjoint_box_box(box, item.bounding_box);
- }
-};
-
template
<
typename Geometry1, typename Geometry2,
@@ -496,12 +459,15 @@ public:
point_type, RobustPolicy
>::type
> box_type;
- typedef typename geometry::sections<box_type, 2> sections_type;
+ typedef geometry::sections<box_type, 2> sections_type;
sections_type sec1, sec2;
+ typedef boost::mpl::vector_c<std::size_t, 0, 1> dimensions;
- geometry::sectionalize<Reverse1>(geometry1, robust_policy, true, sec1, 0);
- geometry::sectionalize<Reverse2>(geometry2, robust_policy, true, sec2, 1);
+ geometry::sectionalize<Reverse1, dimensions>(geometry1, robust_policy,
+ sec1, 0);
+ geometry::sectionalize<Reverse2, dimensions>(geometry2, robust_policy,
+ sec2, 1);
// ... and then partition them, intersecting overlapping sections in visitor method
section_visitor
@@ -513,7 +479,9 @@ public:
geometry::partition
<
- box_type, get_section_box, ovelaps_section_box
+ box_type,
+ detail::section::get_section_box,
+ detail::section::overlaps_section_box
>::apply(sec1, sec2, visitor);
}
};
@@ -556,7 +524,8 @@ struct get_turns_cs
RobustPolicy const& robust_policy,
Turns& turns,
InterruptPolicy& interrupt_policy,
- int multi_index = -1, int ring_index = -1)
+ signed_index_type multi_index = -1,
+ signed_index_type ring_index = -1)
{
if ( boost::size(range) <= 1)
{
@@ -569,7 +538,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;
+ typedef typename boost::range_size<view_type>::type size_type;
+ size_type segments_count1 = boost::size(view) - 1;
iterator_type it = boost::begin(view);
@@ -582,7 +552,7 @@ struct get_turns_cs
//char previous_side[2] = {0, 0};
- int index = 0;
+ signed_index_type index = 0;
for (iterator_type prev = it++;
it != boost::end(view);
@@ -621,7 +591,7 @@ struct get_turns_cs
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,
+ size_type(index) == segments_count1,
robust_policy,
turns, interrupt_policy);
// Future performance enhancement:
@@ -726,7 +696,7 @@ struct get_turns_polygon_cs
int source_id2, Box const& box,
RobustPolicy const& robust_policy,
Turns& turns, InterruptPolicy& interrupt_policy,
- int multi_index = -1)
+ signed_index_type multi_index = -1)
{
typedef typename geometry::ring_type<Polygon>::type ring_type;
@@ -744,7 +714,7 @@ struct get_turns_polygon_cs
turns, interrupt_policy,
multi_index, -1);
- int i = 0;
+ signed_index_type i = 0;
typename interior_return_type<Polygon const>::type
rings = interior_rings(polygon);
@@ -783,7 +753,7 @@ struct get_turns_multi_polygon_cs
Multi const
>::type iterator_type;
- int i = 0;
+ signed_index_type i = 0;
for (iterator_type it = boost::begin(multi);
it != boost::end(multi);
++it, ++i)
diff --git a/boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp b/boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp
index 085933d..277a223 100644
--- a/boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp
+++ b/boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp
@@ -28,6 +28,11 @@
#include <boost/geometry/geometries/segment.hpp>
+// TODO: the approach below should be completely replaced by the new
+// get_left_turns, to keep the outgoing vector which has open space one of its
+// sides.
+
+
namespace boost { namespace geometry
{
@@ -76,6 +81,12 @@ private :
RobustPolicy
>::type robust_point_type;
+ inline bool default_order(Indexed const& left, Indexed const& right) const
+ {
+ // We've nothing to sort on. Take the indexes
+ return left.turn_index < right.turn_index;
+ }
+
// 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,
@@ -336,7 +347,7 @@ private :
#endif
//debug_consider(0, left, right, header, false, "-> return", ret);
- return left.turn_index < right.turn_index;
+ return default_order(left, right);
}
@@ -369,11 +380,17 @@ private :
// Both located at same side (#58, pie_21_7_21_0_3)
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)
{
- bool ret = side_si_r == 1;
+ int const side_ri_s = m_strategy.apply(si, sj, ri);
+ if (side_si_r == side_ri_s)
+ {
+ return default_order(left, right);
+ }
+
+ // Take the most left one
+ bool const ret = side_si_r == 1;
//debug_consider(0, left, right, header, false, "same side", ret);
return ret;
}
@@ -407,6 +424,12 @@ private :
// One coming from left (#90, #94, #95)
if (side_si_r != 0 && (side_ri_p != 0 || side_si_p != 0))
{
+ int const side_ri_s = m_strategy.apply(si, sj, ri);
+ if (side_si_r == side_ri_s)
+ {
+ return default_order(left, right);
+ }
+
bool ret = false;
#if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO
@@ -464,7 +487,7 @@ private :
return ! consider_iu_iu(right, left, header, true);
}
- return left.turn_index < right.turn_index;
+ return default_order(left, right);
}
inline bool consider_ii(Indexed const& left, Indexed const& right,
@@ -488,19 +511,17 @@ private :
bool const ret = side_si_r != 1;
return ret;
}
- return left.turn_index < right.turn_index;
+ return default_order(left, right);
}
public :
inline bool operator()(Indexed const& left, Indexed const& right) const
{
- bool const default_order = left.turn_index < right.turn_index;
-
if ((m_turn_points[left.turn_index].discarded || left.discarded)
&& (m_turn_points[right.turn_index].discarded || right.discarded))
{
- return default_order;
+ return default_order(left, right);
}
else if (m_turn_points[left.turn_index].discarded || left.discarded)
{
@@ -525,7 +546,7 @@ public :
// uu/uu, Order is arbitrary
// Note: uu/uu is discarded now before so this point will
// not be reached.
- return default_order;
+ return default_order(left, right);
}
else if (m_turn_points[left.turn_index].combination(operation_intersection, operation_union)
&& m_turn_points[right.turn_index].combination(operation_intersection, operation_union))
@@ -587,7 +608,7 @@ public :
<< std::endl;
#endif
- return default_order;
+ return default_order(left, right);
}
};
@@ -708,7 +729,7 @@ inline void handle_cluster(Iterator begin_cluster, Iterator end_cluster,
for_operation, geometry1, geometry2, strategy);
- // Then sort this range (discard rows will be ordered first and will be removed in enrich_assign)
+ // Then sort this range (discarded rows will be ordered first and will be removed in enrich_assign)
std::sort(begin_cluster, end_cluster,
sort_in_cluster
<
diff --git a/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp b/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp
index a13a627..3101de8 100644
--- a/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp
+++ b/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp
@@ -43,9 +43,9 @@
#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>
+#include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
+#include <boost/geometry/io/wkt/wkt.hpp>
#endif
namespace boost { namespace geometry
@@ -254,9 +254,10 @@ struct intersection_of_linestring_with_areal
#if defined(BOOST_GEOMETRY_DEBUG_FOLLOW)
int index = 0;
- BOOST_FOREACH(turn_info const& turn, turns)
+ for(typename std::deque<turn_info>::const_iterator
+ it = turns.begin(); it != turns.end(); ++it)
{
- debug_follow(turn, turn.operations[0], index++);
+ debug_follow(*it, it->operations[0], index++);
}
#endif
diff --git a/boost/geometry/algorithms/detail/overlay/linear_linear.hpp b/boost/geometry/algorithms/detail/overlay/linear_linear.hpp
index 3a7a7a7..d4ebcf2 100644
--- a/boost/geometry/algorithms/detail/overlay/linear_linear.hpp
+++ b/boost/geometry/algorithms/detail/overlay/linear_linear.hpp
@@ -144,11 +144,10 @@ protected:
typename Info,
typename Point1,
typename Point2,
- typename IntersectionInfo,
- typename DirInfo
+ typename IntersectionInfo
>
static inline void apply(Info& , Point1 const& , Point2 const& ,
- IntersectionInfo const& , DirInfo const& )
+ IntersectionInfo const& )
{
}
};
diff --git a/boost/geometry/algorithms/detail/overlay/overlay.hpp b/boost/geometry/algorithms/detail/overlay/overlay.hpp
index 44b5a0d..a2f5284 100644
--- a/boost/geometry/algorithms/detail/overlay/overlay.hpp
+++ b/boost/geometry/algorithms/detail/overlay/overlay.hpp
@@ -44,10 +44,6 @@
# include <boost/geometry/io/dsv/write.hpp>
#endif
-#ifdef BOOST_GEOMETRY_TIME_OVERLAY
-# include <boost/timer.hpp>
-#endif
-
namespace boost { namespace geometry
{
@@ -57,19 +53,10 @@ namespace boost { namespace geometry
namespace detail { namespace overlay
{
-// Skip for assemble process
-template <typename TurnInfo>
-inline bool skip(TurnInfo const& turn_info)
-{
- return (turn_info.discarded || turn_info.both(operation_union))
- && ! turn_info.any_blocked()
- && ! turn_info.both(operation_intersection)
- ;
-}
-
-template <typename TurnPoints, typename Map>
-inline void map_turns(Map& map, TurnPoints const& turn_points)
+template <typename TurnPoints, typename TurnInfoMap>
+inline void get_ring_turn_info(TurnInfoMap& turn_info_map,
+ TurnPoints const& turn_points)
{
typedef typename boost::range_value<TurnPoints>::type turn_point_type;
typedef typename turn_point_type::container_type container_type;
@@ -79,20 +66,32 @@ inline void map_turns(Map& map, TurnPoints const& turn_points)
it != boost::end(turn_points);
++it)
{
- if (! skip(*it))
+ typename boost::range_value<TurnPoints>::type const& turn_info = *it;
+ bool both_uu = turn_info.both(operation_union);
+ bool skip = (turn_info.discarded || both_uu)
+ && ! turn_info.any_blocked()
+ && ! turn_info.both(operation_intersection)
+ ;
+
+ for (typename boost::range_iterator<container_type const>::type
+ op_it = boost::begin(turn_info.operations);
+ op_it != boost::end(turn_info.operations);
+ ++op_it)
{
- for (typename boost::range_iterator<container_type const>::type
- op_it = boost::begin(it->operations);
- op_it != boost::end(it->operations);
- ++op_it)
+ ring_identifier ring_id
+ (
+ op_it->seg_id.source_index,
+ op_it->seg_id.multi_index,
+ op_it->seg_id.ring_index
+ );
+
+ if (! skip)
{
- ring_identifier ring_id
- (
- op_it->seg_id.source_index,
- op_it->seg_id.multi_index,
- op_it->seg_id.ring_index
- );
- map[ring_id]++;
+ turn_info_map[ring_id].has_normal_turn = true;
+ }
+ else if (both_uu)
+ {
+ turn_info_map[ring_id].has_uu_turn = true;
}
}
}
@@ -137,10 +136,10 @@ inline OutputIterator return_if_one_input_is_empty(Geometry1 const& geometry1,
#endif
- std::map<ring_identifier, int> empty;
+ std::map<ring_identifier, ring_turn_info> empty;
std::map<ring_identifier, properties> all_of_one_of_them;
- select_rings<Direction>(geometry1, geometry2, empty, all_of_one_of_them, false);
+ select_rings<Direction>(geometry1, geometry2, empty, all_of_one_of_them);
ring_container_type rings;
assign_parents(geometry1, geometry2, rings, all_of_one_of_them);
return add_rings<GeometryOut>(all_of_one_of_them, geometry1, geometry2, rings, out);
@@ -193,10 +192,6 @@ struct overlay
container_type turn_points;
-#ifdef BOOST_GEOMETRY_TIME_OVERLAY
- boost::timer timer;
-#endif
-
#ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE
std::cout << "get turns" << std::endl;
#endif
@@ -207,10 +202,6 @@ std::cout << "get turns" << std::endl;
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;
-#endif
-
#ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE
std::cout << "enrich" << std::endl;
#endif
@@ -223,11 +214,6 @@ std::cout << "enrich" << std::endl;
robust_policy,
side_strategy);
-#ifdef BOOST_GEOMETRY_TIME_OVERLAY
- std::cout << "enrich_intersection_points: " << timer.elapsed() << std::endl;
-#endif
-
-
#ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE
std::cout << "traverse" << std::endl;
#endif
@@ -245,27 +231,18 @@ std::cout << "traverse" << std::endl;
turn_points, rings
);
-#ifdef BOOST_GEOMETRY_TIME_OVERLAY
- std::cout << "traverse: " << timer.elapsed() << std::endl;
-#endif
-
-
- std::map<ring_identifier, int> map;
- map_turns(map, turn_points);
-
-#ifdef BOOST_GEOMETRY_TIME_OVERLAY
- std::cout << "map_turns: " << timer.elapsed() << std::endl;
-#endif
-
- typedef ring_properties<typename geometry::point_type<GeometryOut>::type> properties;
-
- std::map<ring_identifier, properties> selected;
- select_rings<Direction>(geometry1, geometry2, map, selected, ! turn_points.empty());
+ std::map<ring_identifier, ring_turn_info> turn_info_per_ring;
+ get_ring_turn_info(turn_info_per_ring, turn_points);
-#ifdef BOOST_GEOMETRY_TIME_OVERLAY
- std::cout << "select_rings: " << timer.elapsed() << std::endl;
-#endif
+ typedef ring_properties
+ <
+ typename geometry::point_type<GeometryOut>::type
+ > properties;
+ // Select all rings which are NOT touched by any intersection point
+ std::map<ring_identifier, properties> selected_ring_properties;
+ select_rings<Direction>(geometry1, geometry2, turn_info_per_ring,
+ selected_ring_properties);
// Add rings created during traversal
{
@@ -275,24 +252,15 @@ std::cout << "traverse" << std::endl;
it != boost::end(rings);
++it)
{
- selected[id] = properties(*it, true);
- selected[id].reversed = ReverseOut;
+ selected_ring_properties[id] = properties(*it);
+ selected_ring_properties[id].reversed = ReverseOut;
id.multi_index++;
}
}
-#ifdef BOOST_GEOMETRY_TIME_OVERLAY
- std::cout << "add traversal rings: " << timer.elapsed() << std::endl;
-#endif
-
-
- assign_parents(geometry1, geometry2, rings, selected);
-
-#ifdef BOOST_GEOMETRY_TIME_OVERLAY
- std::cout << "assign_parents: " << timer.elapsed() << std::endl;
-#endif
+ assign_parents(geometry1, geometry2, rings, selected_ring_properties);
- return add_rings<GeometryOut>(selected, geometry1, geometry2, rings, out);
+ return add_rings<GeometryOut>(selected_ring_properties, geometry1, geometry2, rings, out);
}
};
diff --git a/boost/geometry/algorithms/detail/overlay/ring_properties.hpp b/boost/geometry/algorithms/detail/overlay/ring_properties.hpp
index a608869..b469052 100644
--- a/boost/geometry/algorithms/detail/overlay/ring_properties.hpp
+++ b/boost/geometry/algorithms/detail/overlay/ring_properties.hpp
@@ -33,8 +33,7 @@ struct ring_properties
Point point;
area_type area;
- // Filled by "update_selection_map"
- int within_code;
+ // Filled by "update_ring_selection"
bool reversed;
// Filled/used by "assign_rings"
@@ -45,21 +44,22 @@ struct ring_properties
inline ring_properties()
: area(area_type())
- , within_code(-1)
, reversed(false)
, discarded(false)
, parent_area(-1)
{}
template <typename RingOrBox>
- inline ring_properties(RingOrBox const& ring_or_box, bool midpoint)
- : within_code(-1)
- , reversed(false)
+ inline ring_properties(RingOrBox const& ring_or_box)
+ : reversed(false)
, discarded(false)
, parent_area(-1)
{
this->area = geometry::area(ring_or_box);
- geometry::point_on_border(this->point, ring_or_box, midpoint);
+ // We should take a point somewhere in the middle of the ring,
+ // to avoid taking a point on a (self)tangency,
+ // in cases where multiple points come together
+ geometry::point_on_border(this->point, ring_or_box, true);
}
inline area_type get_area() const
diff --git a/boost/geometry/algorithms/detail/overlay/select_rings.hpp b/boost/geometry/algorithms/detail/overlay/select_rings.hpp
index 385658a..d18e012 100644
--- a/boost/geometry/algorithms/detail/overlay/select_rings.hpp
+++ b/boost/geometry/algorithms/detail/overlay/select_rings.hpp
@@ -1,6 +1,6 @@
// 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.
// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
// Use, modification and distribution is subject to the Boost Software License,
@@ -20,7 +20,6 @@
#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>
#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
@@ -34,6 +33,18 @@ namespace boost { namespace geometry
namespace detail { namespace overlay
{
+struct ring_turn_info
+{
+ bool has_uu_turn;
+ bool has_normal_turn;
+ bool within_other;
+
+ ring_turn_info()
+ : has_uu_turn(false)
+ , has_normal_turn(false)
+ , within_other(false)
+ {}
+};
namespace dispatch
{
@@ -45,41 +56,41 @@ namespace dispatch
template <typename Box>
struct select_rings<box_tag, Box>
{
- template <typename Geometry, typename Map>
+ template <typename Geometry, typename RingPropertyMap>
static inline void apply(Box const& box, Geometry const& ,
- ring_identifier const& id, Map& map, bool midpoint)
+ ring_identifier const& id, RingPropertyMap& ring_properties)
{
- map[id] = typename Map::mapped_type(box, midpoint);
+ ring_properties[id] = typename RingPropertyMap::mapped_type(box);
}
- template <typename Map>
+ template <typename RingPropertyMap>
static inline void apply(Box const& box,
- ring_identifier const& id, Map& map, bool midpoint)
+ ring_identifier const& id, RingPropertyMap& ring_properties)
{
- map[id] = typename Map::mapped_type(box, midpoint);
+ ring_properties[id] = typename RingPropertyMap::mapped_type(box);
}
};
template <typename Ring>
struct select_rings<ring_tag, Ring>
{
- template <typename Geometry, typename Map>
+ template <typename Geometry, typename RingPropertyMap>
static inline void apply(Ring const& ring, Geometry const& ,
- ring_identifier const& id, Map& map, bool midpoint)
+ ring_identifier const& id, RingPropertyMap& ring_properties)
{
if (boost::size(ring) > 0)
{
- map[id] = typename Map::mapped_type(ring, midpoint);
+ ring_properties[id] = typename RingPropertyMap::mapped_type(ring);
}
}
- template <typename Map>
+ template <typename RingPropertyMap>
static inline void apply(Ring const& ring,
- ring_identifier const& id, Map& map, bool midpoint)
+ ring_identifier const& id, RingPropertyMap& ring_properties)
{
if (boost::size(ring) > 0)
{
- map[id] = typename Map::mapped_type(ring, midpoint);
+ ring_properties[id] = typename RingPropertyMap::mapped_type(ring);
}
}
};
@@ -88,14 +99,14 @@ namespace dispatch
template <typename Polygon>
struct select_rings<polygon_tag, Polygon>
{
- template <typename Geometry, typename Map>
+ template <typename Geometry, typename RingPropertyMap>
static inline void apply(Polygon const& polygon, Geometry const& geometry,
- ring_identifier id, Map& map, bool midpoint)
+ ring_identifier id, RingPropertyMap& ring_properties)
{
typedef typename geometry::ring_type<Polygon>::type ring_type;
typedef select_rings<ring_tag, ring_type> per_ring;
- per_ring::apply(exterior_ring(polygon), geometry, id, map, midpoint);
+ per_ring::apply(exterior_ring(polygon), geometry, id, ring_properties);
typename interior_return_type<Polygon const>::type
rings = interior_rings(polygon);
@@ -103,18 +114,18 @@ namespace dispatch
it = boost::begin(rings); it != boost::end(rings); ++it)
{
id.ring_index++;
- per_ring::apply(*it, geometry, id, map, midpoint);
+ per_ring::apply(*it, geometry, id, ring_properties);
}
}
- template <typename Map>
+ template <typename RingPropertyMap>
static inline void apply(Polygon const& polygon,
- ring_identifier id, Map& map, bool midpoint)
+ ring_identifier id, RingPropertyMap& ring_properties)
{
typedef typename geometry::ring_type<Polygon>::type ring_type;
typedef select_rings<ring_tag, ring_type> per_ring;
- per_ring::apply(exterior_ring(polygon), id, map, midpoint);
+ per_ring::apply(exterior_ring(polygon), id, ring_properties);
typename interior_return_type<Polygon const>::type
rings = interior_rings(polygon);
@@ -122,7 +133,7 @@ namespace dispatch
it = boost::begin(rings); it != boost::end(rings); ++it)
{
id.ring_index++;
- per_ring::apply(*it, id, map, midpoint);
+ per_ring::apply(*it, id, ring_properties);
}
}
};
@@ -130,9 +141,9 @@ namespace dispatch
template <typename Multi>
struct select_rings<multi_polygon_tag, Multi>
{
- template <typename Geometry, typename Map>
+ template <typename Geometry, typename RingPropertyMap>
static inline void apply(Multi const& multi, Geometry const& geometry,
- ring_identifier id, Map& map, bool midpoint)
+ ring_identifier id, RingPropertyMap& ring_properties)
{
typedef typename boost::range_iterator
<
@@ -145,7 +156,7 @@ namespace dispatch
for (iterator_type it = boost::begin(multi); it != boost::end(multi); ++it)
{
id.ring_index = -1;
- per_polygon::apply(*it, geometry, id, map, midpoint);
+ per_polygon::apply(*it, geometry, id, ring_properties);
id.multi_index++;
}
}
@@ -161,14 +172,12 @@ struct decide
template<>
struct decide<overlay_union>
{
- template <typename Code>
- static bool include(ring_identifier const& , Code const& code)
+ static bool include(ring_identifier const& , ring_turn_info const& info)
{
- return code.within_code * -1 == 1;
+ return info.has_uu_turn || ! info.within_other;
}
- template <typename Code>
- static bool reversed(ring_identifier const& , Code const& )
+ static bool reversed(ring_identifier const& , ring_turn_info const& )
{
return false;
}
@@ -177,31 +186,43 @@ struct decide<overlay_union>
template<>
struct decide<overlay_difference>
{
- template <typename Code>
- static bool include(ring_identifier const& id, Code const& code)
+ static bool include(ring_identifier const& id, ring_turn_info const& info)
{
- bool is_first = id.source_index == 0;
- return code.within_code * -1 * (is_first ? 1 : -1) == 1;
+ // Difference: A - B
+
+ // If this is A (source_index=0) and there is only a u/u turn,
+ // then the ring is inside B
+ // If this is B (source_index=1) and there is only a u/u turn,
+ // then the ring is NOT inside A
+
+ // If this is A and the ring is within the other geometry,
+ // then we should NOT include it.
+ // If this is B then we SHOULD include it.
+
+ bool const is_first = id.source_index == 0;
+ bool const within_other = info.within_other
+ || (is_first && info.has_uu_turn);
+ return is_first ? ! within_other : within_other;
}
- template <typename Code>
- static bool reversed(ring_identifier const& id, Code const& code)
+ static bool reversed(ring_identifier const& id, ring_turn_info const& info)
{
- return include(id, code) && id.source_index == 1;
+ // Difference: A - B
+ // If this is B, and the ring is included, it should be reversed afterwards
+
+ return id.source_index == 1 && include(id, info);
}
};
template<>
struct decide<overlay_intersection>
{
- template <typename Code>
- static bool include(ring_identifier const& , Code const& code)
+ static bool include(ring_identifier const& , ring_turn_info const& info)
{
- return code.within_code * 1 == 1;
+ return ! info.has_uu_turn && info.within_other;
}
- template <typename Code>
- static bool reversed(ring_identifier const& , Code const& )
+ static bool reversed(ring_identifier const& , ring_turn_info const& )
{
return false;
}
@@ -211,61 +232,60 @@ struct decide<overlay_intersection>
template
<
overlay_type OverlayType,
- typename Geometry1, typename Geometry2,
- typename IntersectionMap, typename SelectionMap
+ typename Geometry1,
+ typename Geometry2,
+ typename TurnInfoMap,
+ typename RingPropertyMap
>
-inline void update_selection_map(Geometry1 const& geometry1,
+inline void update_ring_selection(Geometry1 const& geometry1,
Geometry2 const& geometry2,
- IntersectionMap const& intersection_map,
- SelectionMap const& map_with_all, SelectionMap& selection_map)
+ TurnInfoMap const& turn_info_map,
+ RingPropertyMap const& all_ring_properties,
+ RingPropertyMap& selected_ring_properties)
{
- selection_map.clear();
+ selected_ring_properties.clear();
- for (typename SelectionMap::const_iterator it = boost::begin(map_with_all);
- it != boost::end(map_with_all);
+ for (typename RingPropertyMap::const_iterator it = boost::begin(all_ring_properties);
+ it != boost::end(all_ring_properties);
++it)
{
- /*
- int union_code = it->second.within_code * -1;
- bool is_first = it->first.source_index == 0;
- std::cout << it->first << " " << it->second.area
- << ": " << it->second.within_code
- << " union: " << union_code
- << " intersection: " << (it->second.within_code * 1)
- << " G1-G2: " << (union_code * (is_first ? 1 : -1))
- << " G2-G1: " << (union_code * (is_first ? -1 : 1))
- << " -> " << (decide<OverlayType>::include(it->first, it->second) ? "INC" : "")
- << decide<OverlayType>::reverse(it->first, it->second)
- << std::endl;
- */
-
- bool found = intersection_map.find(it->first) != intersection_map.end();
- if (! found)
+ ring_identifier const& id = it->first;
+
+ ring_turn_info info;
+
+ typename TurnInfoMap::const_iterator tcit = turn_info_map.find(id);
+ if (tcit != turn_info_map.end())
{
- ring_identifier const id = it->first;
- typename SelectionMap::mapped_type properties = it->second; // Copy by value
+ info = tcit->second; // Copy by value
+ }
- // Calculate the "within code" (previously this was done earlier but is
- // 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
+ if (info.has_normal_turn)
+ {
+ // There are normal turns on this ring. It should be traversed, we
+ // don't include the original ring
+ continue;
+ }
+
+ if (! info.has_uu_turn)
+ {
+ // Check if the ring is within the other geometry, by taking
+ // a point lying on the ring
switch(id.source_index)
{
case 0 :
- properties.within_code
- = geometry::within(properties.point, geometry2) ? 1 : -1;
+ info.within_other = geometry::within(it->second.point, geometry2);
break;
case 1 :
- properties.within_code
- = geometry::within(properties.point, geometry1) ? 1 : -1;
+ info.within_other = geometry::within(it->second.point, geometry1);
break;
}
+ }
- if (decide<OverlayType>::include(id, properties))
- {
- properties.reversed = decide<OverlayType>::reversed(id, properties);
- selection_map[id] = properties;
- }
+ if (decide<OverlayType>::include(id, info))
+ {
+ typename RingPropertyMap::mapped_type properties = it->second; // Copy by value
+ properties.reversed = decide<OverlayType>::reversed(id, info);
+ selected_ring_properties[id] = properties;
}
}
}
@@ -277,44 +297,47 @@ inline void update_selection_map(Geometry1 const& geometry1,
template
<
overlay_type OverlayType,
- typename Geometry1, typename Geometry2,
- typename IntersectionMap, typename SelectionMap
+ typename Geometry1,
+ typename Geometry2,
+ typename RingTurnInfoMap,
+ typename RingPropertyMap
>
inline void select_rings(Geometry1 const& geometry1, Geometry2 const& geometry2,
- IntersectionMap const& intersection_map,
- SelectionMap& selection_map, bool midpoint)
+ RingTurnInfoMap const& turn_info_per_ring,
+ RingPropertyMap& selected_ring_properties)
{
typedef typename geometry::tag<Geometry1>::type tag1;
typedef typename geometry::tag<Geometry2>::type tag2;
- SelectionMap map_with_all;
+ RingPropertyMap all_ring_properties;
dispatch::select_rings<tag1, Geometry1>::apply(geometry1, geometry2,
- ring_identifier(0, -1, -1), map_with_all, midpoint);
+ ring_identifier(0, -1, -1), all_ring_properties);
dispatch::select_rings<tag2, Geometry2>::apply(geometry2, geometry1,
- ring_identifier(1, -1, -1), map_with_all, midpoint);
+ ring_identifier(1, -1, -1), all_ring_properties);
- update_selection_map<OverlayType>(geometry1, geometry2, intersection_map,
- map_with_all, selection_map);
+ update_ring_selection<OverlayType>(geometry1, geometry2, turn_info_per_ring,
+ all_ring_properties, selected_ring_properties);
}
template
<
overlay_type OverlayType,
typename Geometry,
- typename IntersectionMap, typename SelectionMap
+ typename RingTurnInfoMap,
+ typename RingPropertyMap
>
inline void select_rings(Geometry const& geometry,
- IntersectionMap const& intersection_map,
- SelectionMap& selection_map, bool midpoint)
+ RingTurnInfoMap const& turn_info_per_ring,
+ RingPropertyMap& selected_ring_properties)
{
typedef typename geometry::tag<Geometry>::type tag;
- SelectionMap map_with_all;
+ RingPropertyMap all_ring_properties;
dispatch::select_rings<tag, Geometry>::apply(geometry,
- ring_identifier(0, -1, -1), map_with_all, midpoint);
+ ring_identifier(0, -1, -1), all_ring_properties);
- update_selection_map<OverlayType>(geometry, geometry, intersection_map,
- map_with_all, selection_map);
+ update_ring_selection<OverlayType>(geometry, geometry, turn_info_per_ring,
+ all_ring_properties, selected_ring_properties);
}
diff --git a/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp b/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp
index 8dffeae..b1f984f 100644
--- a/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp
+++ b/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp
@@ -23,9 +23,12 @@
#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>
+#include <boost/geometry/algorithms/detail/sections/section_box_policies.hpp>
#include <boost/geometry/geometries/box.hpp>
+#include <boost/geometry/util/condition.hpp>
+
namespace boost { namespace geometry
{
@@ -96,7 +99,7 @@ struct self_section_visitor
m_rescale_policy,
m_turns, m_interrupt_policy);
}
- if (m_interrupt_policy.has_intersections)
+ if (BOOST_GEOMETRY_CONDITION(m_interrupt_policy.has_intersections))
{
// TODO: we should give partition an interrupt policy.
// Now we throw, and catch below, to stop the partition loop.
@@ -121,15 +124,19 @@ struct get_turns
{
typedef model::box
<
- typename geometry::point_type<Geometry>::type
+ typename geometry::robust_point_type
+ <
+ typename geometry::point_type<Geometry>::type,
+ RobustPolicy
+ >::type
> box_type;
- typedef typename geometry::sections
- <
- box_type, 1
- > sections_type;
+
+ typedef geometry::sections<box_type, 1> sections_type;
+
+ typedef boost::mpl::vector_c<std::size_t, 0> dimensions;
sections_type sec;
- geometry::sectionalize<false>(geometry, robust_policy, false, sec);
+ geometry::sectionalize<false, dimensions>(geometry, robust_policy, sec);
self_section_visitor
<
@@ -142,8 +149,8 @@ struct get_turns
geometry::partition
<
box_type,
- detail::get_turns::get_section_box,
- detail::get_turns::ovelaps_section_box
+ detail::section::get_section_box,
+ detail::section::overlaps_section_box
>::apply(sec, visitor);
}
catch(self_ip_exception const& )
diff --git a/boost/geometry/algorithms/detail/partition.hpp b/boost/geometry/algorithms/detail/partition.hpp
index a44d563..25a34ba 100644
--- a/boost/geometry/algorithms/detail/partition.hpp
+++ b/boost/geometry/algorithms/detail/partition.hpp
@@ -10,7 +10,6 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_PARTITION_HPP
#include <vector>
-#include <boost/assert.hpp>
#include <boost/range/algorithm/copy.hpp>
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
@@ -24,7 +23,7 @@ namespace detail { namespace partition
typedef std::vector<std::size_t> index_vector_type;
template <int Dimension, typename Box>
-void divide_box(Box const& box, Box& lower_box, Box& upper_box)
+inline void divide_box(Box const& box, Box& lower_box, Box& upper_box)
{
typedef typename coordinate_type<Box>::type ctype;
@@ -79,20 +78,39 @@ inline void divide_into_subsets(Box const& lower_box,
}
else
{
- // Is nowhere! Should not occur!
- BOOST_ASSERT(false);
+ // Is nowhere. That is (since 1.58) possible, it might be
+ // skipped by the OverlapsPolicy to enhance performance
}
}
}
+template <typename ExpandPolicy, typename Box, typename InputCollection>
+inline void expand_with_elements(Box& total,
+ InputCollection const& collection,
+ index_vector_type const& input)
+{
+ typedef boost::range_iterator<index_vector_type const>::type it_type;
+ for(it_type it = boost::begin(input); it != boost::end(input); ++it)
+ {
+ ExpandPolicy::apply(total, collection[*it]);
+ }
+}
+
+
// Match collection with itself
template <typename InputCollection, typename Policy>
inline void handle_one(InputCollection const& collection,
index_vector_type const& input,
Policy& policy)
{
+ if (boost::size(input) == 0)
+ {
+ return;
+ }
+
typedef boost::range_iterator<index_vector_type const>::type
index_iterator_type;
+
// Quadratic behaviour at lowest level (lowest quad, or all exceeding)
for(index_iterator_type it1 = boost::begin(input);
it1 != boost::end(input);
@@ -118,6 +136,11 @@ inline void handle_two(
InputCollection2 const& collection2, index_vector_type const& input2,
Policy& policy)
{
+ if (boost::size(input1) == 0 || boost::size(input2) == 0)
+ {
+ return;
+ }
+
typedef boost::range_iterator
<
index_vector_type const
@@ -136,43 +159,116 @@ inline void handle_two(
}
}
+inline bool recurse_ok(index_vector_type const& input,
+ std::size_t min_elements, std::size_t level)
+{
+ return boost::size(input) >= min_elements
+ && level < 100;
+}
+
+inline bool recurse_ok(index_vector_type const& input1,
+ index_vector_type const& input2,
+ std::size_t min_elements, std::size_t level)
+{
+ return boost::size(input1) >= min_elements
+ && recurse_ok(input2, min_elements, level);
+}
+
+inline bool recurse_ok(index_vector_type const& input1,
+ index_vector_type const& input2,
+ index_vector_type const& input3,
+ std::size_t min_elements, std::size_t level)
+{
+ return boost::size(input1) >= min_elements
+ && recurse_ok(input2, input3, min_elements, level);
+}
+
+template
+<
+ int Dimension,
+ typename Box,
+ typename OverlapsPolicy1,
+ typename OverlapsPolicy2,
+ typename ExpandPolicy1,
+ typename ExpandPolicy2,
+ typename VisitBoxPolicy
+>
+class partition_two_collections;
+
+
template
<
int Dimension,
typename Box,
typename OverlapsPolicy,
+ typename ExpandPolicy,
typename VisitBoxPolicy
>
class partition_one_collection
{
typedef std::vector<std::size_t> index_vector_type;
- typedef typename coordinate_type<Box>::type ctype;
- typedef partition_one_collection
+
+ template <typename InputCollection>
+ static inline Box get_new_box(InputCollection const& collection,
+ index_vector_type const& input)
+ {
+ Box box;
+ geometry::assign_inverse(box);
+ expand_with_elements<ExpandPolicy>(box, collection, input);
+ return box;
+ }
+
+ template <typename InputCollection, typename Policy>
+ static inline void next_level(Box const& box,
+ InputCollection const& collection,
+ index_vector_type const& input,
+ std::size_t level, std::size_t min_elements,
+ Policy& policy, VisitBoxPolicy& box_policy)
+ {
+ if (recurse_ok(input, min_elements, level))
+ {
+ partition_one_collection
<
1 - Dimension,
Box,
OverlapsPolicy,
+ ExpandPolicy,
VisitBoxPolicy
- > sub_divide;
+ >::apply(box, collection, input,
+ level + 1, min_elements, policy, box_policy);
+ }
+ else
+ {
+ handle_one(collection, input, policy);
+ }
+ }
+ // Function to switch to two collections if there are geometries exceeding
+ // the separation line
template <typename InputCollection, typename Policy>
- static inline void next_level(Box const& box,
+ static inline void next_level2(Box const& box,
InputCollection const& collection,
- index_vector_type const& input,
- int level, std::size_t min_elements,
+ index_vector_type const& input1,
+ index_vector_type const& input2,
+ std::size_t level, std::size_t min_elements,
Policy& policy, VisitBoxPolicy& box_policy)
{
- if (boost::size(input) > 0)
+
+ if (recurse_ok(input1, input2, min_elements, level))
{
- if (std::size_t(boost::size(input)) > min_elements && level < 100)
- {
- sub_divide::apply(box, collection, input, level + 1,
- min_elements, policy, box_policy);
- }
- else
- {
- handle_one(collection, input, policy);
- }
+ partition_two_collections
+ <
+ 1 - Dimension,
+ Box,
+ OverlapsPolicy, OverlapsPolicy,
+ ExpandPolicy, ExpandPolicy,
+ VisitBoxPolicy
+ >::apply(box, collection, input1, collection, input2,
+ level + 1, min_elements, policy, box_policy);
+ }
+ else
+ {
+ handle_two(collection, input1, collection, input2, policy);
}
}
@@ -181,7 +277,7 @@ public :
static inline void apply(Box const& box,
InputCollection const& collection,
index_vector_type const& input,
- int level,
+ std::size_t level,
std::size_t min_elements,
Policy& policy, VisitBoxPolicy& box_policy)
{
@@ -196,11 +292,20 @@ public :
if (boost::size(exceeding) > 0)
{
- // All what is not fitting a partition should be combined
- // with each other, and with all which is fitting.
- handle_one(collection, exceeding, policy);
- handle_two(collection, exceeding, collection, lower, policy);
- handle_two(collection, exceeding, collection, upper, policy);
+ // Get the box of exceeding-only
+ Box exceeding_box = get_new_box(collection, exceeding);
+
+ // Recursively do exceeding elements only, in next dimension they
+ // will probably be less exceeding within the new box
+ next_level(exceeding_box, collection, exceeding, level,
+ min_elements, policy, box_policy);
+
+ // Switch to two collections, combine exceeding with lower resp upper
+ // but not lower/lower, upper/upper
+ next_level2(exceeding_box, collection, exceeding, lower, level,
+ min_elements, policy, box_policy);
+ next_level2(exceeding_box, collection, exceeding, upper, level,
+ min_elements, policy, box_policy);
}
// Recursively call operation both parts
@@ -217,20 +322,13 @@ template
typename Box,
typename OverlapsPolicy1,
typename OverlapsPolicy2,
+ typename ExpandPolicy1,
+ typename ExpandPolicy2,
typename VisitBoxPolicy
>
class partition_two_collections
{
typedef std::vector<std::size_t> index_vector_type;
- typedef typename coordinate_type<Box>::type ctype;
- typedef partition_two_collections
- <
- 1 - Dimension,
- Box,
- OverlapsPolicy1,
- OverlapsPolicy2,
- VisitBoxPolicy
- > sub_divide;
template
<
@@ -243,25 +341,50 @@ class partition_two_collections
index_vector_type const& input1,
InputCollection2 const& collection2,
index_vector_type const& input2,
- int level, std::size_t min_elements,
+ std::size_t level, std::size_t min_elements,
Policy& policy, VisitBoxPolicy& box_policy)
{
- if (boost::size(input1) > 0 && boost::size(input2) > 0)
- {
- if (std::size_t(boost::size(input1)) > min_elements
- && std::size_t(boost::size(input2)) > min_elements
- && level < 100)
- {
- sub_divide::apply(box, collection1, input1, collection2,
- input2, level + 1, min_elements,
- policy, box_policy);
- }
- else
- {
- box_policy.apply(box, level + 1);
- handle_two(collection1, input1, collection2, input2, policy);
- }
- }
+ partition_two_collections
+ <
+ 1 - Dimension,
+ Box,
+ OverlapsPolicy1,
+ OverlapsPolicy2,
+ ExpandPolicy1,
+ ExpandPolicy2,
+ VisitBoxPolicy
+ >::apply(box, collection1, input1, collection2, input2,
+ level + 1, min_elements,
+ policy, box_policy);
+ }
+
+ template
+ <
+ typename ExpandPolicy,
+ typename InputCollection
+ >
+ static inline Box get_new_box(InputCollection const& collection,
+ index_vector_type const& input)
+ {
+ Box box;
+ geometry::assign_inverse(box);
+ expand_with_elements<ExpandPolicy>(box, collection, input);
+ return box;
+ }
+
+ template
+ <
+ typename InputCollection1,
+ typename InputCollection2
+ >
+ static inline Box get_new_box(InputCollection1 const& collection1,
+ index_vector_type const& input1,
+ InputCollection2 const& collection2,
+ index_vector_type const& input2)
+ {
+ Box box = get_new_box<ExpandPolicy1>(collection1, input1);
+ expand_with_elements<ExpandPolicy2>(box, collection2, input2);
+ return box;
}
public :
@@ -274,7 +397,7 @@ public :
static inline void apply(Box const& box,
InputCollection1 const& collection1, index_vector_type const& input1,
InputCollection2 const& collection2, index_vector_type const& input2,
- int level,
+ std::size_t level,
std::size_t min_elements,
Policy& policy, VisitBoxPolicy& box_policy)
{
@@ -293,36 +416,100 @@ public :
if (boost::size(exceeding1) > 0)
{
// All exceeding from 1 with 2:
- handle_two(collection1, exceeding1, collection2, exceeding2,
- policy);
+
+ if (recurse_ok(exceeding1, exceeding2, min_elements, level))
+ {
+ Box exceeding_box = get_new_box(collection1, exceeding1,
+ collection2, exceeding2);
+ next_level(exceeding_box, collection1, exceeding1,
+ collection2, exceeding2, level,
+ min_elements, policy, box_policy);
+ }
+ else
+ {
+ handle_two(collection1, exceeding1, collection2, exceeding2,
+ policy);
+ }
// All exceeding from 1 with lower and upper of 2:
- handle_two(collection1, exceeding1, collection2, lower2, policy);
- handle_two(collection1, exceeding1, collection2, upper2, policy);
+
+ // (Check sizes of all three collections to avoid recurse into
+ // the same combinations again and again)
+ if (recurse_ok(lower2, upper2, exceeding1, min_elements, level))
+ {
+ Box exceeding_box
+ = get_new_box<ExpandPolicy1>(collection1, exceeding1);
+ next_level(exceeding_box, collection1, exceeding1,
+ collection2, lower2, level, min_elements, policy, box_policy);
+ next_level(exceeding_box, collection1, exceeding1,
+ collection2, upper2, level, min_elements, policy, box_policy);
+ }
+ else
+ {
+ handle_two(collection1, exceeding1, collection2, lower2, policy);
+ handle_two(collection1, exceeding1, collection2, upper2, policy);
+ }
}
+
if (boost::size(exceeding2) > 0)
{
// All exceeding from 2 with lower and upper of 1:
- handle_two(collection1, lower1, collection2, exceeding2, policy);
- handle_two(collection1, upper1, collection2, exceeding2, policy);
+ if (recurse_ok(lower1, upper1, exceeding2, min_elements, level))
+ {
+ Box exceeding_box
+ = get_new_box<ExpandPolicy2>(collection2, exceeding2);
+ next_level(exceeding_box, collection1, lower1,
+ collection2, exceeding2, level, min_elements, policy, box_policy);
+ next_level(exceeding_box, collection1, upper1,
+ collection2, exceeding2, level, min_elements, policy, box_policy);
+ }
+ else
+ {
+ handle_two(collection1, lower1, collection2, exceeding2, policy);
+ handle_two(collection1, upper1, collection2, exceeding2, policy);
+ }
}
- next_level(lower_box, collection1, lower1, collection2, lower2, level,
- min_elements, policy, box_policy);
- next_level(upper_box, collection1, upper1, collection2, upper2, level,
- min_elements, policy, box_policy);
+ if (recurse_ok(lower1, lower2, min_elements, level))
+ {
+ next_level(lower_box, collection1, lower1, collection2, lower2, level,
+ min_elements, policy, box_policy);
+ }
+ else
+ {
+ handle_two(collection1, lower1, collection2, lower2, policy);
+ }
+ if (recurse_ok(upper1, upper2, min_elements, level))
+ {
+ next_level(upper_box, collection1, upper1, collection2, upper2, level,
+ min_elements, policy, box_policy);
+ }
+ else
+ {
+ handle_two(collection1, upper1, collection2, upper2, policy);
+ }
}
};
-}} // namespace detail::partition
-
struct visit_no_policy
{
template <typename Box>
- static inline void apply(Box const&, int )
+ static inline void apply(Box const&, std::size_t )
{}
};
+struct include_all_policy
+{
+ template <typename Item>
+ static inline bool apply(Item const&)
+ {
+ return true;
+ }
+};
+
+
+}} // namespace detail::partition
+
template
<
typename Box,
@@ -330,13 +517,15 @@ template
typename OverlapsPolicy1,
typename ExpandPolicy2 = ExpandPolicy1,
typename OverlapsPolicy2 = OverlapsPolicy1,
- typename VisitBoxPolicy = visit_no_policy
+ typename IncludePolicy1 = detail::partition::include_all_policy,
+ typename IncludePolicy2 = detail::partition::include_all_policy,
+ typename VisitBoxPolicy = detail::partition::visit_no_policy
>
class partition
{
typedef std::vector<std::size_t> index_vector_type;
- template <typename ExpandPolicy, typename InputCollection>
+ template <typename ExpandPolicy, typename IncludePolicy, typename InputCollection>
static inline void expand_to_collection(InputCollection const& collection,
Box& total, index_vector_type& index_vector)
{
@@ -346,8 +535,11 @@ class partition
it != boost::end(collection);
++it, ++index)
{
- ExpandPolicy::apply(total, *it);
- index_vector.push_back(index);
+ if (IncludePolicy::apply(*it))
+ {
+ ExpandPolicy::apply(total, *it);
+ index_vector.push_back(index);
+ }
}
}
@@ -356,7 +548,7 @@ public :
static inline void apply(InputCollection const& collection,
VisitPolicy& visitor,
std::size_t min_elements = 16,
- VisitBoxPolicy box_visitor = visit_no_policy()
+ VisitBoxPolicy box_visitor = detail::partition::visit_no_policy()
)
{
if (std::size_t(boost::size(collection)) > min_elements)
@@ -364,12 +556,14 @@ public :
index_vector_type index_vector;
Box total;
assign_inverse(total);
- expand_to_collection<ExpandPolicy1>(collection, total, index_vector);
+ expand_to_collection<ExpandPolicy1, IncludePolicy1>(collection,
+ total, index_vector);
detail::partition::partition_one_collection
<
0, Box,
OverlapsPolicy1,
+ ExpandPolicy1,
VisitBoxPolicy
>::apply(total, collection, index_vector, 0, min_elements,
visitor, box_visitor);
@@ -403,7 +597,7 @@ public :
InputCollection2 const& collection2,
VisitPolicy& visitor,
std::size_t min_elements = 16,
- VisitBoxPolicy box_visitor = visit_no_policy()
+ VisitBoxPolicy box_visitor = detail::partition::visit_no_policy()
)
{
if (std::size_t(boost::size(collection1)) > min_elements
@@ -412,12 +606,15 @@ public :
index_vector_type index_vector1, index_vector2;
Box total;
assign_inverse(total);
- expand_to_collection<ExpandPolicy1>(collection1, total, index_vector1);
- expand_to_collection<ExpandPolicy2>(collection2, total, index_vector2);
+ expand_to_collection<ExpandPolicy1, IncludePolicy1>(collection1,
+ total, index_vector1);
+ expand_to_collection<ExpandPolicy2, IncludePolicy2>(collection2,
+ total, index_vector2);
detail::partition::partition_two_collections
<
- 0, Box, OverlapsPolicy1, OverlapsPolicy2, VisitBoxPolicy
+ 0, Box, OverlapsPolicy1, OverlapsPolicy2,
+ ExpandPolicy1, ExpandPolicy2, VisitBoxPolicy
>::apply(total,
collection1, index_vector1,
collection2, index_vector2,
diff --git a/boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp b/boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp
index cd3acb5..9db1ef8 100644
--- a/boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp
+++ b/boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp
@@ -17,6 +17,7 @@
#include <boost/geometry/algorithms/detail/recalculate.hpp>
#include <boost/geometry/policies/robustness/robust_point_type.hpp>
#include <boost/geometry/strategies/side.hpp>
+#include <boost/geometry/util/condition.hpp>
#include <boost/geometry/util/math.hpp>
namespace boost { namespace geometry
@@ -91,7 +92,7 @@ static inline bool point_is_spike_or_equal(Point1 const& last_point,
return true;
}
- if (! RobustPolicy::enabled)
+ if (BOOST_GEOMETRY_CONDITION(! RobustPolicy::enabled))
{
return false;
}
diff --git a/boost/geometry/algorithms/detail/relate/areal_areal.hpp b/boost/geometry/algorithms/detail/relate/areal_areal.hpp
index 31d206a..2859841 100644
--- a/boost/geometry/algorithms/detail/relate/areal_areal.hpp
+++ b/boost/geometry/algorithms/detail/relate/areal_areal.hpp
@@ -2,19 +2,21 @@
// 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.
+// This file was modified by Oracle on 2013, 2014, 2015.
+// Modifications copyright (c) 2013-2015 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)
-// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
-
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_AREAL_AREAL_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_AREAL_AREAL_HPP
#include <boost/geometry/core/topological_dimension.hpp>
+
+#include <boost/geometry/util/condition.hpp>
#include <boost/geometry/util/range.hpp>
#include <boost/geometry/algorithms/num_interior_rings.hpp>
@@ -197,7 +199,7 @@ struct areal_areal
// The result should be FFFFFFFFF
relate::set<exterior, exterior, result_dimension<Geometry2>::value>(result);// FFFFFFFFd, d in [1,9] or T
- if ( result.interrupt )
+ if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
return;
// get and analyse turns
@@ -207,17 +209,17 @@ struct areal_areal
interrupt_policy_areal_areal<Result> interrupt_policy(geometry1, geometry2, result);
turns::get_turns<Geometry1, Geometry2>::apply(turns, geometry1, geometry2, interrupt_policy);
- if ( result.interrupt )
+ if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
return;
no_turns_aa_pred<Geometry2, Result, false> pred1(geometry2, result);
for_each_disjoint_geometry_if<0, Geometry1>::apply(turns.begin(), turns.end(), geometry1, pred1);
- if ( result.interrupt )
+ if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
return;
no_turns_aa_pred<Geometry1, Result, true> pred2(geometry1, result);
for_each_disjoint_geometry_if<1, Geometry2>::apply(turns.begin(), turns.end(), geometry2, pred2);
- if ( result.interrupt )
+ if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
return;
if ( turns.empty() )
@@ -242,7 +244,7 @@ struct areal_areal
turns_analyser<turn_type, 0> analyser;
analyse_each_turn(result, analyser, turns.begin(), turns.end());
- if ( result.interrupt )
+ if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
return;
}
@@ -257,7 +259,7 @@ struct areal_areal
uncertain_rings_analyser<0, Result, Geometry1, Geometry2> rings_analyser(result, geometry1, geometry2);
analyse_uncertain_rings<0>::apply(rings_analyser, turns.begin(), turns.end());
- if ( result.interrupt )
+ if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
return;
}
}
@@ -281,7 +283,7 @@ struct areal_areal
turns_analyser<turn_type, 1> analyser;
analyse_each_turn(result, analyser, turns.begin(), turns.end());
- if ( result.interrupt )
+ if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
return;
}
@@ -549,7 +551,7 @@ struct areal_areal
{
analyser.apply(res, it);
- if ( res.interrupt )
+ if ( BOOST_GEOMETRY_CONDITION(res.interrupt) )
return;
}
@@ -573,8 +575,7 @@ struct areal_areal
{
// check which relations must be analysed
- if ( ! may_update<interior, interior, '2', transpose_result>(m_result)
- && ! may_update<boundary, interior, '1', transpose_result>(m_result) )
+ if ( ! may_update<interior, interior, '2', transpose_result>(m_result) )
{
m_flags |= 1;
}
@@ -595,7 +596,7 @@ struct areal_areal
inline void no_turns(segment_identifier const& seg_id)
{
// if those flags are set nothing will change
- if ( (m_flags & 3) == 3 )
+ if ( m_flags == 7 )
{
return;
}
@@ -614,15 +615,18 @@ struct areal_areal
// to know which other single geometries should be checked
// TODO: optimize! e.g. use spatial index
- // O(N) - running it in a loop would gives O(NM)
+ // O(N) - running it in a loop gives O(NM)
int const pig = detail::within::point_in_geometry(range::front(range_ref), other_geometry);
//BOOST_ASSERT(pig != 0);
if ( pig > 0 )
{
- update<boundary, interior, '1', transpose_result>(m_result);
update<interior, interior, '2', transpose_result>(m_result);
m_flags |= 1;
+
+ update<boundary, interior, '1', transpose_result>(m_result);
+ update<exterior, interior, '2', transpose_result>(m_result);
+ m_flags |= 4;
}
else
{
@@ -696,12 +700,6 @@ struct areal_areal
update<boundary, exterior, '1', transpose_result>(m_result);
update<interior, exterior, '2', transpose_result>(m_result);
m_flags |= 2;
-
- // not necessary since this will be checked in the next iteration
- // but increases the pruning strength
- // WARNING: this is not reflected in flags
- update<exterior, boundary, '1', transpose_result>(m_result);
- update<exterior, interior, '2', transpose_result>(m_result);
}
interrupt = m_flags == 7 || m_result.interrupt; // interrupt if the result won't be changed in the future
@@ -795,7 +793,8 @@ struct areal_areal
{
segment_identifier const& seg_id = turn.operations[OpId].seg_id;
- int count = boost::numeric_cast<int>(
+ signed_index_type
+ count = boost::numeric_cast<signed_index_type>(
geometry::num_interior_rings(
detail::single_geometry(analyser.geometry, seg_id)));
@@ -803,7 +802,10 @@ struct areal_areal
}
template <typename Analyser, typename Turn>
- static inline void for_no_turns_rings(Analyser & analyser, Turn const& turn, int first, int last)
+ static inline void for_no_turns_rings(Analyser & analyser,
+ Turn const& turn,
+ signed_index_type first,
+ signed_index_type last)
{
segment_identifier seg_id = turn.operations[OpId].seg_id;
diff --git a/boost/geometry/algorithms/detail/relate/follow_helpers.hpp b/boost/geometry/algorithms/detail/relate/follow_helpers.hpp
index 78fa037..2c44b00 100644
--- a/boost/geometry/algorithms/detail/relate/follow_helpers.hpp
+++ b/boost/geometry/algorithms/detail/relate/follow_helpers.hpp
@@ -14,6 +14,7 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_FOLLOW_HELPERS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_FOLLOW_HELPERS_HPP
+#include <boost/geometry/util/condition.hpp>
#include <boost/geometry/util/range.hpp>
//#include <boost/geometry/algorithms/detail/sub_range.hpp>
@@ -98,9 +99,9 @@ struct for_each_disjoint_geometry_if<OpId, Geometry, Tag, true>
std::vector<bool> detected_intersections(count, false);
for ( TurnIt it = first ; it != last ; ++it )
{
- int multi_index = it->operations[OpId].seg_id.multi_index;
+ signed_index_type multi_index = it->operations[OpId].seg_id.multi_index;
BOOST_ASSERT(multi_index >= 0);
- std::size_t index = static_cast<std::size_t>(multi_index);
+ std::size_t const index = static_cast<std::size_t>(multi_index);
BOOST_ASSERT(index < count);
detected_intersections[index] = true;
}
@@ -116,8 +117,8 @@ struct for_each_disjoint_geometry_if<OpId, Geometry, Tag, true>
if ( *it == false )
{
found = true;
- bool cont = pred(range::at(geometry,
- std::distance(detected_intersections.begin(), it)));
+ std::size_t const index = std::size_t(std::distance(detected_intersections.begin(), it));
+ bool cont = pred(range::at(geometry, index));
if ( !cont )
break;
}
@@ -375,14 +376,14 @@ static inline bool is_ip_on_boundary(IntersectionPoint const& ip,
bool res = false;
// IP on the last point of the linestring
- if ( (BoundaryQuery == boundary_back || BoundaryQuery == boundary_any)
+ if ( BOOST_GEOMETRY_CONDITION(BoundaryQuery == boundary_back || BoundaryQuery == boundary_any)
&& operation_info.position == overlay::position_back )
{
// check if this point is a boundary
res = boundary_checker.template is_endpoint_boundary<boundary_back>(ip);
}
// IP on the last point of the linestring
- else if ( (BoundaryQuery == boundary_front || BoundaryQuery == boundary_any)
+ else if ( BOOST_GEOMETRY_CONDITION(BoundaryQuery == boundary_front || BoundaryQuery == boundary_any)
&& operation_info.position == overlay::position_front )
{
// check if this point is a boundary
diff --git a/boost/geometry/algorithms/detail/relate/linear_areal.hpp b/boost/geometry/algorithms/detail/relate/linear_areal.hpp
index 3159ab3..7d85a1d 100644
--- a/boost/geometry/algorithms/detail/relate/linear_areal.hpp
+++ b/boost/geometry/algorithms/detail/relate/linear_areal.hpp
@@ -2,21 +2,23 @@
// 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.
+// This file was modified by Oracle on 2013, 2014, 2015.
+// Modifications copyright (c) 2013-2015 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)
-// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
-
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_AREAL_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_AREAL_HPP
#include <boost/core/ignore_unused.hpp>
#include <boost/geometry/core/topological_dimension.hpp>
+
+#include <boost/geometry/util/condition.hpp>
#include <boost/geometry/util/range.hpp>
#include <boost/geometry/algorithms/num_interior_rings.hpp>
@@ -193,6 +195,33 @@ struct linear_areal
typedef typename geometry::point_type<Geometry1>::type point1_type;
typedef typename geometry::point_type<Geometry2>::type point2_type;
+
+ template <typename Geometry>
+ struct is_multi
+ : boost::is_base_of
+ <
+ multi_tag,
+ typename tag<Geometry>::type
+ >
+ {};
+
+ template <typename Geom1, typename Geom2>
+ struct multi_turn_info
+ : turns::get_turns<Geom1, Geom2>::turn_info
+ {
+ multi_turn_info() : priority(0) {}
+ int priority; // single-geometry sorting priority
+ };
+
+ template <typename Geom1, typename Geom2>
+ struct turn_info_type
+ : boost::mpl::if_c
+ <
+ is_multi<Geometry2>::value,
+ multi_turn_info<Geom1, Geom2>,
+ typename turns::get_turns<Geom1, Geom2>::turn_info
+ >
+ {};
template <typename Result>
static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Result & result)
@@ -202,17 +231,17 @@ struct linear_areal
// The result should be FFFFFFFFF
relate::set<exterior, exterior, result_dimension<Geometry2>::value, TransposeResult>(result);// FFFFFFFFd, d in [1,9] or T
- if ( result.interrupt )
+ if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) )
return;
// get and analyse turns
- typedef typename turns::get_turns<Geometry1, Geometry2>::turn_info turn_type;
+ typedef typename turn_info_type<Geometry1, Geometry2>::type turn_type;
std::vector<turn_type> turns;
interrupt_policy_linear_areal<Geometry2, Result> interrupt_policy(geometry2, result);
turns::get_turns<Geometry1, Geometry2>::apply(turns, geometry1, geometry2, interrupt_policy);
- if ( result.interrupt )
+ if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) )
return;
boundary_checker<Geometry1> boundary_checker1(geometry1);
@@ -224,12 +253,12 @@ struct linear_areal
TransposeResult
> pred1(geometry2, result, boundary_checker1);
for_each_disjoint_geometry_if<0, Geometry1>::apply(turns.begin(), turns.end(), geometry1, pred1);
- if ( result.interrupt )
+ if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) )
return;
no_turns_la_areal_pred<Result, !TransposeResult> pred2(result);
for_each_disjoint_geometry_if<1, Geometry2>::apply(turns.begin(), turns.end(), geometry2, pred2);
- if ( result.interrupt )
+ if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) )
return;
if ( turns.empty() )
@@ -238,14 +267,11 @@ struct linear_areal
// This is set here because in the case if empty Areal geometry were passed
// those shouldn't be set
relate::set<exterior, interior, '2', TransposeResult>(result);// FFFFFF2Fd
- if ( result.interrupt )
+ if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) )
return;
{
- // for different multi or same ring id: x, u, i, c
- // for same multi and different ring id: c, i, u, x
- typedef turns::less<0, turns::less_op_linear_areal<0> > less;
- std::sort(turns.begin(), turns.end(), less());
+ sort_dispatch(turns.begin(), turns.end(), is_multi<Geometry2>());
turns_analyser<turn_type> analyser;
analyse_each_turn(result, analyser,
@@ -253,7 +279,7 @@ struct linear_areal
geometry1, geometry2,
boundary_checker1);
- if ( result.interrupt )
+ if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) )
return;
}
@@ -297,7 +323,7 @@ struct linear_areal
// if there was some previous ring
if ( prev_seg_id_ptr != NULL )
{
- int const next_ring_index = prev_seg_id_ptr->ring_index + 1;
+ signed_index_type const next_ring_index = prev_seg_id_ptr->ring_index + 1;
BOOST_ASSERT(next_ring_index >= 0);
// if one of the last rings of previous single geometry was ommited
@@ -368,7 +394,7 @@ struct linear_areal
// if there was some previous ring
if ( prev_seg_id_ptr != NULL )
{
- int const next_ring_index = prev_seg_id_ptr->ring_index + 1;
+ signed_index_type const next_ring_index = prev_seg_id_ptr->ring_index + 1;
BOOST_ASSERT(next_ring_index >= 0);
// if one of the last rings of previous single geometry was ommited
@@ -383,6 +409,127 @@ struct linear_areal
}
}
+ template <typename It, typename Pred, typename Comp>
+ static void for_each_equal_range(It first, It last, Pred pred, Comp comp)
+ {
+ if ( first == last )
+ return;
+
+ It first_equal = first;
+ It prev = first;
+ for ( ++first ; ; ++first, ++prev )
+ {
+ if ( first == last || !comp(*prev, *first) )
+ {
+ pred(first_equal, first);
+ first_equal = first;
+ }
+
+ if ( first == last )
+ break;
+ }
+ }
+
+ struct same_ip
+ {
+ template <typename Turn>
+ bool operator()(Turn const& left, Turn const& right) const
+ {
+ return left.operations[0].seg_id == right.operations[0].seg_id
+ && left.operations[0].fraction == right.operations[0].fraction;
+ }
+ };
+
+ struct same_ip_and_multi_index
+ {
+ template <typename Turn>
+ bool operator()(Turn const& left, Turn const& right) const
+ {
+ return same_ip()(left, right)
+ && left.operations[1].seg_id.multi_index == right.operations[1].seg_id.multi_index;
+ }
+ };
+
+ template <typename OpToPriority>
+ struct set_turns_group_priority
+ {
+ template <typename TurnIt>
+ void operator()(TurnIt first, TurnIt last) const
+ {
+ BOOST_ASSERT(first != last);
+ static OpToPriority op_to_priority;
+ // find the operation with the least priority
+ int least_priority = op_to_priority(first->operations[0]);
+ for ( TurnIt it = first + 1 ; it != last ; ++it )
+ {
+ int priority = op_to_priority(it->operations[0]);
+ if ( priority < least_priority )
+ least_priority = priority;
+ }
+ // set the least priority for all turns of the group
+ for ( TurnIt it = first ; it != last ; ++it )
+ {
+ it->priority = least_priority;
+ }
+ }
+ };
+
+ template <typename SingleLess>
+ struct sort_turns_group
+ {
+ struct less
+ {
+ template <typename Turn>
+ bool operator()(Turn const& left, Turn const& right) const
+ {
+ return left.operations[1].seg_id.multi_index == right.operations[1].seg_id.multi_index ?
+ SingleLess()(left, right) :
+ left.priority < right.priority;
+ }
+ };
+
+ template <typename TurnIt>
+ void operator()(TurnIt first, TurnIt last) const
+ {
+ std::sort(first, last, less());
+ }
+ };
+
+ template <typename TurnIt>
+ static void sort_dispatch(TurnIt first, TurnIt last, boost::true_type const& /*is_multi*/)
+ {
+ // sort turns by Linear seg_id, then by fraction, then by other multi_index
+ typedef turns::less<0, turns::less_other_multi_index<0> > less;
+ std::sort(first, last, less());
+
+ // For the same IP and multi_index - the same other's single geometry
+ // set priorities as the least operation found for the whole single geometry
+ // so e.g. single geometries containing 'u' will always be before those only containing 'i'
+ typedef turns::op_to_int<0,2,3,1,4,0> op_to_int_xuic;
+ for_each_equal_range(first, last,
+ set_turns_group_priority<op_to_int_xuic>(), // least operation in xuic order
+ same_ip_and_multi_index()); // other's multi_index
+
+ // When priorities for single geometries are set now sort turns for the same IP
+ // if multi_index is the same sort them according to the single-less
+ // else use priority of the whole single-geometry set earlier
+ typedef turns::less<0, turns::less_op_linear_areal_single<0> > single_less;
+ for_each_equal_range(first, last,
+ sort_turns_group<single_less>(),
+ same_ip());
+ }
+
+ template <typename TurnIt>
+ static void sort_dispatch(TurnIt first, TurnIt last, boost::false_type const& /*is_multi*/)
+ {
+ // sort turns by Linear seg_id, then by fraction, then
+ // for same ring id: x, u, i, c
+ // for different ring id: c, i, u, x
+ typedef turns::less<0, turns::less_op_linear_areal_single<0> > less;
+ std::sort(first, last, less());
+ }
+
+
// interrupt policy which may be passed to get_turns to interrupt the analysis
// based on the info in the passed result/mask
template <typename Areal, typename Result>
@@ -458,6 +605,8 @@ struct linear_areal
, m_boundary_counter(0)
, m_interior_detected(false)
, m_first_interior_other_id_ptr(NULL)
+ , m_first_from_unknown(false)
+ , m_first_from_unknown_boundary_detected(false)
{}
template <typename Result,
@@ -485,6 +634,11 @@ struct linear_areal
const bool first_in_range = m_seg_watcher.update(seg_id);
+ // TODO: should apply() for the post-last ip be called if first_in_range ?
+ // this would unify how last points in ranges are handled
+ // possibly replacing parts of the code below
+ // e.g. for is_multi and m_interior_detected
+
// handle possible exit
bool fake_enter_detected = false;
if ( m_exit_watcher.get_exit_operation() == overlay::operation_union )
@@ -495,8 +649,24 @@ struct linear_areal
{
m_exit_watcher.reset_detected_exit();
- // not the last IP
update<interior, exterior, '1', TransposeResult>(res);
+
+ // next single geometry
+ if ( first_in_range && m_previous_turn_ptr )
+ {
+ // NOTE: similar code is in the post-last-ip-apply()
+ segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id;
+
+ bool const prev_back_b = is_endpoint_on_boundary<boundary_back>(
+ range::back(sub_range(geometry, prev_seg_id)),
+ boundary_checker);
+
+ // if there is a boundary on the last point
+ if ( prev_back_b )
+ {
+ update<boundary, exterior, '0', TransposeResult>(res);
+ }
+ }
}
// fake exit point, reset state
else if ( op == overlay::operation_intersection
@@ -508,9 +678,12 @@ struct linear_areal
}
else if ( m_exit_watcher.get_exit_operation() == overlay::operation_blocked )
{
- // ignore multiple BLOCKs
- if ( op == overlay::operation_blocked )
+ // ignore multiple BLOCKs for this same single geometry1
+ if ( op == overlay::operation_blocked
+ && seg_id.multi_index == m_previous_turn_ptr->operations[op_id].seg_id.multi_index )
+ {
return;
+ }
if ( ( op == overlay::operation_intersection
|| op == overlay::operation_continue )
@@ -522,11 +695,39 @@ struct linear_areal
m_exit_watcher.reset_detected_exit();
}
+ if ( BOOST_GEOMETRY_CONDITION( is_multi<OtherGeometry>::value )
+ && m_first_from_unknown )
+ {
+ // For MultiPolygon many x/u operations may be generated as a first IP
+ // if for all turns x/u was generated and any of the Polygons doesn't contain the LineString
+ // then we know that the LineString is outside
+ // Similar with the u/u turns, if it was the first one it doesn't mean that the
+ // Linestring came from the exterior
+ if ( ( m_previous_operation == overlay::operation_blocked
+ && ( op != overlay::operation_blocked // operation different than block
+ || seg_id.multi_index != m_previous_turn_ptr->operations[op_id].seg_id.multi_index ) ) // or the next single-geometry
+ || ( m_previous_operation == overlay::operation_union
+ && ! turn_on_the_same_ip<op_id>(*m_previous_turn_ptr, *it) )
+ )
+ {
+ update<interior, exterior, '1', TransposeResult>(res);
+ if ( m_first_from_unknown_boundary_detected )
+ {
+ update<boundary, exterior, '0', TransposeResult>(res);
+ }
+
+ m_first_from_unknown = false;
+ m_first_from_unknown_boundary_detected = false;
+ }
+ }
+
// NOTE: THE WHOLE m_interior_detected HANDLING IS HERE BECAUSE WE CAN'T EFFICIENTLY SORT TURNS (CORRECTLY)
// BECAUSE THE SAME IP MAY BE REPRESENTED BY TWO SEGMENTS WITH DIFFERENT DISTANCES
// IT WOULD REQUIRE THE CALCULATION OF MAX DISTANCE
// TODO: WE COULD GET RID OF THE TEST IF THE DISTANCES WERE NORMALIZED
+// UPDATE: THEY SHOULD BE NORMALIZED NOW
+
// TODO: THIS IS POTENTIALLY ERROREOUS!
// THIS ALGORITHM DEPENDS ON SOME SPECIFIC SEQUENCE OF OPERATIONS
// IT WOULD GIVE WRONG RESULTS E.G.
@@ -540,6 +741,30 @@ struct linear_areal
{
update<interior, interior, '1', TransposeResult>(res);
m_interior_detected = false;
+
+ // new range detected - reset previous state and check the boundary
+ if ( first_in_range )
+ {
+ // actually it should be != NULL if m_interior_detected
+ // so an assert could be checked here
+ if ( m_previous_turn_ptr )
+ {
+ segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id;
+
+ bool const prev_back_b = is_endpoint_on_boundary<boundary_back>(
+ range::back(sub_range(geometry, prev_seg_id)),
+ boundary_checker);
+
+ // if there is a boundary on the last point
+ if ( prev_back_b )
+ {
+ update<boundary, interior, '0', TransposeResult>(res);
+ }
+ }
+
+ // The exit_watcher is reset below
+ // m_exit_watcher.reset();
+ }
}
// fake interior overlap
else if ( op == overlay::operation_continue )
@@ -560,10 +785,20 @@ struct linear_areal
}
}
+ // NOTE: If post-last-ip apply() was called this wouldn't be needed
+ if ( first_in_range )
+ {
+ m_exit_watcher.reset();
+ m_boundary_counter = 0;
+ m_first_from_unknown = false;
+ m_first_from_unknown_boundary_detected = false;
+ }
+
// i/u, c/u
if ( op == overlay::operation_intersection
|| op == overlay::operation_continue ) // operation_boundary/operation_boundary_intersection
{
+ bool const first_point = first_in_range || m_first_from_unknown;
bool no_enters_detected = m_exit_watcher.is_outside();
m_exit_watcher.enter(*it);
@@ -592,7 +827,7 @@ struct linear_areal
{
// don't add to the count for all met boundaries
// only if this is the "new" boundary
- if ( first_in_range || !it->operations[op_id].is_collinear )
+ if ( first_point || !it->operations[op_id].is_collinear )
++m_boundary_counter;
update<interior, boundary, '1', TransposeResult>(res);
@@ -619,7 +854,7 @@ struct linear_areal
&& it->operations[op_id].position != overlay::position_front )
{
// TODO: calculate_from_inside() is only needed if the current Linestring is not closed
- bool const from_inside = first_in_range
+ bool const from_inside = first_point
&& calculate_from_inside(geometry,
other_geometry,
*it);
@@ -630,7 +865,7 @@ struct linear_areal
update<interior, exterior, '1', TransposeResult>(res);
// if it's the first IP then the first point is outside
- if ( first_in_range )
+ if ( first_point )
{
bool const front_b = is_endpoint_on_boundary<boundary_front>(
range::front(sub_range(geometry, seg_id)),
@@ -647,6 +882,12 @@ struct linear_areal
}
}
}
+
+ if ( BOOST_GEOMETRY_CONDITION( is_multi<OtherGeometry>::value ) )
+ {
+ m_first_from_unknown = false;
+ m_first_from_unknown_boundary_detected = false;
+ }
}
// u/u, x/u
else if ( op == overlay::operation_union || op == overlay::operation_blocked )
@@ -709,7 +950,11 @@ struct linear_areal
if ( it->operations[op_id].position != overlay::position_front )
{
// TODO: calculate_from_inside() is only needed if the current Linestring is not closed
- bool const first_from_inside = first_in_range
+ // NOTE: this is not enough for MultiPolygon and operation_blocked
+ // For LS/MultiPolygon multiple x/u turns may be generated
+ // the first checked Polygon may be the one which LS is outside for.
+ bool const first_point = first_in_range || m_first_from_unknown;
+ bool const first_from_inside = first_point
&& calculate_from_inside(geometry,
other_geometry,
*it);
@@ -719,14 +964,26 @@ struct linear_areal
// notify the exit_watcher that we started inside
m_exit_watcher.enter(*it);
+ // and reset unknown flags since we know that we started inside
+ m_first_from_unknown = false;
+ m_first_from_unknown_boundary_detected = false;
}
else
{
- update<interior, exterior, '1', TransposeResult>(res);
+ if ( BOOST_GEOMETRY_CONDITION( is_multi<OtherGeometry>::value )
+ /*&& ( op == overlay::operation_blocked
+ || op == overlay::operation_union )*/ ) // if we're here it's u or x
+ {
+ m_first_from_unknown = true;
+ }
+ else
+ {
+ update<interior, exterior, '1', TransposeResult>(res);
+ }
}
// first IP on the last segment point - this means that the first point is outside or inside
- if ( first_in_range && ( !this_b || op_blocked ) )
+ if ( first_point && ( !this_b || op_blocked ) )
{
bool const front_b = is_endpoint_on_boundary<boundary_front>(
range::front(sub_range(geometry, seg_id)),
@@ -736,9 +993,23 @@ struct linear_areal
if ( front_b )
{
if ( first_from_inside )
+ {
update<boundary, interior, '0', TransposeResult>(res);
+ }
else
- update<boundary, exterior, '0', TransposeResult>(res);
+ {
+ if ( BOOST_GEOMETRY_CONDITION( is_multi<OtherGeometry>::value )
+ /*&& ( op == overlay::operation_blocked
+ || op == overlay::operation_union )*/ ) // if we're here it's u or x
+ {
+ BOOST_ASSERT(m_first_from_unknown);
+ m_first_from_unknown_boundary_detected = true;
+ }
+ else
+ {
+ update<boundary, exterior, '0', TransposeResult>(res);
+ }
+ }
}
}
}
@@ -774,6 +1045,23 @@ struct linear_areal
boost::ignore_unused(first, last);
//BOOST_ASSERT( first != last );
+ // For MultiPolygon many x/u operations may be generated as a first IP
+ // if for all turns x/u was generated and any of the Polygons doesn't contain the LineString
+ // then we know that the LineString is outside
+ if ( BOOST_GEOMETRY_CONDITION( is_multi<OtherGeometry>::value )
+ && m_first_from_unknown )
+ {
+ update<interior, exterior, '1', TransposeResult>(res);
+ if ( m_first_from_unknown_boundary_detected )
+ {
+ update<boundary, exterior, '0', TransposeResult>(res);
+ }
+
+ // done below
+ //m_first_from_unknown = false;
+ //m_first_from_unknown_boundary_detected = false;
+ }
+
// here, the possible exit is the real one
// we know that we entered and now we exit
if ( /*m_exit_watcher.get_exit_operation() == overlay::operation_union // THIS CHECK IS REDUNDANT
@@ -822,12 +1110,37 @@ struct linear_areal
}
}
- BOOST_ASSERT_MSG(m_previous_operation != overlay::operation_continue,
- "Unexpected operation! Probably the error in get_turns(L,A) or relate(L,A)");
+ // This condition may be false if the Linestring is lying on the Polygon's collinear spike
+ // if Polygon's spikes are not handled in get_turns() or relate() (they currently aren't)
+ //BOOST_ASSERT_MSG(m_previous_operation != overlay::operation_continue,
+ // "Unexpected operation! Probably the error in get_turns(L,A) or relate(L,A)");
+ // Currently one c/c turn is generated for the exit
+ // when a Linestring is going out on a collinear spike
+ // When a Linestring is going in on a collinear spike
+ // the turn is not generated for the entry
+ // So assume it's the former
+ if ( m_previous_operation == overlay::operation_continue )
+ {
+ update<interior, exterior, '1', TransposeResult>(res);
+
+ segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id;
+
+ bool const prev_back_b = is_endpoint_on_boundary<boundary_back>(
+ range::back(sub_range(geometry, prev_seg_id)),
+ boundary_checker);
+
+ // if there is a boundary on the last point
+ if ( prev_back_b )
+ {
+ update<boundary, exterior, '0', TransposeResult>(res);
+ }
+ }
// Reset exit watcher before the analysis of the next Linestring
m_exit_watcher.reset();
m_boundary_counter = 0;
+ m_first_from_unknown = false;
+ m_first_from_unknown_boundary_detected = false;
}
// check if the passed turn's segment of Linear geometry arrived
@@ -852,8 +1165,8 @@ struct linear_areal
BOOST_ASSERT(s2 > 2);
std::size_t const seg_count2 = s2 - 1;
- std::size_t const p_seg_ij = turn.operations[op_id].seg_id.segment_index;
- std::size_t const q_seg_ij = turn.operations[other_op_id].seg_id.segment_index;
+ std::size_t const p_seg_ij = static_cast<std::size_t>(turn.operations[op_id].seg_id.segment_index);
+ std::size_t const q_seg_ij = static_cast<std::size_t>(turn.operations[other_op_id].seg_id.segment_index);
BOOST_ASSERT(p_seg_ij + 1 < boost::size(range1));
BOOST_ASSERT(q_seg_ij + 1 < s2);
@@ -876,7 +1189,7 @@ struct linear_areal
// TODO: the following function should return immediately, however the worst case complexity is O(N)
// It would be good to replace it with some O(1) mechanism
range2_iterator qk_it = find_next_non_duplicated(boost::begin(range2),
- boost::begin(range2) + q_seg_jk,
+ range::pos(range2, q_seg_jk),
boost::end(range2));
// Will this sequence of points be always correct?
@@ -945,6 +1258,8 @@ struct linear_areal
unsigned m_boundary_counter;
bool m_interior_detected;
const segment_identifier * m_first_interior_other_id_ptr;
+ bool m_first_from_unknown;
+ bool m_first_from_unknown_boundary_detected;
};
// call analyser.apply() for each turn in range
@@ -971,7 +1286,7 @@ struct linear_areal
geometry, other_geometry,
boundary_checker);
- if ( res.interrupt )
+ if ( BOOST_GEOMETRY_CONDITION( res.interrupt ) )
return;
}
@@ -1017,8 +1332,8 @@ struct linear_areal
if ( first == last )
return last;
- int const multi_index = first->operations[1].seg_id.multi_index;
- int const ring_index = first->operations[1].seg_id.ring_index;
+ signed_index_type const multi_index = first->operations[1].seg_id.multi_index;
+ signed_index_type const ring_index = first->operations[1].seg_id.ring_index;
fun(*first);
++first;
diff --git a/boost/geometry/algorithms/detail/relate/linear_linear.hpp b/boost/geometry/algorithms/detail/relate/linear_linear.hpp
index 263c82d..20a22c3 100644
--- a/boost/geometry/algorithms/detail/relate/linear_linear.hpp
+++ b/boost/geometry/algorithms/detail/relate/linear_linear.hpp
@@ -2,8 +2,8 @@
// 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.
+// This file was modified by Oracle on 2013, 2014, 2015.
+// Modifications copyright (c) 2013-2015 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
@@ -16,6 +16,7 @@
#include <boost/core/ignore_unused.hpp>
+#include <boost/geometry/util/condition.hpp>
#include <boost/geometry/util/range.hpp>
#include <boost/geometry/algorithms/detail/sub_range.hpp>
@@ -117,7 +118,7 @@ struct linear_linear
{
// The result should be FFFFFFFFF
relate::set<exterior, exterior, result_dimension<Geometry1>::value>(result);// FFFFFFFFd, d in [1,9] or T
- if ( result.interrupt )
+ if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) )
return;
// get and analyse turns
@@ -133,19 +134,19 @@ struct linear_linear
detail::get_turns::get_turn_info_type<Geometry1, Geometry2, turns::assign_policy<true> >
>::apply(turns, geometry1, geometry2, interrupt_policy);
- if ( result.interrupt )
+ if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) )
return;
boundary_checker<Geometry1> boundary_checker1(geometry1);
disjoint_linestring_pred<Result, boundary_checker<Geometry1>, false> pred1(result, boundary_checker1);
for_each_disjoint_geometry_if<0, Geometry1>::apply(turns.begin(), turns.end(), geometry1, pred1);
- if ( result.interrupt )
+ if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) )
return;
boundary_checker<Geometry2> boundary_checker2(geometry2);
disjoint_linestring_pred<Result, boundary_checker<Geometry2>, true> pred2(result, boundary_checker2);
for_each_disjoint_geometry_if<1, Geometry2>::apply(turns.begin(), turns.end(), geometry2, pred2);
- if ( result.interrupt )
+ if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) )
return;
if ( turns.empty() )
@@ -171,7 +172,7 @@ struct linear_linear
boundary_checker1, boundary_checker2);
}
- if ( result.interrupt )
+ if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) )
return;
if ( may_update<interior, interior, '1', true>(result)
@@ -250,6 +251,7 @@ struct linear_linear
: m_previous_turn_ptr(NULL)
, m_previous_operation(overlay::operation_none)
, m_degenerated_turn_ptr(NULL)
+ , m_collinear_spike_exit(false)
{}
template <typename Result,
@@ -383,7 +385,8 @@ struct linear_linear
// if we didn't enter in the past, we were outside
if ( was_outside
&& ! fake_enter_detected
- && it->operations[op_id].position != overlay::position_front )
+ && it->operations[op_id].position != overlay::position_front
+ && ! m_collinear_spike_exit )
{
update<interior, exterior, '1', transpose_result>(res);
@@ -402,6 +405,8 @@ struct linear_linear
}
}
}
+
+ m_collinear_spike_exit = false;
}
// u/i, u/u, u/x, x/i, x/u, x/x
else if ( op == overlay::operation_union || op == overlay::operation_blocked )
@@ -418,6 +423,11 @@ struct linear_linear
if ( !was_outside && is_collinear )
{
m_exit_watcher.exit(*it, false);
+ // if the position is not set to back it must be a spike
+ if ( it->operations[op_id].position != overlay::position_back )
+ {
+ m_collinear_spike_exit = true;
+ }
}
bool const op_blocked = op == overlay::operation_blocked;
@@ -456,6 +466,7 @@ struct linear_linear
// if we are truly outside
if ( was_outside
&& it->operations[op_id].position != overlay::position_front
+ && ! m_collinear_spike_exit
/*&& !is_collinear*/ )
{
update<interior, exterior, '1', transpose_result>(res);
@@ -526,6 +537,7 @@ struct linear_linear
&& ( !this_b || op_blocked )
&& was_outside
&& it->operations[op_id].position != overlay::position_front
+ && ! m_collinear_spike_exit
/*&& !is_collinear*/ )
{
bool const front_b = is_endpoint_on_boundary<boundary_front>(
@@ -607,6 +619,10 @@ struct linear_linear
m_previous_turn_ptr = NULL;
m_previous_operation = overlay::operation_none;
m_degenerated_turn_ptr = NULL;
+
+ // actually if this is set to true here there is some error
+ // in get_turns_ll or relate_ll, an assert could be checked here
+ m_collinear_spike_exit = false;
}
template <typename Result,
@@ -724,6 +740,7 @@ struct linear_linear
const TurnInfo * m_previous_turn_ptr;
overlay::operation_type m_previous_operation;
const TurnInfo * m_degenerated_turn_ptr;
+ bool m_collinear_spike_exit;
};
template <typename Result,
@@ -750,7 +767,7 @@ struct linear_linear
geometry, other_geometry,
boundary_checker, other_boundary_checker);
- if ( res.interrupt )
+ if ( BOOST_GEOMETRY_CONDITION( res.interrupt ) )
return;
}
diff --git a/boost/geometry/algorithms/detail/relate/point_geometry.hpp b/boost/geometry/algorithms/detail/relate/point_geometry.hpp
index 86c236d..62ab100 100644
--- a/boost/geometry/algorithms/detail/relate/point_geometry.hpp
+++ b/boost/geometry/algorithms/detail/relate/point_geometry.hpp
@@ -2,15 +2,15 @@
// 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.
+// This file was modified by Oracle on 2013, 2014, 2015.
+// Modifications copyright (c) 2013-2015 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)
-// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
-
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_GEOMETRY_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_GEOMETRY_HPP
@@ -20,6 +20,8 @@
#include <boost/geometry/algorithms/detail/relate/topology_check.hpp>
+#include <boost/geometry/util/condition.hpp>
+
namespace boost { namespace geometry
{
@@ -54,7 +56,7 @@ struct point_geometry
set<exterior, exterior, result_dimension<Point>::value, Transpose>(result);
- if ( result.interrupt )
+ if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
return;
// the point is on the boundary
diff --git a/boost/geometry/algorithms/detail/relate/result.hpp b/boost/geometry/algorithms/detail/relate/result.hpp
index 1bcb527..e26bda6 100644
--- a/boost/geometry/algorithms/detail/relate/result.hpp
+++ b/boost/geometry/algorithms/detail/relate/result.hpp
@@ -2,15 +2,15 @@
// 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.
+// This file was modified by Oracle on 2013, 2014, 2015.
+// Modifications copyright (c) 2013-2015 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)
-// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
-
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_RESULT_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_RESULT_HPP
@@ -24,6 +24,7 @@
#include <boost/mpl/vector_c.hpp>
#include <boost/geometry/core/topological_dimension.hpp>
+#include <boost/geometry/util/condition.hpp>
// TEMP - move this header to geometry/detail
#include <boost/geometry/index/detail/tuples.hpp>
@@ -235,17 +236,17 @@ struct interrupt_dispatch<Mask, true>
static inline bool apply(Mask const& mask)
{
char m = mask.template get<F1, F2>();
- return check<V>(m);
+ return check_element<V>(m);
}
template <char V>
- static inline bool check(char m)
+ static inline bool check_element(char m)
{
- if ( V >= '0' && V <= '9' )
+ if ( BOOST_GEOMETRY_CONDITION(V >= '0' && V <= '9') )
{
return m == 'F' || ( m < V && m >= '0' && m <= '9' );
}
- else if ( V == 'T' )
+ else if ( BOOST_GEOMETRY_CONDITION(V == 'T') )
{
return m == 'F';
}
@@ -394,7 +395,7 @@ inline bool may_update(Mask const& mask, Matrix const& matrix)
::template apply<F1, F2, D>(mask, matrix);
}
-// check()
+// check_matrix()
template <typename Mask>
struct check_dispatch
@@ -485,7 +486,7 @@ struct check_dispatch< boost::tuples::cons<Head, Tail> >
};
template <typename Mask, typename Matrix>
-inline bool check(Mask const& mask, Matrix const& matrix)
+inline bool check_matrix(Mask const& mask, Matrix const& matrix)
{
return check_dispatch<Mask>::apply(mask, matrix);
}
@@ -546,7 +547,7 @@ public:
result_type result() const
{
return !interrupt
- && check(m_mask, static_cast<base_t const&>(*this));
+ && check_matrix(m_mask, static_cast<base_t const&>(*this));
}
template <field F1, field F2, char D>
@@ -964,7 +965,7 @@ struct static_check_dispatch<StaticMask, true>
};
template <typename StaticMask>
-struct static_check
+struct static_check_matrix
{
template <typename Matrix>
static inline bool apply(Matrix const& matrix)
@@ -997,7 +998,7 @@ public:
result_type result() const
{
return (!Interrupt || !interrupt)
- && static_check<StaticMask>::
+ && static_check_matrix<StaticMask>::
apply(static_cast<base_t const&>(*this));
}
diff --git a/boost/geometry/algorithms/detail/relate/turns.hpp b/boost/geometry/algorithms/detail/relate/turns.hpp
index a2e56a8..636c975 100644
--- a/boost/geometry/algorithms/detail/relate/turns.hpp
+++ b/boost/geometry/algorithms/detail/relate/turns.hpp
@@ -1,16 +1,17 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
-// This file was modified by Oracle on 2013, 2014.
-// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates.
+// This file was modified by Oracle on 2013, 2014, 2015.
+// Modifications copyright (c) 2013-2015 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// 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_RELATE_TURNS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TURNS_HPP
@@ -19,8 +20,12 @@
#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
+#include <boost/geometry/policies/robustness/get_rescale_policy.hpp>
+#include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
+
#include <boost/type_traits/is_base_of.hpp>
+
namespace boost { namespace geometry {
#ifndef DOXYGEN_NO_DETAIL
@@ -35,10 +40,16 @@ struct assign_policy
// GET_TURNS
-template <typename Geometry1,
- typename Geometry2,
- typename GetTurnPolicy
- = detail::get_turns::get_turn_info_type<Geometry1, Geometry2, assign_policy<> > >
+template
+<
+ typename Geometry1,
+ typename Geometry2,
+ typename GetTurnPolicy = detail::get_turns::get_turn_info_type
+ <
+ Geometry1, Geometry2, assign_policy<>
+ >,
+ typename RobustPolicy = detail::no_rescale_policy
+>
struct get_turns
{
typedef typename geometry::point_type<Geometry1>::type point1_type;
@@ -46,11 +57,14 @@ struct get_turns
typedef overlay::turn_info
<
point1_type,
- typename segment_ratio_type<point1_type, detail::no_rescale_policy>::type,
+ typename segment_ratio_type<point1_type, RobustPolicy>::type,
typename detail::get_turns::turn_operation_type
<
Geometry1, Geometry2,
- typename segment_ratio_type<point1_type, detail::no_rescale_policy>::type
+ typename segment_ratio_type
+ <
+ point1_type, RobustPolicy
+ >::type
>::type
> turn_info;
@@ -73,6 +87,12 @@ struct get_turns
static const bool reverse1 = detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value;
static const bool reverse2 = detail::overlay::do_reverse<geometry::point_order<Geometry2>::value>::value;
+ RobustPolicy robust_policy = geometry::get_rescale_policy
+ <
+ RobustPolicy
+ >(geometry1, geometry2);
+
+
dispatch::get_turns
<
typename geometry::tag<Geometry1>::type,
@@ -83,7 +103,7 @@ struct get_turns
reverse2,
GetTurnPolicy
>::apply(0, geometry1, 1, geometry2,
- detail::no_rescale_policy(), turns, interrupt_policy);
+ robust_policy, turns, interrupt_policy);
}
};
@@ -125,7 +145,7 @@ struct less_op_linear_linear
{};
template <std::size_t OpId>
-struct less_op_linear_areal
+struct less_op_linear_areal_single
{
template <typename Turn>
inline bool operator()(Turn const& left, Turn const& right) const
@@ -137,27 +157,19 @@ struct less_op_linear_areal
segment_identifier const& left_other_seg_id = left.operations[other_op_id].seg_id;
segment_identifier const& right_other_seg_id = right.operations[other_op_id].seg_id;
- if ( left_other_seg_id.multi_index == right_other_seg_id.multi_index )
- {
- typedef typename Turn::turn_operation_type operation_type;
- operation_type const& left_operation = left.operations[OpId];
- operation_type const& right_operation = right.operations[OpId];
+ typedef typename Turn::turn_operation_type operation_type;
+ operation_type const& left_operation = left.operations[OpId];
+ operation_type const& right_operation = right.operations[OpId];
- if ( left_other_seg_id.ring_index == right_other_seg_id.ring_index )
- {
- return op_to_int_xuic(left_operation)
- < op_to_int_xuic(right_operation);
- }
- else
- {
- return op_to_int_xiuc(left_operation)
- < op_to_int_xiuc(right_operation);
- }
+ if ( left_other_seg_id.ring_index == right_other_seg_id.ring_index )
+ {
+ return op_to_int_xuic(left_operation)
+ < op_to_int_xuic(right_operation);
}
else
{
- //return op_to_int_xuic(left.operations[OpId]) < op_to_int_xuic(right.operations[OpId]);
- return left_other_seg_id.multi_index < right_other_seg_id.multi_index;
+ return op_to_int_xiuc(left_operation)
+ < op_to_int_xiuc(right_operation);
}
}
};
@@ -217,6 +229,19 @@ struct less_op_areal_areal
}
};
+template <std::size_t OpId>
+struct less_other_multi_index
+{
+ static const std::size_t other_op_id = (OpId + 1) % 2;
+
+ template <typename Turn>
+ inline bool operator()(Turn const& left, Turn const& right) const
+ {
+ return left.operations[other_op_id].seg_id.multi_index
+ < right.operations[other_op_id].seg_id.multi_index;
+ }
+};
+
// sort turns by G1 - source_index == 0 by:
// seg_id -> distance -> operation
template <std::size_t OpId = 0,
diff --git a/boost/geometry/algorithms/detail/sections/range_by_section.hpp b/boost/geometry/algorithms/detail/sections/range_by_section.hpp
index 63feb12..d139a3f 100644
--- a/boost/geometry/algorithms/detail/sections/range_by_section.hpp
+++ b/boost/geometry/algorithms/detail/sections/range_by_section.hpp
@@ -58,7 +58,8 @@ struct full_section_polygon
{
return section.ring_id.ring_index < 0
? geometry::exterior_ring(polygon)
- : range::at(geometry::interior_rings(polygon), section.ring_id.ring_index);
+ : range::at(geometry::interior_rings(polygon),
+ static_cast<std::size_t>(section.ring_id.ring_index));
}
};
@@ -74,13 +75,15 @@ struct full_section_multi
static inline typename ring_return_type<MultiGeometry const>::type apply(
MultiGeometry const& multi, Section const& section)
{
+ typedef typename boost::range_size<MultiGeometry>::type size_type;
+
BOOST_ASSERT
(
section.ring_id.multi_index >= 0
- && section.ring_id.multi_index < int(boost::size(multi))
+ && size_type(section.ring_id.multi_index) < boost::size(multi)
);
- return Policy::apply(range::at(multi, section.ring_id.multi_index), section);
+ return Policy::apply(range::at(multi, size_type(section.ring_id.multi_index)), section);
}
};
diff --git a/boost/geometry/algorithms/detail/sections/section_box_policies.hpp b/boost/geometry/algorithms/detail/sections/section_box_policies.hpp
new file mode 100644
index 0000000..cf06700
--- /dev/null
+++ b/boost/geometry/algorithms/detail/sections/section_box_policies.hpp
@@ -0,0 +1,49 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2015 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTION_BOX_POLICIES_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTION_BOX_POLICIES_HPP
+
+
+#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
+#include <boost/geometry/algorithms/expand.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace section
+{
+
+struct get_section_box
+{
+ template <typename Box, typename Section>
+ static inline void apply(Box& total, Section const& section)
+ {
+ geometry::expand(total, section.bounding_box);
+ }
+};
+
+struct overlaps_section_box
+{
+ template <typename Box, typename Section>
+ static inline bool apply(Box const& box, Section const& section)
+ {
+ return ! detail::disjoint::disjoint_box_box(box, section.bounding_box);
+ }
+};
+
+
+}} // namespace detail::section
+#endif
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTION_BOX_POLICIES_HPP
diff --git a/boost/geometry/algorithms/detail/sections/section_functions.hpp b/boost/geometry/algorithms/detail/sections/section_functions.hpp
new file mode 100644
index 0000000..ba1cf93
--- /dev/null
+++ b/boost/geometry/algorithms/detail/sections/section_functions.hpp
@@ -0,0 +1,66 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2015 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_FUNCTIONS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_FUNCTIONS_HPP
+
+
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/algorithms/detail/recalculate.hpp>
+#include <boost/geometry/policies/robustness/robust_point_type.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace section
+{
+
+template
+<
+ std::size_t Dimension,
+ typename Point,
+ typename RobustBox,
+ typename RobustPolicy
+>
+static inline bool preceding(int dir, Point const& point,
+ RobustBox const& robust_box,
+ RobustPolicy const& robust_policy)
+{
+ typename geometry::robust_point_type<Point, RobustPolicy>::type robust_point;
+ geometry::recalculate(robust_point, point, robust_policy);
+ return (dir == 1 && get<Dimension>(robust_point) < get<min_corner, Dimension>(robust_box))
+ || (dir == -1 && get<Dimension>(robust_point) > get<max_corner, Dimension>(robust_box));
+}
+
+template
+<
+ std::size_t Dimension,
+ typename Point,
+ typename RobustBox,
+ typename RobustPolicy
+>
+static inline bool exceeding(int dir, Point const& point,
+ RobustBox const& robust_box,
+ RobustPolicy const& robust_policy)
+{
+ typename geometry::robust_point_type<Point, RobustPolicy>::type robust_point;
+ geometry::recalculate(robust_point, point, robust_policy);
+ return (dir == 1 && get<Dimension>(robust_point) > get<max_corner, Dimension>(robust_box))
+ || (dir == -1 && get<Dimension>(robust_point) < get<min_corner, Dimension>(robust_box));
+}
+
+
+}} // namespace detail::section
+#endif
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_FUNCTIONS_HPP
diff --git a/boost/geometry/algorithms/detail/sections/sectionalize.hpp b/boost/geometry/algorithms/detail/sections/sectionalize.hpp
index 250577c..a744ea0 100644
--- a/boost/geometry/algorithms/detail/sections/sectionalize.hpp
+++ b/boost/geometry/algorithms/detail/sections/sectionalize.hpp
@@ -8,6 +8,9 @@
// This file was modified by Oracle on 2013, 2014.
// Modifications copyright (c) 2013, 2014 Oracle and/or its affiliates.
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -15,8 +18,6 @@
// 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_SECTIONS_SECTIONALIZE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP
@@ -25,7 +26,9 @@
#include <boost/concept/requires.hpp>
#include <boost/mpl/assert.hpp>
+#include <boost/mpl/vector_c.hpp>
#include <boost/range.hpp>
+#include <boost/static_assert.hpp>
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/algorithms/expand.hpp>
@@ -63,12 +66,15 @@ namespace boost { namespace geometry
\tparam DimensionCount number of dimensions for this section
\ingroup sectionalize
*/
-template <typename Box, std::size_t DimensionCount>
+template
+<
+ typename Box,
+ std::size_t DimensionCount
+>
struct section
{
typedef Box box_type;
-
- int id; // might be obsolete now, BSG 14-03-2011 TODO decide about this
+ static std::size_t const dimension_count = DimensionCount;
int directions[DimensionCount];
ring_identifier ring_id;
@@ -85,8 +91,7 @@ struct section
bool is_non_duplicate_last;
inline section()
- : id(-1)
- , begin_index(-1)
+ : begin_index(-1)
, end_index(-1)
, count(0)
, range_count(0)
@@ -122,75 +127,83 @@ struct sections : std::vector<section<Box, DimensionCount> >
namespace detail { namespace sectionalize
{
-template <std::size_t Dimension, std::size_t DimensionCount>
+template
+<
+ typename DimensionVector,
+ std::size_t Index,
+ std::size_t Count
+>
struct get_direction_loop
{
+ typedef typename boost::mpl::at_c<DimensionVector, Index>::type dimension;
+
template <typename Segment>
static inline void apply(Segment const& seg,
- int directions[DimensionCount])
+ int directions[Count])
{
typedef typename coordinate_type<Segment>::type coordinate_type;
+
coordinate_type const diff =
- geometry::get<1, Dimension>(seg) - geometry::get<0, Dimension>(seg);
+ geometry::get<1, dimension::value>(seg)
+ - geometry::get<0, dimension::value>(seg);
coordinate_type zero = coordinate_type();
- directions[Dimension] = diff > zero ? 1 : diff < zero ? -1 : 0;
+ directions[Index] = diff > zero ? 1 : diff < zero ? -1 : 0;
get_direction_loop
- <
- Dimension + 1, DimensionCount
- >::apply(seg, directions);
+ <
+ DimensionVector,
+ Index + 1,
+ Count
+ >::apply(seg, directions);
}
};
-template <std::size_t DimensionCount>
-struct get_direction_loop<DimensionCount, DimensionCount>
+template <typename DimensionVector, std::size_t Count>
+struct get_direction_loop<DimensionVector, Count, Count>
{
template <typename Segment>
- static inline void apply(Segment const&, int [DimensionCount])
+ static inline void apply(Segment const&, int [Count])
{}
};
-template <typename T, std::size_t Dimension, std::size_t DimensionCount>
+//! Copy one static array to another
+template <typename T, std::size_t Index, std::size_t Count>
struct copy_loop
{
- static inline void apply(T const source[DimensionCount],
- T target[DimensionCount])
+ static inline void apply(T const source[Count], T target[Count])
{
- target[Dimension] = source[Dimension];
- copy_loop<T, Dimension + 1, DimensionCount>::apply(source, target);
+ target[Index] = source[Index];
+ copy_loop<T, Index + 1, Count>::apply(source, target);
}
};
-template <typename T, std::size_t DimensionCount>
-struct copy_loop<T, DimensionCount, DimensionCount>
+template <typename T, std::size_t Count>
+struct copy_loop<T, Count, Count>
{
- static inline void apply(T const [DimensionCount], T [DimensionCount])
+ static inline void apply(T const [Count], T [Count])
{}
};
-template <typename T, std::size_t Dimension, std::size_t DimensionCount>
+//! Compare two static arrays
+template <typename T, std::size_t Index, std::size_t Count>
struct compare_loop
{
- static inline bool apply(T const source[DimensionCount],
- T const target[DimensionCount])
+ static inline bool apply(T const array1[Count], T const array2[Count])
{
- bool const not_equal = target[Dimension] != source[Dimension];
-
- return not_equal
+ return array1[Index] != array2[Index]
? false
: compare_loop
<
- T, Dimension + 1, DimensionCount
- >::apply(source, target);
+ T, Index + 1, Count
+ >::apply(array1, array2);
}
};
-template <typename T, std::size_t DimensionCount>
-struct compare_loop<T, DimensionCount, DimensionCount>
+template <typename T, std::size_t Count>
+struct compare_loop<T, Count, Count>
{
- static inline bool apply(T const [DimensionCount],
- T const [DimensionCount])
+ static inline bool apply(T const [Count], T const [Count])
{
return true;
@@ -215,9 +228,9 @@ struct check_duplicate_loop
}
return check_duplicate_loop
- <
+ <
Dimension + 1, DimensionCount
- >::apply(seg);
+ >::apply(seg);
}
};
@@ -231,20 +244,21 @@ struct check_duplicate_loop<DimensionCount, DimensionCount>
}
};
-template <typename T, std::size_t Dimension, std::size_t DimensionCount>
+//! Assign a value to a static array
+template <typename T, std::size_t Index, std::size_t Count>
struct assign_loop
{
- static inline void apply(T dims[DimensionCount], int const value)
+ static inline void apply(T dims[Count], int const value)
{
- dims[Dimension] = value;
- assign_loop<T, Dimension + 1, DimensionCount>::apply(dims, value);
+ dims[Index] = value;
+ assign_loop<T, Index + 1, Count>::apply(dims, value);
}
};
-template <typename T, std::size_t DimensionCount>
-struct assign_loop<T, DimensionCount, DimensionCount>
+template <typename T, std::size_t Count>
+struct assign_loop<T, Count, Count>
{
- static inline void apply(T [DimensionCount], int const)
+ static inline void apply(T [Count], int const)
{
}
};
@@ -253,35 +267,42 @@ struct assign_loop<T, DimensionCount, DimensionCount>
template
<
typename Point,
- std::size_t DimensionCount
+ typename DimensionVector
>
struct sectionalize_part
{
+ static const std::size_t dimension_count
+ = boost::mpl::size<DimensionVector>::value;
+
template
<
- typename Range, // Can be closeable_view
+ typename Iterator,
typename RobustPolicy,
typename Sections
>
static inline void apply(Sections& sections,
- Range const& range,
+ Iterator begin, Iterator end,
RobustPolicy const& robust_policy,
- bool make_rescaled_boxes,
ring_identifier ring_id,
std::size_t max_count)
{
boost::ignore_unused_variable_warning(robust_policy);
- boost::ignore_unused_variable_warning(make_rescaled_boxes);
- typedef model::referring_segment<Point const> segment_type;
typedef typename boost::range_value<Sections>::type section_type;
- typedef model::segment
- <
- typename robust_point_type<Point, RobustPolicy>::type
- > robust_segment_type;
- typedef typename boost::range_iterator<Range const>::type iterator_type;
+ BOOST_STATIC_ASSERT
+ (
+ (static_cast<int>(section_type::dimension_count)
+ == static_cast<int>(boost::mpl::size<DimensionVector>::value))
+ );
- if ( boost::empty(range) )
+ typedef typename geometry::robust_point_type
+ <
+ Point,
+ RobustPolicy
+ >::type robust_point_type;
+
+ std::size_t const count = std::distance(begin, end);
+ if (count == 0)
{
return;
}
@@ -293,21 +314,24 @@ struct sectionalize_part
bool mark_first_non_duplicated = true;
std::size_t last_non_duplicate_index = sections.size();
- iterator_type it = boost::begin(range);
+ Iterator it = begin;
+ robust_point_type previous_robust_point;
+ geometry::recalculate(previous_robust_point, *it, robust_policy);
- for(iterator_type previous = it++;
- it != boost::end(range);
+ for(Iterator previous = it++;
+ it != end;
++previous, ++it, index++)
{
- segment_type segment(*previous, *it);
- robust_segment_type robust_segment;
- geometry::recalculate(robust_segment, segment, robust_policy);
+ robust_point_type current_robust_point;
+ geometry::recalculate(current_robust_point, *it, robust_policy);
+ model::referring_segment<robust_point_type> robust_segment(
+ previous_robust_point, current_robust_point);
- int direction_classes[DimensionCount] = {0};
+ int direction_classes[dimension_count] = {0};
get_direction_loop
- <
- 0, DimensionCount
- >::apply(robust_segment, direction_classes);
+ <
+ DimensionVector, 0, dimension_count
+ >::apply(robust_segment, direction_classes);
// if "dir" == 0 for all point-dimensions, it is duplicate.
// Those sections might be omitted, if wished, lateron
@@ -317,7 +341,7 @@ struct sectionalize_part
{
// Recheck because ALL dimensions should be checked,
// not only first one.
- // (DimensionCount might be < dimension<P>::value)
+ // (dimension_count might be < dimension<P>::value)
if (check_duplicate_loop
<
0, geometry::dimension<Point>::type::value
@@ -332,21 +356,20 @@ struct sectionalize_part
// Actual value is not important as long as it is not -1,0,1
assign_loop
<
- int, 0, DimensionCount
+ int, 0, dimension_count
>::apply(direction_classes, -99);
}
}
if (section.count > 0
- && (!compare_loop
+ && (! compare_loop
<
- int, 0, DimensionCount
+ int, 0, dimension_count
>::apply(direction_classes, section.directions)
- || section.count > max_count
- )
+ || section.count > max_count)
)
{
- if ( !section.duplicate )
+ if (! section.duplicate)
{
last_non_duplicate_index = sections.size();
}
@@ -361,9 +384,9 @@ struct sectionalize_part
section.ring_id = ring_id;
section.duplicate = duplicate;
section.non_duplicate_index = ndi;
- section.range_count = boost::size(range);
+ section.range_count = count;
- if ( mark_first_non_duplicated && !duplicate )
+ if (mark_first_non_duplicated && ! duplicate)
{
section.is_non_duplicate_first = true;
mark_first_non_duplicated = false;
@@ -371,25 +394,26 @@ struct sectionalize_part
copy_loop
<
- int, 0, DimensionCount
+ int, 0, dimension_count
>::apply(direction_classes, section.directions);
- expand_box(*previous, robust_policy, section);
+ geometry::expand(section.bounding_box, previous_robust_point);
}
- expand_box(*it, robust_policy, section);
+ geometry::expand(section.bounding_box, current_robust_point);
section.end_index = index + 1;
section.count++;
if (! duplicate)
{
ndi++;
}
+ previous_robust_point = current_robust_point;
}
// Add last section if applicable
if (section.count > 0)
{
- if ( !section.duplicate )
+ if (! section.duplicate)
{
last_non_duplicate_index = sections.size();
}
@@ -397,30 +421,21 @@ struct sectionalize_part
sections.push_back(section);
}
- if ( last_non_duplicate_index < sections.size()
- && !sections[last_non_duplicate_index].duplicate )
+ if (last_non_duplicate_index < sections.size()
+ && ! sections[last_non_duplicate_index].duplicate)
{
sections[last_non_duplicate_index].is_non_duplicate_last = true;
}
}
-
- template <typename InputPoint, typename RobustPolicy, typename Section>
- static inline void expand_box(InputPoint const& point,
- RobustPolicy const& robust_policy,
- Section& section)
- {
- typename geometry::point_type<typename Section::box_type>::type robust_point;
- geometry::recalculate(robust_point, point, robust_policy);
- geometry::expand(section.bounding_box, robust_point);
- }
};
template
<
- closure_selector Closure, bool Reverse,
+ closure_selector Closure,
+ bool Reverse,
typename Point,
- std::size_t DimensionCount
+ typename DimensionVector
>
struct sectionalize_range
{
@@ -432,13 +447,12 @@ struct sectionalize_range
>
static inline void apply(Range const& range,
RobustPolicy const& robust_policy,
- bool make_rescaled_boxes,
Sections& sections,
ring_identifier ring_id,
std::size_t max_count)
{
- typedef typename closeable_view<Range const, Closure>::type cview_type;
- typedef typename reversible_view
+ typedef typename closeable_view<Range const, Closure>::type cview_type;
+ typedef typename reversible_view
<
cview_type const,
Reverse ? iterate_reverse : iterate_forward
@@ -460,15 +474,16 @@ struct sectionalize_range
return;
}
- sectionalize_part<Point, DimensionCount>
- ::apply(sections, view, robust_policy, make_rescaled_boxes, ring_id, max_count);
+ sectionalize_part<Point, DimensionVector>::apply(sections,
+ boost::begin(view), boost::end(view),
+ robust_policy, ring_id, max_count);
}
};
template
<
bool Reverse,
- std::size_t DimensionCount
+ typename DimensionVector
>
struct sectionalize_polygon
{
@@ -480,20 +495,18 @@ struct sectionalize_polygon
>
static inline void apply(Polygon const& poly,
RobustPolicy const& robust_policy,
- bool make_rescaled_boxes,
Sections& sections,
ring_identifier ring_id, std::size_t max_count)
{
typedef typename point_type<Polygon>::type point_type;
- //typedef typename ring_type<Polygon>::type ring_type;
typedef sectionalize_range
- <
+ <
closure<Polygon>::value, Reverse,
- point_type, DimensionCount
- > per_range;
+ point_type, DimensionVector
+ > per_range;
ring_id.ring_index = -1;
- per_range::apply(exterior_ring(poly), robust_policy, make_rescaled_boxes, sections, ring_id, max_count);
+ per_range::apply(exterior_ring(poly), robust_policy, sections, ring_id, max_count);
ring_id.ring_index++;
typename interior_return_type<Polygon const>::type
@@ -501,15 +514,12 @@ struct sectionalize_polygon
for (typename detail::interior_iterator<Polygon const>::type
it = boost::begin(rings); it != boost::end(rings); ++it, ++ring_id.ring_index)
{
- per_range::apply(*it, robust_policy, make_rescaled_boxes, sections, ring_id, max_count);
+ per_range::apply(*it, robust_policy, sections, ring_id, max_count);
}
}
};
-template
-<
- std::size_t DimensionCount
->
+template <typename DimensionVector>
struct sectionalize_box
{
template
@@ -520,7 +530,6 @@ struct sectionalize_box
>
static inline void apply(Box const& box,
RobustPolicy const& robust_policy,
- bool make_rescaled_boxes,
Sections& sections,
ring_identifier const& ring_id, std::size_t max_count)
{
@@ -547,16 +556,16 @@ struct sectionalize_box
points.push_back(ll);
sectionalize_range
- <
+ <
closed, false,
- point_type,
- DimensionCount
- >::apply(points, robust_policy, make_rescaled_boxes, sections,
- ring_id, max_count);
+ point_type,
+ DimensionVector
+ >::apply(points, robust_policy, sections,
+ ring_id, max_count);
}
};
-template <std::size_t DimensionCount, typename Policy>
+template <typename DimensionVector, typename Policy>
struct sectionalize_multi
{
template
@@ -567,7 +576,6 @@ struct sectionalize_multi
>
static inline void apply(MultiGeometry const& multi,
RobustPolicy const& robust_policy,
- bool make_rescaled_boxes,
Sections& sections, ring_identifier ring_id, std::size_t max_count)
{
ring_id.multi_index = 0;
@@ -576,25 +584,12 @@ struct sectionalize_multi
it != boost::end(multi);
++it, ++ring_id.multi_index)
{
- Policy::apply(*it, robust_policy, make_rescaled_boxes, sections, ring_id, max_count);
+ Policy::apply(*it, robust_policy, sections, ring_id, max_count);
}
}
};
template <typename Sections>
-inline void set_section_unique_ids(Sections& sections)
-{
- // Set ID's.
- int index = 0;
- for (typename boost::range_iterator<Sections>::type it = boost::begin(sections);
- it != boost::end(sections);
- ++it)
- {
- it->id = index++;
- }
-}
-
-template <typename Sections>
inline void enlarge_sections(Sections& sections)
{
// Robustness issue. Increase sections a tiny bit such that all points are really within (and not on border)
@@ -631,7 +626,7 @@ template
typename Tag,
typename Geometry,
bool Reverse,
- std::size_t DimensionCount
+ typename DimensionVector
>
struct sectionalize
{
@@ -646,29 +641,29 @@ template
<
typename Box,
bool Reverse,
- std::size_t DimensionCount
+ typename DimensionVector
>
-struct sectionalize<box_tag, Box, Reverse, DimensionCount>
- : detail::sectionalize::sectionalize_box<DimensionCount>
+struct sectionalize<box_tag, Box, Reverse, DimensionVector>
+ : detail::sectionalize::sectionalize_box<DimensionVector>
{};
template
<
typename LineString,
- std::size_t DimensionCount
+ typename DimensionVector
>
struct sectionalize
<
linestring_tag,
LineString,
false,
- DimensionCount
+ DimensionVector
>
: detail::sectionalize::sectionalize_range
<
closed, false,
typename point_type<LineString>::type,
- DimensionCount
+ DimensionVector
>
{};
@@ -676,14 +671,14 @@ template
<
typename Ring,
bool Reverse,
- std::size_t DimensionCount
+ typename DimensionVector
>
-struct sectionalize<ring_tag, Ring, Reverse, DimensionCount>
+struct sectionalize<ring_tag, Ring, Reverse, DimensionVector>
: detail::sectionalize::sectionalize_range
<
geometry::closure<Ring>::value, Reverse,
typename point_type<Ring>::type,
- DimensionCount
+ DimensionVector
>
{};
@@ -691,12 +686,12 @@ template
<
typename Polygon,
bool Reverse,
- std::size_t DimensionCount
+ typename DimensionVector
>
-struct sectionalize<polygon_tag, Polygon, Reverse, DimensionCount>
+struct sectionalize<polygon_tag, Polygon, Reverse, DimensionVector>
: detail::sectionalize::sectionalize_polygon
<
- Reverse, DimensionCount
+ Reverse, DimensionVector
>
{};
@@ -704,16 +699,16 @@ template
<
typename MultiPolygon,
bool Reverse,
- std::size_t DimensionCount
+ typename DimensionVector
>
-struct sectionalize<multi_polygon_tag, MultiPolygon, Reverse, DimensionCount>
+struct sectionalize<multi_polygon_tag, MultiPolygon, Reverse, DimensionVector>
: detail::sectionalize::sectionalize_multi
<
- DimensionCount,
+ DimensionVector,
detail::sectionalize::sectionalize_polygon
<
Reverse,
- DimensionCount
+ DimensionVector
>
>
@@ -723,17 +718,17 @@ template
<
typename MultiLinestring,
bool Reverse,
- std::size_t DimensionCount
+ typename DimensionVector
>
-struct sectionalize<multi_linestring_tag, MultiLinestring, Reverse, DimensionCount>
+struct sectionalize<multi_linestring_tag, MultiLinestring, Reverse, DimensionVector>
: detail::sectionalize::sectionalize_multi
<
- DimensionCount,
+ DimensionVector,
detail::sectionalize::sectionalize_range
<
closed, false,
typename point_type<MultiLinestring>::type,
- DimensionCount
+ DimensionVector
>
>
@@ -750,54 +745,61 @@ struct sectionalize<multi_linestring_tag, MultiLinestring, Reverse, DimensionCou
\tparam Sections type of sections to create
\param geometry geometry to create sections from
\param robust_policy policy to handle robustness issues
- \param enlarge_secion_boxes if true, boxes are enlarged a tiny bit to be sure
- they really contain all geometries (w.r.t. robustness)
\param sections structure with sections
\param source_index index to assign to the ring_identifiers
+ \param max_count maximal number of points per section
+ (defaults to 10, this seems to give the fastest results)
+
*/
-template<bool Reverse, typename Geometry, typename Sections, typename RobustPolicy>
+template
+<
+ bool Reverse,
+ typename DimensionVector,
+ typename Geometry,
+ typename Sections,
+ typename RobustPolicy
+>
inline void sectionalize(Geometry const& geometry,
RobustPolicy const& robust_policy,
- bool enlarge_secion_boxes,
Sections& sections,
- int source_index = 0)
+ int source_index = 0,
+ std::size_t max_count = 10)
{
concept::check<Geometry const>();
+ typedef typename boost::range_value<Sections>::type section_type;
+
+ // Compiletime check for point type of section boxes
+ // and point type related to robust policy
+ typedef typename geometry::coordinate_type
+ <
+ typename section_type::box_type
+ >::type ctype1;
+ typedef typename geometry::coordinate_type
+ <
+ typename geometry::robust_point_type
+ <
+ typename geometry::point_type<Geometry>::type,
+ RobustPolicy
+ >::type
+ >::type ctype2;
+
+ BOOST_MPL_ASSERT((boost::is_same<ctype1, ctype2>));
+
+
sections.clear();
ring_identifier ring_id;
ring_id.source_index = source_index;
- // A maximum of 10 segments per section seems to give the fastest results
dispatch::sectionalize
<
typename tag<Geometry>::type,
Geometry,
Reverse,
- Sections::value
- >::apply(geometry, robust_policy, enlarge_secion_boxes, sections, ring_id, 10);
-
- detail::sectionalize::set_section_unique_ids(sections);
- if (! enlarge_secion_boxes)
- {
- detail::sectionalize::enlarge_sections(sections);
- }
-}
-
-
-#if defined(BOOST_GEOMETRY_UNIT_TEST_SECTIONALIZE)
-// Backwards compatibility
-template<bool Reverse, typename Geometry, typename Sections>
-inline void sectionalize(Geometry const& geometry,
- Sections& sections,
- int source_index = 0)
-{
- return geometry::sectionalize<Reverse>(geometry, detail::no_rescale_policy(),
- false, sections,
- source_index);
+ DimensionVector
+ >::apply(geometry, robust_policy, sections, ring_id, max_count);
}
-#endif
}} // namespace boost::geometry
diff --git a/boost/geometry/algorithms/detail/single_geometry.hpp b/boost/geometry/algorithms/detail/single_geometry.hpp
index c65ff8b..f38295a 100644
--- a/boost/geometry/algorithms/detail/single_geometry.hpp
+++ b/boost/geometry/algorithms/detail/single_geometry.hpp
@@ -55,7 +55,8 @@ struct single_geometry<Geometry, true>
static inline return_type apply(Geometry & g, Id const& id)
{
BOOST_ASSERT(id.multi_index >= 0);
- return range::at(g, id.multi_index);
+ typedef typename boost::range_size<Geometry>::type size_type;
+ return range::at(g, static_cast<size_type>(id.multi_index));
}
};
diff --git a/boost/geometry/algorithms/detail/sub_range.hpp b/boost/geometry/algorithms/detail/sub_range.hpp
index a68f313..eda3ce5 100644
--- a/boost/geometry/algorithms/detail/sub_range.hpp
+++ b/boost/geometry/algorithms/detail/sub_range.hpp
@@ -44,7 +44,7 @@ struct sub_range<Geometry, Tag, false>
template <typename Geometry>
struct sub_range<Geometry, polygon_tag, false>
{
- typedef typename geometry::ring_type<Geometry>::type & return_type;
+ typedef typename geometry::ring_return_type<Geometry>::type return_type;
template <typename Id> static inline
return_type apply(Geometry & geometry, Id const& id)
@@ -55,7 +55,11 @@ struct sub_range<Geometry, polygon_tag, false>
}
else
{
- std::size_t ri = static_cast<std::size_t>(id.ring_index);
+ typedef typename boost::range_size
+ <
+ typename geometry::interior_type<Geometry>::type
+ >::type size_type;
+ size_type const ri = static_cast<size_type>(id.ring_index);
return range::at(geometry::interior_rings(geometry), ri);
}
}
@@ -81,7 +85,9 @@ struct sub_range<Geometry, Tag, true>
return_type apply(Geometry & geometry, Id const& id)
{
BOOST_ASSERT(0 <= id.multi_index);
- return sub_sub_range::apply(range::at(geometry, id.multi_index), id);
+ typedef typename boost::range_size<Geometry>::type size_type;
+ size_type const mi = static_cast<size_type>(id.multi_index);
+ return sub_sub_range::apply(range::at(geometry, mi), id);
}
};
diff --git a/boost/geometry/algorithms/detail/turns/print_turns.hpp b/boost/geometry/algorithms/detail/turns/print_turns.hpp
index b339e11..9d4e45c 100644
--- a/boost/geometry/algorithms/detail/turns/print_turns.hpp
+++ b/boost/geometry/algorithms/detail/turns/print_turns.hpp
@@ -10,9 +10,9 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_PRINT_TURNS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_PRINT_TURNS_HPP
+#include <algorithm>
#include <iostream>
-#include <boost/foreach.hpp>
#include <boost/range.hpp>
#include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp>
@@ -27,21 +27,16 @@ namespace boost { namespace geometry
namespace detail { namespace turns
{
-
-
-template <typename Geometry1, typename Geometry2, typename Turns>
-static inline void print_turns(Geometry1 const& g1,
- Geometry2 const& g2,
- Turns const& turns)
+struct turn_printer
{
- typedef typename boost::range_value<Turns>::type turn_info;
+ turn_printer(std::ostream & os)
+ : index(0)
+ , out(os)
+ {}
- std::cout << geometry::wkt(g1) << std::endl;
- std::cout << geometry::wkt(g2) << std::endl;
- int index = 0;
- BOOST_FOREACH(turn_info const& turn, turns)
+ template <typename Turn>
+ void operator()(Turn const& turn)
{
- std::ostream& out = std::cout;
out << index
<< ": " << geometry::method_char(turn.method);
@@ -81,8 +76,22 @@ static inline void print_turns(Geometry1 const& g1,
out << ' ' << geometry::dsv(turn.point) << ' ';
++index;
- std::cout << std::endl;
+ out << std::endl;
}
+
+ int index;
+ std::ostream & out;
+};
+
+template <typename Geometry1, typename Geometry2, typename Turns>
+static inline void print_turns(Geometry1 const& g1,
+ Geometry2 const& g2,
+ Turns const& turns)
+{
+ std::cout << geometry::wkt(g1) << std::endl;
+ std::cout << geometry::wkt(g2) << std::endl;
+
+ std::for_each(boost::begin(turns), boost::end(turns), turn_printer(std::cout));
}
diff --git a/boost/geometry/algorithms/detail/vincenty_direct.hpp b/boost/geometry/algorithms/detail/vincenty_direct.hpp
new file mode 100644
index 0000000..775687c
--- /dev/null
+++ b/boost/geometry/algorithms/detail/vincenty_direct.hpp
@@ -0,0 +1,190 @@
+// Boost.Geometry
+
+// 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_VINCENTY_DIRECT_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_VINCENTY_DIRECT_HPP
+
+
+#include <boost/math/constants/constants.hpp>
+
+#include <boost/geometry/core/radius.hpp>
+#include <boost/geometry/core/srs.hpp>
+
+#include <boost/geometry/util/math.hpp>
+
+#include <boost/geometry/algorithms/detail/flattening.hpp>
+
+
+#ifndef BOOST_GEOMETRY_DETAIL_VINCENTY_MAX_STEPS
+#define BOOST_GEOMETRY_DETAIL_VINCENTY_MAX_STEPS 1000
+#endif
+
+
+namespace boost { namespace geometry { namespace detail
+{
+
+/*!
+\brief The solution of the direct problem of geodesics on latlong coordinates, after Vincenty, 1975
+\author See
+ - http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf
+ - http://www.icsm.gov.au/gda/gdav2.3.pdf
+\author Adapted from various implementations to get it close to the original document
+ - http://www.movable-type.co.uk/scripts/LatLongVincenty.html
+ - http://exogen.case.edu/projects/geopy/source/geopy.distance.html
+ - http://futureboy.homeip.net/fsp/colorize.fsp?fileName=navigation.frink
+
+*/
+template <typename CT>
+class vincenty_direct
+{
+public:
+ template <typename T, typename Dist, typename Azi, typename Spheroid>
+ vincenty_direct(T const& lo1,
+ T const& la1,
+ Dist const& distance,
+ Azi const& azimuth12,
+ Spheroid const& spheroid)
+ : lon1(lo1)
+ , lat1(la1)
+ , is_distance_zero(false)
+ {
+ if ( math::equals(distance, Dist(0)) || distance < Dist(0) )
+ {
+ is_distance_zero = true;
+ return;
+ }
+
+ CT const radius_a = CT(get_radius<0>(spheroid));
+ CT const radius_b = CT(get_radius<2>(spheroid));
+ flattening = geometry::detail::flattening<CT>(spheroid);
+
+ sin_azimuth12 = sin(azimuth12);
+ cos_azimuth12 = cos(azimuth12);
+
+ // U: reduced latitude, defined by tan U = (1-f) tan phi
+ one_min_f = CT(1) - flattening;
+ CT const tan_U1 = one_min_f * tan(lat1);
+ CT const sigma1 = atan2(tan_U1, cos_azimuth12); // (1)
+
+ // may be calculated from tan using 1 sqrt()
+ CT const U1 = atan(tan_U1);
+ sin_U1 = sin(U1);
+ cos_U1 = cos(U1);
+
+ sin_alpha = cos_U1 * sin_azimuth12; // (2)
+ sin_alpha_sqr = math::sqr(sin_alpha);
+ cos_alpha_sqr = CT(1) - sin_alpha_sqr;
+
+ CT const b_sqr = radius_b * radius_b;
+ CT const u_sqr = cos_alpha_sqr * (radius_a * radius_a - b_sqr) / b_sqr;
+ CT const A = CT(1) + (u_sqr/CT(16384)) * (CT(4096) + u_sqr*(CT(-768) + u_sqr*(CT(320) - u_sqr*CT(175)))); // (3)
+ CT const B = (u_sqr/CT(1024))*(CT(256) + u_sqr*(CT(-128) + u_sqr*(CT(74) - u_sqr*CT(47)))); // (4)
+
+ CT s_div_bA = distance / (radius_b * A);
+ sigma = s_div_bA; // (7)
+
+ CT previous_sigma;
+
+ int counter = 0; // robustness
+
+ do
+ {
+ previous_sigma = sigma;
+
+ CT const two_sigma_m = CT(2) * sigma1 + sigma; // (5)
+
+ sin_sigma = sin(sigma);
+ cos_sigma = cos(sigma);
+ CT const sin_sigma_sqr = math::sqr(sin_sigma);
+ cos_2sigma_m = cos(two_sigma_m);
+ cos_2sigma_m_sqr = math::sqr(cos_2sigma_m);
+
+ CT const delta_sigma = B * sin_sigma * (cos_2sigma_m
+ + (B/CT(4)) * ( cos_sigma * (CT(-1) + CT(2)*cos_2sigma_m_sqr)
+ - (B/CT(6) * cos_2sigma_m * (CT(-3)+CT(4)*sin_sigma_sqr) * (CT(-3)+CT(4)*cos_2sigma_m_sqr)) )); // (6)
+
+ sigma = s_div_bA + delta_sigma; // (7)
+
+ ++counter; // robustness
+
+ } while ( geometry::math::abs(previous_sigma - sigma) > CT(1e-12)
+ //&& geometry::math::abs(sigma) < pi
+ && counter < BOOST_GEOMETRY_DETAIL_VINCENTY_MAX_STEPS ); // robustness
+ }
+
+ inline CT lat2() const
+ {
+ if ( is_distance_zero )
+ {
+ return lat1;
+ }
+
+ return atan2( sin_U1 * cos_sigma + cos_U1 * sin_sigma * cos_azimuth12,
+ one_min_f * math::sqrt(sin_alpha_sqr + math::sqr(sin_U1 * sin_sigma - cos_U1 * cos_sigma * cos_azimuth12))); // (8)
+ }
+
+ inline CT lon2() const
+ {
+ if ( is_distance_zero )
+ {
+ return lon1;
+ }
+
+ CT const lambda = atan2( sin_sigma * sin_azimuth12,
+ cos_U1 * cos_sigma - sin_U1 * sin_sigma * cos_azimuth12); // (9)
+ CT const C = (flattening/CT(16)) * cos_alpha_sqr * ( CT(4) + flattening * ( CT(4) - CT(3) * cos_alpha_sqr ) ); // (10)
+ CT const L = lambda - (CT(1) - C) * flattening * sin_alpha
+ * ( sigma + C * sin_sigma * ( cos_2sigma_m + C * cos_sigma * ( CT(-1) + CT(2) * cos_2sigma_m_sqr ) ) ); // (11)
+
+ return lon1 + L;
+ }
+
+ inline CT azimuth21() const
+ {
+ // NOTE: signs of X and Y are different than in the original paper
+ return is_distance_zero ?
+ CT(0) :
+ atan2(-sin_alpha, sin_U1 * sin_sigma - cos_U1 * cos_sigma * cos_azimuth12); // (12)
+ }
+
+private:
+ CT sigma;
+ CT sin_sigma;
+ CT cos_sigma;
+
+ CT cos_2sigma_m;
+ CT cos_2sigma_m_sqr;
+
+ CT sin_alpha;
+ CT sin_alpha_sqr;
+ CT cos_alpha_sqr;
+
+ CT sin_azimuth12;
+ CT cos_azimuth12;
+
+ CT sin_U1;
+ CT cos_U1;
+
+ CT flattening;
+ CT one_min_f;
+
+ CT const lon1;
+ CT const lat1;
+
+ bool is_distance_zero;
+};
+
+}}} // namespace boost::geometry::detail
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_VINCENTY_DIRECT_HPP
diff --git a/boost/geometry/algorithms/detail/vincenty_inverse.hpp b/boost/geometry/algorithms/detail/vincenty_inverse.hpp
new file mode 100644
index 0000000..861452a
--- /dev/null
+++ b/boost/geometry/algorithms/detail/vincenty_inverse.hpp
@@ -0,0 +1,218 @@
+// Boost.Geometry
+
+// 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_VINCENTY_INVERSE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_VINCENTY_INVERSE_HPP
+
+
+#include <boost/math/constants/constants.hpp>
+
+#include <boost/geometry/core/radius.hpp>
+#include <boost/geometry/core/srs.hpp>
+
+#include <boost/geometry/util/math.hpp>
+
+#include <boost/geometry/algorithms/detail/flattening.hpp>
+
+
+#ifndef BOOST_GEOMETRY_DETAIL_VINCENTY_MAX_STEPS
+#define BOOST_GEOMETRY_DETAIL_VINCENTY_MAX_STEPS 1000
+#endif
+
+
+namespace boost { namespace geometry { namespace detail
+{
+
+/*!
+\brief The solution of the inverse problem of geodesics on latlong coordinates, after Vincenty, 1975
+\author See
+ - http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf
+ - http://www.icsm.gov.au/gda/gdav2.3.pdf
+\author Adapted from various implementations to get it close to the original document
+ - http://www.movable-type.co.uk/scripts/LatLongVincenty.html
+ - http://exogen.case.edu/projects/geopy/source/geopy.distance.html
+ - http://futureboy.homeip.net/fsp/colorize.fsp?fileName=navigation.frink
+
+*/
+template <typename CT>
+class vincenty_inverse
+{
+public:
+ template <typename T1, typename T2, typename Spheroid>
+ vincenty_inverse(T1 const& lon1,
+ T1 const& lat1,
+ T2 const& lon2,
+ T2 const& lat2,
+ Spheroid const& spheroid)
+ : is_result_zero(false)
+ {
+ if (math::equals(lat1, lat2) && math::equals(lon1, lon2))
+ {
+ is_result_zero = true;
+ return;
+ }
+
+ CT const c1 = 1;
+ CT const c2 = 2;
+ CT const c3 = 3;
+ CT const c4 = 4;
+ CT const c16 = 16;
+ CT const c_e_12 = CT(1e-12);
+
+ CT const pi = geometry::math::pi<CT>();
+ CT const two_pi = c2 * pi;
+
+ // lambda: difference in longitude on an auxiliary sphere
+ CT L = lon2 - lon1;
+ CT lambda = L;
+
+ if (L < -pi) L += two_pi;
+ if (L > pi) L -= two_pi;
+
+ radius_a = CT(get_radius<0>(spheroid));
+ radius_b = CT(get_radius<2>(spheroid));
+ CT const flattening = geometry::detail::flattening<CT>(spheroid);
+
+ // U: reduced latitude, defined by tan U = (1-f) tan phi
+ CT const one_min_f = c1 - flattening;
+ CT const tan_U1 = one_min_f * tan(lat1); // above (1)
+ CT const tan_U2 = one_min_f * tan(lat2); // above (1)
+
+ // calculate sin U and cos U using trigonometric identities
+ CT const temp_den_U1 = math::sqrt(c1 + math::sqr(tan_U1));
+ CT const temp_den_U2 = math::sqrt(c1 + math::sqr(tan_U2));
+ // cos = 1 / sqrt(1 + tan^2)
+ cos_U1 = c1 / temp_den_U1;
+ cos_U2 = c1 / temp_den_U2;
+ // sin = tan / sqrt(1 + tan^2)
+ sin_U1 = tan_U1 / temp_den_U1;
+ sin_U2 = tan_U2 / temp_den_U2;
+
+ // calculate sin U and cos U directly
+ //CT const U1 = atan(tan_U1);
+ //CT const U2 = atan(tan_U2);
+ //cos_U1 = cos(U1);
+ //cos_U2 = cos(U2);
+ //sin_U1 = tan_U1 * cos_U1; // sin(U1);
+ //sin_U2 = tan_U2 * cos_U2; // sin(U2);
+
+ CT previous_lambda;
+
+ int counter = 0; // robustness
+
+ do
+ {
+ previous_lambda = lambda; // (13)
+ sin_lambda = sin(lambda);
+ cos_lambda = cos(lambda);
+ sin_sigma = math::sqrt(math::sqr(cos_U2 * sin_lambda) + math::sqr(cos_U1 * sin_U2 - sin_U1 * cos_U2 * cos_lambda)); // (14)
+ CT cos_sigma = sin_U1 * sin_U2 + cos_U1 * cos_U2 * cos_lambda; // (15)
+ sin_alpha = cos_U1 * cos_U2 * sin_lambda / sin_sigma; // (17)
+ cos2_alpha = c1 - math::sqr(sin_alpha);
+ cos2_sigma_m = math::equals(cos2_alpha, 0) ? 0 : cos_sigma - c2 * sin_U1 * sin_U2 / cos2_alpha; // (18)
+
+ CT C = flattening/c16 * cos2_alpha * (c4 + flattening * (c4 - c3 * cos2_alpha)); // (10)
+ sigma = atan2(sin_sigma, cos_sigma); // (16)
+ lambda = L + (c1 - C) * flattening * sin_alpha *
+ (sigma + C * sin_sigma * ( cos2_sigma_m + C * cos_sigma * (-c1 + c2 * math::sqr(cos2_sigma_m)))); // (11)
+
+ ++counter; // robustness
+
+ } while ( geometry::math::abs(previous_lambda - lambda) > c_e_12
+ && geometry::math::abs(lambda) < pi
+ && counter < BOOST_GEOMETRY_DETAIL_VINCENTY_MAX_STEPS ); // robustness
+ }
+
+ inline CT distance() const
+ {
+ if ( is_result_zero )
+ {
+ return CT(0);
+ }
+
+ // Oops getting hard here
+ // (again, problem is that ttmath cannot divide by doubles, which is OK)
+ CT const c1 = 1;
+ CT const c2 = 2;
+ CT const c3 = 3;
+ CT const c4 = 4;
+ CT const c6 = 6;
+ CT const c47 = 47;
+ CT const c74 = 74;
+ CT const c128 = 128;
+ CT const c256 = 256;
+ CT const c175 = 175;
+ CT const c320 = 320;
+ CT const c768 = 768;
+ CT const c1024 = 1024;
+ CT const c4096 = 4096;
+ CT const c16384 = 16384;
+
+ //CT sqr_u = cos2_alpha * (math::sqr(radius_a) - math::sqr(radius_b)) / math::sqr(radius_b); // above (1)
+ CT sqr_u = cos2_alpha * ( math::sqr(radius_a / radius_b) - c1 ); // above (1)
+
+ CT A = c1 + sqr_u/c16384 * (c4096 + sqr_u * (-c768 + sqr_u * (c320 - c175 * sqr_u))); // (3)
+ CT B = sqr_u/c1024 * (c256 + sqr_u * ( -c128 + sqr_u * (c74 - c47 * sqr_u))); // (4)
+ CT delta_sigma = B * sin_sigma * ( cos2_sigma_m + (B/c4) * (cos(sigma)* (-c1 + c2 * cos2_sigma_m)
+ - (B/c6) * cos2_sigma_m * (-c3 + c4 * math::sqr(sin_sigma)) * (-c3 + c4 * cos2_sigma_m))); // (6)
+
+ return radius_b * A * (sigma - delta_sigma); // (19)
+ }
+
+ inline CT azimuth12() const
+ {
+ return is_result_zero ?
+ CT(0) :
+ atan2(cos_U2 * sin_lambda, cos_U1 * sin_U2 - sin_U1 * cos_U2 * cos_lambda); // (20)
+ }
+
+ inline CT azimuth21() const
+ {
+ // NOTE: signs of X and Y are different than in the original paper
+ return is_result_zero ?
+ CT(0) :
+ atan2(-cos_U1 * sin_lambda, sin_U1 * cos_U2 - cos_U1 * sin_U2 * cos_lambda); // (21)
+ }
+
+private:
+ // alpha: azimuth of the geodesic at the equator
+ CT cos2_alpha;
+ CT sin_alpha;
+
+ // sigma: angular distance p1,p2 on the sphere
+ // sigma1: angular distance on the sphere from the equator to p1
+ // sigma_m: angular distance on the sphere from the equator to the midpoint of the line
+ CT sigma;
+ CT sin_sigma;
+ CT cos2_sigma_m;
+
+ CT sin_lambda;
+ CT cos_lambda;
+
+ // set only once
+ CT cos_U1;
+ CT cos_U2;
+ CT sin_U1;
+ CT sin_U2;
+
+ // set only once
+ CT radius_a;
+ CT radius_b;
+
+ bool is_result_zero;
+};
+
+}}} // namespace boost::geometry::detail
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_VINCENTY_INVERSE_HPP
diff --git a/boost/geometry/algorithms/detail/within/point_in_geometry.hpp b/boost/geometry/algorithms/detail/within/point_in_geometry.hpp
index 6f1c181..e7486f0 100644
--- a/boost/geometry/algorithms/detail/within/point_in_geometry.hpp
+++ b/boost/geometry/algorithms/detail/within/point_in_geometry.hpp
@@ -5,8 +5,8 @@
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
-// This file was modified by Oracle on 2013, 2014.
-// Modifications copyright (c) 2013, 2014, Oracle and/or its affiliates.
+// This file was modified by Oracle on 2013, 2014, 2015.
+// Modifications copyright (c) 2013-2015, Oracle and/or its affiliates.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -21,6 +21,7 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_POINT_IN_GEOMETRY_HPP
#include <boost/assert.hpp>
+#include <boost/core/ignore_unused.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/range.hpp>
#include <boost/type_traits/is_same.hpp>
@@ -35,6 +36,7 @@
#include <boost/geometry/strategies/within.hpp>
#include <boost/geometry/strategies/covered_by.hpp>
+#include <boost/geometry/util/range.hpp>
#include <boost/geometry/views/detail/normalized_view.hpp>
namespace boost { namespace geometry {
@@ -58,7 +60,7 @@ inline T check_result_type(T result)
template <typename Point, typename Range, typename Strategy> inline
int point_in_range(Point const& point, Range const& range, Strategy const& strategy)
{
- boost::ignore_unused_variable_warning(strategy);
+ boost::ignore_unused(strategy);
typedef typename boost::range_iterator<Range const>::type iterator_type;
typename Strategy::state_type state;
@@ -147,7 +149,7 @@ struct point_in_geometry<Point2, point_tag>
template <typename Point1, typename Strategy> static inline
int apply(Point1 const& point1, Point2 const& point2, Strategy const& strategy)
{
- boost::ignore_unused_variable_warning(strategy);
+ boost::ignore_unused(strategy);
return strategy.apply(point1, point2) ? 1 : -1;
}
};
@@ -158,6 +160,8 @@ struct point_in_geometry<Segment, segment_tag>
template <typename Point, typename Strategy> static inline
int apply(Point const& point, Segment const& segment, Strategy const& strategy)
{
+ boost::ignore_unused(strategy);
+
typedef typename geometry::point_type<Segment>::type point_type;
point_type p0, p1;
// TODO: don't copy points
@@ -194,11 +198,11 @@ struct point_in_geometry<Linestring, linestring_tag>
return -1; // exterior
// if the linestring doesn't have a boundary
- if ( detail::equals::equals_point_point(*boost::begin(linestring), *(--boost::end(linestring))) )
+ if (detail::equals::equals_point_point(range::front(linestring), range::back(linestring)))
return 1; // interior
// else if the point is equal to the one of the terminal points
- else if ( detail::equals::equals_point_point(point, *boost::begin(linestring))
- || detail::equals::equals_point_point(point, *(--boost::end(linestring))) )
+ else if (detail::equals::equals_point_point(point, range::front(linestring))
+ || detail::equals::equals_point_point(point, range::back(linestring)))
return 0; // boundary
else
return 1; // interior
@@ -207,7 +211,7 @@ struct point_in_geometry<Linestring, linestring_tag>
// throw an exception here?
/*else if ( count == 1 )
{
- if ( detail::equals::equals_point_point(point, *boost::begin(linestring)) )
+ if ( detail::equals::equals_point_point(point, range::front(linestring)) )
return 1;
}*/
@@ -333,8 +337,8 @@ struct point_in_geometry<Geometry, multi_linestring_tag>
if ( boost::size(*it) < 2 )
continue;
- point_type const& front = *boost::begin(*it);
- point_type const& back = *(--boost::end(*it));
+ point_type const& front = range::front(*it);
+ point_type const& back = range::back(*it);
// is closed_ring - no boundary
if ( detail::equals::equals_point_point(front, back) )