summaryrefslogtreecommitdiff
path: root/boost/geometry
diff options
context:
space:
mode:
Diffstat (limited to 'boost/geometry')
-rw-r--r--boost/geometry/algorithms/correct.hpp22
-rw-r--r--boost/geometry/algorithms/correct_closure.hpp235
-rw-r--r--boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp43
-rw-r--r--boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp146
-rw-r--r--boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp29
-rw-r--r--boost/geometry/algorithms/detail/direction_code.hpp25
-rw-r--r--boost/geometry/algorithms/detail/disjoint/multipoint_geometry.hpp9
-rw-r--r--boost/geometry/algorithms/detail/distance/point_to_geometry.hpp2
-rw-r--r--boost/geometry/algorithms/detail/envelope/box.hpp15
-rw-r--r--boost/geometry/algorithms/detail/envelope/multipoint.hpp5
-rw-r--r--boost/geometry/algorithms/detail/envelope/point.hpp13
-rw-r--r--boost/geometry/algorithms/detail/envelope/range_of_boxes.hpp15
-rw-r--r--boost/geometry/algorithms/detail/envelope/segment.hpp66
-rw-r--r--boost/geometry/algorithms/detail/expand/box.hpp51
-rw-r--r--boost/geometry/algorithms/detail/expand/indexed.hpp42
-rw-r--r--boost/geometry/algorithms/detail/expand/point.hpp116
-rw-r--r--boost/geometry/algorithms/detail/expand/segment.hpp48
-rw-r--r--boost/geometry/algorithms/detail/has_self_intersections.hpp6
-rw-r--r--boost/geometry/algorithms/detail/intersection/multi.hpp16
-rw-r--r--boost/geometry/algorithms/detail/intersects/implementation.hpp3
-rw-r--r--boost/geometry/algorithms/detail/is_simple/linear.hpp3
-rw-r--r--boost/geometry/algorithms/detail/normalize.hpp27
-rw-r--r--boost/geometry/algorithms/detail/overlay/add_rings.hpp43
-rw-r--r--boost/geometry/algorithms/detail/overlay/aggregate_operations.hpp28
-rw-r--r--boost/geometry/algorithms/detail/overlay/assign_parents.hpp45
-rw-r--r--boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp18
-rw-r--r--boost/geometry/algorithms/detail/overlay/follow.hpp12
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_turns.hpp53
-rw-r--r--boost/geometry/algorithms/detail/overlay/handle_colocations.hpp93
-rw-r--r--boost/geometry/algorithms/detail/overlay/handle_self_turns.hpp193
-rw-r--r--boost/geometry/algorithms/detail/overlay/intersection_insert.hpp438
-rw-r--r--boost/geometry/algorithms/detail/overlay/is_self_turn.hpp11
-rw-r--r--boost/geometry/algorithms/detail/overlay/needs_self_turns.hpp83
-rw-r--r--boost/geometry/algorithms/detail/overlay/overlay.hpp133
-rw-r--r--boost/geometry/algorithms/detail/overlay/overlay_type.hpp27
-rw-r--r--boost/geometry/algorithms/detail/overlay/pointlike_linear.hpp1
-rw-r--r--boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp21
-rw-r--r--boost/geometry/algorithms/detail/overlay/segment_identifier.hpp3
-rw-r--r--boost/geometry/algorithms/detail/overlay/select_rings.hpp6
-rw-r--r--boost/geometry/algorithms/detail/overlay/self_turn_points.hpp32
-rw-r--r--boost/geometry/algorithms/detail/overlay/sort_by_side.hpp11
-rw-r--r--boost/geometry/algorithms/detail/overlay/traversal.hpp231
-rw-r--r--boost/geometry/algorithms/detail/overlay/traversal_intersection_patterns.hpp153
-rw-r--r--boost/geometry/algorithms/detail/overlay/traversal_ring_creator.hpp10
-rw-r--r--boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp409
-rw-r--r--boost/geometry/algorithms/detail/overlay/traverse.hpp10
-rw-r--r--boost/geometry/algorithms/detail/overlay/turn_info.hpp13
-rw-r--r--boost/geometry/algorithms/detail/relate/less.hpp83
-rw-r--r--boost/geometry/algorithms/detail/relate/linear_areal.hpp6
-rw-r--r--boost/geometry/algorithms/detail/relate/multi_point_geometry.hpp4
-rw-r--r--boost/geometry/algorithms/detail/relate/point_point.hpp9
-rw-r--r--boost/geometry/algorithms/detail/relate/topology_check.hpp7
-rw-r--r--boost/geometry/algorithms/detail/sections/section_functions.hpp27
-rw-r--r--boost/geometry/algorithms/detail/touches/implementation.hpp6
-rw-r--r--boost/geometry/algorithms/detail/within/multi_point.hpp7
-rw-r--r--boost/geometry/algorithms/dispatch/expand.hpp7
-rw-r--r--boost/geometry/core/exception.hpp23
-rw-r--r--boost/geometry/formulas/andoyer_inverse.hpp35
-rw-r--r--boost/geometry/formulas/area_formulas.hpp19
-rw-r--r--boost/geometry/formulas/authalic_radius_sqr.hpp96
-rw-r--r--boost/geometry/formulas/elliptic_arc_length.hpp214
-rw-r--r--boost/geometry/formulas/geographic.hpp7
-rw-r--r--boost/geometry/formulas/mean_radius.hpp71
-rw-r--r--boost/geometry/formulas/sjoberg_intersection.hpp81
-rw-r--r--boost/geometry/formulas/thomas_direct.hpp7
-rw-r--r--boost/geometry/formulas/unit_spheroid.hpp43
-rw-r--r--boost/geometry/geometries/helper_geometry.hpp15
-rw-r--r--boost/geometry/index/rtree.hpp6
-rw-r--r--boost/geometry/io/wkt/write.hpp115
-rw-r--r--boost/geometry/policies/compare.hpp276
-rw-r--r--boost/geometry/strategies/agnostic/buffer_distance_symmetric.hpp2
-rw-r--r--boost/geometry/strategies/agnostic/point_in_point.hpp2
-rw-r--r--boost/geometry/strategies/agnostic/point_in_poly_winding.hpp549
-rw-r--r--boost/geometry/strategies/cartesian/intersection.hpp5
-rw-r--r--boost/geometry/strategies/cartesian/point_in_poly_winding.hpp296
-rw-r--r--boost/geometry/strategies/cartesian/side_by_triangle.hpp16
-rw-r--r--boost/geometry/strategies/compare.hpp248
-rw-r--r--boost/geometry/strategies/geographic/area.hpp36
-rw-r--r--boost/geometry/strategies/geographic/distance.hpp41
-rw-r--r--boost/geometry/strategies/geographic/distance_cross_track.hpp641
-rw-r--r--boost/geometry/strategies/geographic/intersection.hpp21
-rw-r--r--boost/geometry/strategies/geographic/parameters.hpp51
-rw-r--r--boost/geometry/strategies/geographic/point_in_poly_winding.hpp80
-rw-r--r--boost/geometry/strategies/spherical/area.hpp11
-rw-r--r--boost/geometry/strategies/spherical/compare.hpp321
-rw-r--r--boost/geometry/strategies/spherical/compare_circular.hpp152
-rw-r--r--boost/geometry/strategies/spherical/distance_cross_track.hpp61
-rw-r--r--boost/geometry/strategies/spherical/intersection.hpp5
-rw-r--r--boost/geometry/strategies/spherical/point_in_poly_winding.hpp581
-rw-r--r--boost/geometry/strategies/spherical/side_by_cross_track.hpp23
-rw-r--r--boost/geometry/strategies/strategies.hpp6
-rw-r--r--boost/geometry/util/normalize_spheroidal_box_coordinates.hpp36
-rw-r--r--boost/geometry/util/normalize_spheroidal_coordinates.hpp135
93 files changed, 5518 insertions, 1979 deletions
diff --git a/boost/geometry/algorithms/correct.hpp b/boost/geometry/algorithms/correct.hpp
index a572d921d5..07e012fafa 100644
--- a/boost/geometry/algorithms/correct.hpp
+++ b/boost/geometry/algorithms/correct.hpp
@@ -32,6 +32,7 @@
#include <boost/variant/static_visitor.hpp>
#include <boost/variant/variant_fwd.hpp>
+#include <boost/geometry/algorithms/correct_closure.hpp>
#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
#include <boost/geometry/core/closure.hpp>
@@ -45,7 +46,6 @@
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/algorithms/area.hpp>
-#include <boost/geometry/algorithms/disjoint.hpp>
#include <boost/geometry/algorithms/detail/multi_modify.hpp>
#include <boost/geometry/util/order_as_direction.hpp>
@@ -140,23 +140,9 @@ struct correct_ring
template <typename Strategy>
static inline void apply(Ring& r, Strategy const& strategy)
{
- // Check close-ness
- if (boost::size(r) > 2)
- {
- // check if closed, if not, close it
- bool const disjoint = geometry::disjoint(*boost::begin(r), *(boost::end(r) - 1));
- closure_selector const s = geometry::closure<Ring>::value;
-
- if (disjoint && (s == closed))
- {
- geometry::append(r, *boost::begin(r));
- }
- if (! disjoint && s != closed)
- {
- // Open it by removing last point
- geometry::traits::resize<Ring>::apply(r, boost::size(r) - 1);
- }
- }
+ // Correct closure if necessary
+ detail::correct_closure::close_or_open_ring<Ring>::apply(r);
+
// Check area
typedef typename Strategy::return_type area_result_type;
Predicate<area_result_type> predicate;
diff --git a/boost/geometry/algorithms/correct_closure.hpp b/boost/geometry/algorithms/correct_closure.hpp
new file mode 100644
index 0000000000..323107f23a
--- /dev/null
+++ b/boost/geometry/algorithms/correct_closure.hpp
@@ -0,0 +1,235 @@
+// Boost.Geometry
+
+// Copyright (c) 2017 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_CORRECT_CLOSURE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_CORRECT_CLOSURE_HPP
+
+#include <cstddef>
+
+#include <boost/range.hpp>
+
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
+
+#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
+
+#include <boost/geometry/core/closure.hpp>
+#include <boost/geometry/core/exterior_ring.hpp>
+#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/core/ring_type.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+
+#include <boost/geometry/algorithms/disjoint.hpp>
+#include <boost/geometry/algorithms/detail/multi_modify.hpp>
+
+namespace boost { namespace geometry
+{
+
+// Silence warning C4127: conditional expression is constant
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4127)
+#endif
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace correct_closure
+{
+
+template <typename Geometry>
+struct nop
+{
+ static inline void apply(Geometry& )
+ {}
+};
+
+
+// Close a ring, if not closed, or open it
+template <typename Ring>
+struct close_or_open_ring
+{
+ static inline void apply(Ring& r)
+ {
+ if (boost::size(r) <= 2)
+ {
+ return;
+ }
+
+ bool const disjoint = geometry::disjoint(*boost::begin(r),
+ *(boost::end(r) - 1));
+ closure_selector const s = geometry::closure<Ring>::value;
+
+ if (disjoint && s == closed)
+ {
+ // Close it by adding first point
+ geometry::append(r, *boost::begin(r));
+ }
+ else if (! disjoint && s != closed)
+ {
+ // Open it by removing last point
+ geometry::traits::resize<Ring>::apply(r, boost::size(r) - 1);
+ }
+ }
+};
+
+// Close/open exterior ring and all its interior rings
+template <typename Polygon>
+struct close_or_open_polygon
+{
+ typedef typename ring_type<Polygon>::type ring_type;
+
+ static inline void apply(Polygon& poly)
+ {
+ close_or_open_ring<ring_type>::apply(exterior_ring(poly));
+
+ typename interior_return_type<Polygon>::type
+ rings = interior_rings(poly);
+
+ for (typename detail::interior_iterator<Polygon>::type
+ it = boost::begin(rings); it != boost::end(rings); ++it)
+ {
+ close_or_open_ring<ring_type>::apply(*it);
+ }
+ }
+};
+
+}} // namespace detail::correct_closure
+#endif // DOXYGEN_NO_DETAIL
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+template <typename Geometry, typename Tag = typename tag<Geometry>::type>
+struct correct_closure: not_implemented<Tag>
+{};
+
+template <typename Point>
+struct correct_closure<Point, point_tag>
+ : detail::correct_closure::nop<Point>
+{};
+
+template <typename LineString>
+struct correct_closure<LineString, linestring_tag>
+ : detail::correct_closure::nop<LineString>
+{};
+
+template <typename Segment>
+struct correct_closure<Segment, segment_tag>
+ : detail::correct_closure::nop<Segment>
+{};
+
+
+template <typename Box>
+struct correct_closure<Box, box_tag>
+ : detail::correct_closure::nop<Box>
+{};
+
+template <typename Ring>
+struct correct_closure<Ring, ring_tag>
+ : detail::correct_closure::close_or_open_ring<Ring>
+{};
+
+template <typename Polygon>
+struct correct_closure<Polygon, polygon_tag>
+ : detail::correct_closure::close_or_open_polygon<Polygon>
+{};
+
+
+template <typename MultiPoint>
+struct correct_closure<MultiPoint, multi_point_tag>
+ : detail::correct_closure::nop<MultiPoint>
+{};
+
+
+template <typename MultiLineString>
+struct correct_closure<MultiLineString, multi_linestring_tag>
+ : detail::correct_closure::nop<MultiLineString>
+{};
+
+
+template <typename Geometry>
+struct correct_closure<Geometry, multi_polygon_tag>
+ : detail::multi_modify
+ <
+ Geometry,
+ detail::correct_closure::close_or_open_polygon
+ <
+ typename boost::range_value<Geometry>::type
+ >
+ >
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+namespace resolve_variant
+{
+
+template <typename Geometry>
+struct correct_closure
+{
+ static inline void apply(Geometry& geometry)
+ {
+ concepts::check<Geometry const>();
+ dispatch::correct_closure<Geometry>::apply(geometry);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct correct_closure<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ struct visitor: boost::static_visitor<void>
+ {
+ template <typename Geometry>
+ void operator()(Geometry& geometry) const
+ {
+ correct_closure<Geometry>::apply(geometry);
+ }
+ };
+
+ static inline void
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry)
+ {
+ visitor vis;
+ boost::apply_visitor(vis, geometry);
+ }
+};
+
+} // namespace resolve_variant
+
+
+/*!
+\brief Closes or opens a geometry, according to its type
+\details Corrects a geometry w.r.t. closure points to all rings which do not
+ have a closing point and are typed as they should have one, the first point
+ is appended.
+\ingroup correct_closure
+\tparam Geometry \tparam_geometry
+\param geometry \param_geometry which will be corrected if necessary
+*/
+template <typename Geometry>
+inline void correct_closure(Geometry& geometry)
+{
+ resolve_variant::correct_closure<Geometry>::apply(geometry);
+}
+
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_CORRECT_CLOSURE_HPP
diff --git a/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp b/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp
index a149f1dd46..990081a86c 100644
--- a/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp
+++ b/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp
@@ -243,6 +243,7 @@ struct buffer_range
EndStrategy const& end_strategy,
RobustPolicy const& robust_policy,
Strategy const& strategy, // side strategy
+ bool linear,
output_point_type& first_p1,
output_point_type& first_p2,
output_point_type& last_p1,
@@ -274,6 +275,10 @@ struct buffer_range
* pup: penultimate_point
*/
+ bool const mark_flat
+ = linear
+ && end_strategy.get_piece_type() == geometry::strategy::buffer::buffered_flat_end;
+
geometry::strategy::buffer::result_code result = geometry::strategy::buffer::result_no_output;
bool first = true;
@@ -318,6 +323,11 @@ struct buffer_range
collection.add_side_piece(*prev, *it, generated_side, first);
+ if (first && mark_flat)
+ {
+ collection.mark_flat_start();
+ }
+
penultimate_point = *prev;
ultimate_point = *it;
last_p1 = generated_side.front();
@@ -331,6 +341,12 @@ struct buffer_range
first_p2 = generated_side.back();
}
}
+
+ if (mark_flat)
+ {
+ collection.mark_flat_end();
+ }
+
return result;
}
};
@@ -396,7 +412,7 @@ inline void buffer_point(Point const& point, Collection& collection,
DistanceStrategy const& distance_strategy,
PointStrategy const& point_strategy)
{
- collection.start_new_ring();
+ collection.start_new_ring(false);
std::vector<OutputPointType> range_out;
point_strategy.apply(point, distance_strategy, range_out);
collection.add_piece(geometry::strategy::buffer::buffered_point, range_out, false);
@@ -499,7 +515,7 @@ struct buffer_inserter_ring
side,
distance_strategy, side_strategy, join_strategy, end_strategy,
robust_policy, strategy,
- first_p1, first_p2, last_p1, last_p2);
+ false, first_p1, first_p2, last_p1, last_p2);
// Generate closing join
if (result == geometry::strategy::buffer::result_normal)
@@ -611,7 +627,7 @@ struct buffer_inserter<ring_tag, RingInput, RingOutput>
RobustPolicy const& robust_policy,
Strategy const& strategy) // side strategy
{
- collection.start_new_ring();
+ collection.start_new_ring(distance.negative());
geometry::strategy::buffer::result_code const code
= buffer_inserter_ring<RingInput, RingOutput>::apply(ring,
collection, distance,
@@ -689,7 +705,7 @@ struct buffer_inserter<linestring_tag, Linestring, Polygon>
begin, end, side,
distance_strategy, side_strategy, join_strategy, end_strategy,
robust_policy, strategy,
- first_p1, first_p2, last_p1, last_p2);
+ true, first_p1, first_p2, last_p1, last_p2);
if (result == geometry::strategy::buffer::result_normal)
{
@@ -729,7 +745,7 @@ struct buffer_inserter<linestring_tag, Linestring, Polygon>
std::size_t n = boost::size(simplified);
if (n > 1)
{
- collection.start_new_ring();
+ collection.start_new_ring(false);
output_point_type first_p1;
code = iterate(collection,
boost::begin(simplified), boost::end(simplified),
@@ -803,7 +819,13 @@ private:
{
for (Iterator it = begin; it != end; ++it)
{
- collection.start_new_ring();
+ // For exterior rings, it deflates if distance is negative.
+ // For interior rings, it is vice versa
+ bool const deflate = is_interior
+ ? ! distance.negative()
+ : distance.negative();
+
+ collection.start_new_ring(deflate);
geometry::strategy::buffer::result_code const code
= policy::apply(*it, collection, distance, side_strategy,
join_strategy, end_strategy, point_strategy,
@@ -865,7 +887,7 @@ public:
Strategy const& strategy) // side strategy
{
{
- collection.start_new_ring();
+ collection.start_new_ring(distance.negative());
geometry::strategy::buffer::result_code const code
= policy::apply(exterior_ring(polygon), collection,
@@ -956,11 +978,6 @@ 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
<
@@ -977,7 +994,7 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator
robust_policy, intersection_strategy.get_side_strategy());
collection.get_turns();
- collection.classify_turns(linear);
+ collection.classify_turns();
if (BOOST_GEOMETRY_CONDITION(areal))
{
collection.check_remaining_points(distance_strategy);
diff --git a/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp b/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp
index c0d906fe62..bc9c1ca7fb 100644
--- a/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp
+++ b/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp
@@ -46,6 +46,7 @@
#include <boost/geometry/algorithms/detail/overlay/enrichment_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp>
#include <boost/geometry/algorithms/detail/overlay/ring_properties.hpp>
+#include <boost/geometry/algorithms/detail/overlay/select_rings.hpp>
#include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/traverse.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
@@ -216,7 +217,10 @@ struct buffered_piece_collection
// 2: half, not part of offsetted rings - part of robust ring
std::vector<point_type> helper_points; // 4 points for side, 3 points for join - 0 points for flat-end
#endif
+ bool is_flat_start;
+ bool is_flat_end;
+ bool is_deflated;
bool is_convex;
bool is_monotonic_increasing[2]; // 0=x, 1=y
bool is_monotonic_decreasing[2]; // 0=x, 1=y
@@ -244,6 +248,9 @@ struct buffered_piece_collection
, right_index(-1)
, last_segment_index(-1)
, offsetted_count(-1)
+ , is_flat_start(false)
+ , is_flat_end(false)
+ , is_deflated(false)
, is_convex(false)
, robust_min_comparable_radius(0)
, robust_max_comparable_radius(0)
@@ -295,6 +302,8 @@ struct buffered_piece_collection
piece_vector_type m_pieces;
turn_vector_type m_turns;
signed_size_type m_first_piece_index;
+ bool m_deflate;
+ bool m_has_deflated;
buffered_ring_collection<buffered_ring<Ring> > offsetted_rings; // indexed by multi_index
std::vector<robust_original> robust_originals; // robust representation of the original(s)
@@ -333,6 +342,8 @@ struct buffered_piece_collection
buffered_piece_collection(IntersectionStrategy const& intersection_strategy,
RobustPolicy const& robust_policy)
: m_first_piece_index(-1)
+ , m_deflate(false)
+ , m_has_deflated(false)
, m_intersection_strategy(intersection_strategy)
, m_side_strategy(intersection_strategy.get_side_strategy())
, m_area_strategy(intersection_strategy.template get_area_strategy<point_type>())
@@ -498,7 +509,7 @@ struct buffered_piece_collection
}
}
- inline void classify_turns(bool linear)
+ inline void classify_turns()
{
for (typename boost::range_iterator<turn_vector_type>::type it =
boost::begin(m_turns); it != boost::end(m_turns); ++it)
@@ -507,7 +518,7 @@ struct buffered_piece_collection
{
it->location = inside_buffer;
}
- if (it->count_on_original_boundary > 0 && ! linear)
+ if (it->count_on_original_boundary > 0)
{
it->location = inside_buffer;
}
@@ -524,6 +535,90 @@ struct buffered_piece_collection
}
}
+ struct deflate_properties
+ {
+ bool has_inflated;
+ std::size_t count;
+
+ inline deflate_properties()
+ : has_inflated(false)
+ , count(0u)
+ {}
+ };
+
+ inline void discard_turns_for_deflate()
+ {
+ // Deflate cases should have at least 3 points PER deflated original
+ // to form a correct triangle
+
+ // But if there are intersections between a deflated ring and another
+ // ring, it is all accepted
+
+ // In deflate most turns are i/u by nature, but u/u is also possible
+
+ std::map<signed_size_type, deflate_properties> properties;
+
+ for (typename boost::range_iterator<turn_vector_type const>::type it =
+ boost::begin(m_turns); it != boost::end(m_turns); ++it)
+ {
+ const buffer_turn_info_type& turn = *it;
+ if (turn.location == location_ok)
+ {
+ const buffer_turn_operation_type& op0 = turn.operations[0];
+ const buffer_turn_operation_type& op1 = turn.operations[1];
+
+ if (! m_pieces[op0.seg_id.piece_index].is_deflated
+ || ! m_pieces[op1.seg_id.piece_index].is_deflated)
+ {
+ properties[op0.seg_id.multi_index].has_inflated = true;
+ properties[op1.seg_id.multi_index].has_inflated = true;
+ continue;
+ }
+
+ // It is deflated, update counts
+ for (int i = 0; i < 2; i++)
+ {
+ const buffer_turn_operation_type& op = turn.operations[i];
+ if (op.operation == detail::overlay::operation_union
+ || op.operation == detail::overlay::operation_continue)
+ {
+ properties[op.seg_id.multi_index].count++;
+ }
+ }
+ }
+ }
+
+ for (typename boost::range_iterator<turn_vector_type>::type it =
+ boost::begin(m_turns); it != boost::end(m_turns); ++it)
+ {
+ buffer_turn_info_type& turn = *it;
+
+ if (turn.location == location_ok)
+ {
+ const buffer_turn_operation_type& op0 = turn.operations[0];
+ const buffer_turn_operation_type& op1 = turn.operations[1];
+ signed_size_type const multi0 = op0.seg_id.multi_index;
+ signed_size_type const multi1 = op1.seg_id.multi_index;
+
+ if (multi0 == multi1)
+ {
+ const deflate_properties& prop = properties[multi0];
+ if (! prop.has_inflated && prop.count < 3)
+ {
+ // Property is not inflated
+ // Not enough points, this might be caused by <float> where
+ // detection turn-in-original failed because of numeric errors
+ turn.location = location_discard;
+ }
+ }
+ else
+ {
+ // Two different (possibly deflated) rings
+ }
+ }
+ }
+ }
+
template <typename DistanceStrategy>
inline void check_remaining_points(DistanceStrategy const& distance_strategy)
{
@@ -549,7 +644,7 @@ struct buffered_piece_collection
{
if (deflate && turn.count_in_original <= 0)
{
- // For deflate: it is not in original, discard
+ // For deflate/negative buffers: it is not in original, discard
turn.location = location_discard;
}
else if (! deflate && turn.count_in_original > 0)
@@ -559,6 +654,12 @@ struct buffered_piece_collection
}
}
}
+
+ if (m_has_deflated)
+ {
+ // Either strategy was negative, or there were interior rings
+ discard_turns_for_deflate();
+ }
}
inline bool assert_indices_in_robust_rings() const
@@ -827,7 +928,7 @@ struct buffered_piece_collection
}
}
- inline void start_new_ring()
+ inline void start_new_ring(bool deflate)
{
signed_size_type const n = static_cast<signed_size_type>(offsetted_rings.size());
current_segment_id.source_index = 0;
@@ -839,6 +940,13 @@ struct buffered_piece_collection
current_robust_ring.clear();
m_first_piece_index = static_cast<signed_size_type>(boost::size(m_pieces));
+ m_deflate = deflate;
+ if (deflate)
+ {
+ // Pieces contain either deflated exterior rings, or inflated
+ // interior rings which are effectively deflated too
+ m_has_deflated = true;
+ }
}
inline void abort_ring()
@@ -973,12 +1081,12 @@ struct buffered_piece_collection
piece pc;
pc.type = type;
pc.index = static_cast<signed_size_type>(boost::size(m_pieces));
+ pc.is_deflated = m_deflate;
current_segment_id.piece_index = pc.index;
pc.first_seg_id = current_segment_id;
-
// Assign left/right (for first/last piece per ring they will be re-assigned later)
pc.left_index = pc.index - 1;
pc.right_index = pc.index + 1;
@@ -1232,6 +1340,24 @@ struct buffered_piece_collection
}
}
+ inline void mark_flat_start()
+ {
+ if (! m_pieces.empty())
+ {
+ piece& back = m_pieces.back();
+ back.is_flat_start = true;
+ }
+ }
+
+ inline void mark_flat_end()
+ {
+ if (! m_pieces.empty())
+ {
+ piece& back = m_pieces.back();
+ back.is_flat_end = true;
+ }
+ }
+
//-------------------------------------------------------------------------
inline void enrich()
@@ -1369,12 +1495,14 @@ struct buffered_piece_collection
overlay_buffer,
backtrack_for_buffer
> traverser;
+ std::map<ring_identifier, overlay::ring_turn_info> turn_info_per_ring;
traversed_rings.clear();
buffer_overlay_visitor visitor;
traverser::apply(offsetted_rings, offsetted_rings,
m_intersection_strategy, m_robust_policy,
m_turns, traversed_rings,
+ turn_info_per_ring,
m_clusters, visitor);
}
@@ -1442,8 +1570,12 @@ struct buffered_piece_collection
}
}
- detail::overlay::assign_parents(offsetted_rings, traversed_rings, selected, m_intersection_strategy, true);
- return detail::overlay::add_rings<GeometryOutput>(selected, offsetted_rings, traversed_rings, out);
+ // Assign parents, checking orientation but NOT discarding double
+ // negative rings (negative child with negative parent)
+ detail::overlay::assign_parents(offsetted_rings, traversed_rings,
+ selected, m_intersection_strategy, true, false);
+ return detail::overlay::add_rings<GeometryOutput>(selected, offsetted_rings, traversed_rings, out,
+ m_area_strategy);
}
};
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 d23a3b3fd6..29e49f9dae 100644
--- a/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp
+++ b/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp
@@ -311,7 +311,11 @@ 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,
+#if defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
+ bool , // is on original, to be reused
+#else
bool is_original,
+#endif
Point const& offsetted)
{
boost::ignore_unused(offsetted);
@@ -340,11 +344,9 @@ class analyse_turn_wrt_piece
if (geometry::covered_by(turn.robust_point, box))
{
- // Points on helper-segments are considered as within
- // Points on original boundary are processed differently
- return is_original
- ? analyse_on_original_boundary
- : analyse_within;
+ // Points on helper-segments (and not on its corners)
+ // are considered as within
+ return analyse_within;
}
// It is collinear but not on the segment. Because these
@@ -424,6 +426,13 @@ class analyse_turn_wrt_piece
{
points[i] = piece.robust_ring[piece.offsetted_count + i];
}
+
+ // 3--offsetted outline--0
+ // | |
+ // left | | right
+ // | |
+ // 2===>==original===>===1
+
}
else if (helper_count == 3)
{
@@ -447,9 +456,15 @@ class analyse_turn_wrt_piece
{
return analyse_on_offsetted;
}
- if (comparator(point, points[1]) || comparator(point, points[2]))
+ if (comparator(point, points[1]))
+ {
+ // On original, right corner
+ return piece.is_flat_end ? analyse_continue : analyse_on_original_boundary;
+ }
+ if (comparator(point, points[2]))
{
- return analyse_on_original_boundary;
+ // On original, left corner
+ return piece.is_flat_start ? analyse_continue : analyse_on_original_boundary;
}
// Right side of the piece
diff --git a/boost/geometry/algorithms/detail/direction_code.hpp b/boost/geometry/algorithms/detail/direction_code.hpp
index c5c5221109..3a7d3d8789 100644
--- a/boost/geometry/algorithms/detail/direction_code.hpp
+++ b/boost/geometry/algorithms/detail/direction_code.hpp
@@ -114,7 +114,9 @@ struct direction_code_impl<Point, spherical_equatorial_tag>
typedef typename geometry::select_coordinate_type <Point1, Point2>::type calc_t;
typedef math::detail::constants_on_spheroid<coord1_t, units_t> constants1;
typedef math::detail::constants_on_spheroid<coord2_t, units_t> constants2;
- typedef math::detail::constants_on_spheroid<calc_t, units_t> constants;
+ static coord1_t const pi_half1 = constants1::max_latitude();
+ static coord2_t const pi_half2 = constants2::max_latitude();
+ static calc_t const c0 = 0;
coord1_t const a0 = geometry::get<0>(segment_a);
coord1_t const a1 = geometry::get<1>(segment_a);
@@ -122,11 +124,6 @@ struct direction_code_impl<Point, spherical_equatorial_tag>
coord1_t const b1 = geometry::get<1>(segment_b);
coord2_t const p0 = geometry::get<0>(p);
coord2_t const p1 = geometry::get<1>(p);
- coord1_t const pi_half1 = constants1::max_latitude();
- coord2_t const pi_half2 = constants2::max_latitude();
- calc_t const pi = constants::half_period();
- calc_t const pi_half = constants::max_latitude();
- calc_t const c0 = 0;
if ( (math::equals(b0, a0) && math::equals(b1, a1))
|| (math::equals(b0, p0) && math::equals(b1, p1)) )
@@ -147,12 +144,12 @@ struct direction_code_impl<Point, spherical_equatorial_tag>
// NOTE: as opposed to the implementation for cartesian CS
// here point b is the origin
- calc_t const dlon1 = math::longitude_distance_signed<units_t>(b0, a0);
- calc_t const dlon2 = math::longitude_distance_signed<units_t>(b0, p0);
+ calc_t const dlon1 = math::longitude_distance_signed<units_t, calc_t>(b0, a0);
+ calc_t const dlon2 = math::longitude_distance_signed<units_t, calc_t>(b0, p0);
bool is_antilon1 = false, is_antilon2 = false;
- calc_t const dlat1 = latitude_distance_signed(b1, a1, dlon1, pi, is_antilon1);
- calc_t const dlat2 = latitude_distance_signed(b1, p1, dlon2, pi, is_antilon2);
+ calc_t const dlat1 = latitude_distance_signed<units_t, calc_t>(b1, a1, dlon1, is_antilon1);
+ calc_t const dlat2 = latitude_distance_signed<units_t, calc_t>(b1, p1, dlon2, is_antilon2);
calc_t mx = is_a_pole || is_b_pole || is_p_pole ?
c0 :
@@ -176,10 +173,12 @@ struct direction_code_impl<Point, spherical_equatorial_tag>
return s1 == s2 ? -1 : 1;
}
- template <typename T>
- static inline T latitude_distance_signed(T const& lat1, T const& lat2, T const& lon_ds, T const& pi, bool & is_antilon)
+ template <typename Units, typename T>
+ static inline T latitude_distance_signed(T const& lat1, T const& lat2, T const& lon_ds, bool & is_antilon)
{
- T const c0 = 0;
+ typedef math::detail::constants_on_spheroid<T, Units> constants;
+ static T const pi = constants::half_period();
+ static T const c0 = 0;
T res = lat2 - lat1;
diff --git a/boost/geometry/algorithms/detail/disjoint/multipoint_geometry.hpp b/boost/geometry/algorithms/detail/disjoint/multipoint_geometry.hpp
index f8d3e3c593..d7aa9089e3 100644
--- a/boost/geometry/algorithms/detail/disjoint/multipoint_geometry.hpp
+++ b/boost/geometry/algorithms/detail/disjoint/multipoint_geometry.hpp
@@ -36,10 +36,11 @@
#include <boost/geometry/algorithms/detail/disjoint/point_box.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>
+#include <boost/geometry/policies/compare.hpp>
+
namespace boost { namespace geometry
{
@@ -56,10 +57,10 @@ class multipoint_multipoint
private:
template <typename Iterator>
class unary_disjoint_predicate
- : detail::relate::less
+ : geometry::less<>
{
private:
- typedef detail::relate::less base_type;
+ typedef geometry::less<> base_type;
public:
unary_disjoint_predicate(Iterator first, Iterator last)
@@ -90,7 +91,7 @@ public:
std::vector<point1_type> points1(boost::begin(multipoint1),
boost::end(multipoint1));
- std::sort(points1.begin(), points1.end(), detail::relate::less());
+ std::sort(points1.begin(), points1.end(), geometry::less<>());
typedef unary_disjoint_predicate
<
diff --git a/boost/geometry/algorithms/detail/distance/point_to_geometry.hpp b/boost/geometry/algorithms/detail/distance/point_to_geometry.hpp
index ab5de3d9b2..9596799cb2 100644
--- a/boost/geometry/algorithms/detail/distance/point_to_geometry.hpp
+++ b/boost/geometry/algorithms/detail/distance/point_to_geometry.hpp
@@ -391,7 +391,7 @@ struct distance
template <typename Point, typename Polygon, typename Strategy>
struct distance
<
- Point, Polygon, Strategy, point_tag, polygon_tag,
+ Point, Polygon, Strategy, point_tag, polygon_tag,
strategy_tag_distance_point_segment, false
> : detail::distance::point_to_polygon
<
diff --git a/boost/geometry/algorithms/detail/envelope/box.hpp b/boost/geometry/algorithms/detail/envelope/box.hpp
index 795f51392e..33b43da255 100644
--- a/boost/geometry/algorithms/detail/envelope/box.hpp
+++ b/boost/geometry/algorithms/detail/envelope/box.hpp
@@ -4,11 +4,12 @@
// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
-// This file was modified by Oracle on 2015, 2016.
-// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates.
+// This file was modified by Oracle on 2015, 2016, 2017.
+// Modifications copyright (c) 2015-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
@@ -146,13 +147,19 @@ namespace dispatch
{
-template <typename Box, typename CS_Tag>
-struct envelope<Box, box_tag, CS_Tag>
+template <typename Box>
+struct envelope<Box, box_tag, cartesian_tag>
: detail::envelope::envelope_box
{};
template <typename Box>
+struct envelope<Box, box_tag, spherical_polar_tag>
+ : detail::envelope::envelope_box_on_spheroid
+{};
+
+
+template <typename Box>
struct envelope<Box, box_tag, spherical_equatorial_tag>
: detail::envelope::envelope_box_on_spheroid
{};
diff --git a/boost/geometry/algorithms/detail/envelope/multipoint.hpp b/boost/geometry/algorithms/detail/envelope/multipoint.hpp
index efee4701c9..eef7563796 100644
--- a/boost/geometry/algorithms/detail/envelope/multipoint.hpp
+++ b/boost/geometry/algorithms/detail/envelope/multipoint.hpp
@@ -1,9 +1,10 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2015-2016, Oracle and/or its affiliates.
+// Copyright (c) 2015-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
@@ -336,8 +337,6 @@ public:
{
detail::expand::point_loop
<
- strategy::compare::default_strategy,
- strategy::compare::default_strategy,
2, dimension<Box>::value
>::apply(mbr, *it, strategy);
}
diff --git a/boost/geometry/algorithms/detail/envelope/point.hpp b/boost/geometry/algorithms/detail/envelope/point.hpp
index ee0559bf5f..86e73f3aa3 100644
--- a/boost/geometry/algorithms/detail/envelope/point.hpp
+++ b/boost/geometry/algorithms/detail/envelope/point.hpp
@@ -4,11 +4,12 @@
// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
-// This file was modified by Oracle on 2015, 2016.
+// This file was modified by Oracle on 2015, 2016, 2017.
// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
@@ -102,13 +103,19 @@ namespace dispatch
{
-template <typename Point, typename CS_Tag>
-struct envelope<Point, point_tag, CS_Tag>
+template <typename Point>
+struct envelope<Point, point_tag, cartesian_tag>
: detail::envelope::envelope_one_point<0, dimension<Point>::value>
{};
template <typename Point>
+struct envelope<Point, point_tag, spherical_polar_tag>
+ : detail::envelope::envelope_point_on_spheroid
+{};
+
+
+template <typename Point>
struct envelope<Point, point_tag, spherical_equatorial_tag>
: detail::envelope::envelope_point_on_spheroid
{};
diff --git a/boost/geometry/algorithms/detail/envelope/range_of_boxes.hpp b/boost/geometry/algorithms/detail/envelope/range_of_boxes.hpp
index f61fc422de..9b9e2f85d3 100644
--- a/boost/geometry/algorithms/detail/envelope/range_of_boxes.hpp
+++ b/boost/geometry/algorithms/detail/envelope/range_of_boxes.hpp
@@ -1,9 +1,10 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2015-2016, Oracle and/or its affiliates.
+// Copyright (c) 2015-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
@@ -194,8 +195,6 @@ struct envelope_range_of_boxes_by_expansion
{
detail::expand::indexed_loop
<
- strategy::compare::default_strategy,
- strategy::compare::default_strategy,
min_corner,
Dimension,
DimensionCount
@@ -203,8 +202,6 @@ struct envelope_range_of_boxes_by_expansion
detail::expand::indexed_loop
<
- strategy::compare::default_strategy,
- strategy::compare::default_strategy,
max_corner,
Dimension,
DimensionCount
@@ -243,9 +240,15 @@ struct envelope_range_of_boxes
RangeOfBoxes const
>::type iterator_type;
+ static const bool is_equatorial = ! boost::is_same
+ <
+ typename cs_tag<box_type>::type,
+ spherical_polar_tag
+ >::value;
+
typedef math::detail::constants_on_spheroid
<
- coordinate_type, units_type
+ coordinate_type, units_type, is_equatorial
> constants;
typedef longitude_interval<coordinate_type> interval_type;
diff --git a/boost/geometry/algorithms/detail/envelope/segment.hpp b/boost/geometry/algorithms/detail/envelope/segment.hpp
index 7e37194968..97f2fc84a8 100644
--- a/boost/geometry/algorithms/detail/envelope/segment.hpp
+++ b/boost/geometry/algorithms/detail/envelope/segment.hpp
@@ -80,6 +80,35 @@ struct envelope_segment_call_vertex_latitude<CalculationType, geographic_tag>
}
};
+template <typename Units, typename CS_Tag>
+struct envelope_segment_convert_polar
+{
+ template <typename T>
+ static inline void pre(T & , T & ) {}
+
+ template <typename T>
+ static inline void post(T & , T & ) {}
+};
+
+template <typename Units>
+struct envelope_segment_convert_polar<Units, spherical_polar_tag>
+{
+ template <typename T>
+ static inline void pre(T & lat1, T & lat2)
+ {
+ lat1 = math::latitude_convert_ep<Units>(lat1);
+ lat2 = math::latitude_convert_ep<Units>(lat2);
+ }
+
+ template <typename T>
+ static inline void post(T & lat1, T & lat2)
+ {
+ lat1 = math::latitude_convert_ep<Units>(lat1);
+ lat2 = math::latitude_convert_ep<Units>(lat2);
+ std::swap(lat1, lat2);
+ }
+};
+
template <typename CS_Tag>
class envelope_segment_impl
{
@@ -171,7 +200,7 @@ private:
lat1 = lat_min;
}
}
- else if (mid_lat > 0)
+ else
{
// update using max latitude
CalculationType const lat_max_rad = p_max;
@@ -266,29 +295,29 @@ private:
Box, box_coordinate_type, Units
>::type helper_box_type;
- helper_box_type radian_mbr;
+ helper_box_type helper_mbr;
geometry::set
<
min_corner, 0
- >(radian_mbr, boost::numeric_cast<box_coordinate_type>(lon1));
+ >(helper_mbr, boost::numeric_cast<box_coordinate_type>(lon1));
geometry::set
<
min_corner, 1
- >(radian_mbr, boost::numeric_cast<box_coordinate_type>(lat1));
+ >(helper_mbr, boost::numeric_cast<box_coordinate_type>(lat1));
geometry::set
<
max_corner, 0
- >(radian_mbr, boost::numeric_cast<box_coordinate_type>(lon2));
+ >(helper_mbr, boost::numeric_cast<box_coordinate_type>(lon2));
geometry::set
<
max_corner, 1
- >(radian_mbr, boost::numeric_cast<box_coordinate_type>(lat2));
+ >(helper_mbr, boost::numeric_cast<box_coordinate_type>(lat2));
- transform_units(radian_mbr, mbr);
+ transform_units(helper_mbr, mbr);
}
@@ -347,7 +376,14 @@ public:
Box& mbr,
Strategy const& strategy)
{
+ typedef envelope_segment_convert_polar<Units, typename cs_tag<Box>::type> convert_polar;
+
+ convert_polar::pre(lat1, lat2);
+
apply<Units>(lon1, lat1, lon2, lat2, strategy);
+
+ convert_polar::post(lat1, lat2);
+
create_box<Units>(lon1, lat1, lon2, lat2, mbr);
}
@@ -366,7 +402,14 @@ public:
Strategy const& strategy,
CalculationType alp1)
{
+ typedef envelope_segment_convert_polar<Units, typename cs_tag<Box>::type> convert_polar;
+
+ convert_polar::pre(lat1, lat2);
+
apply<Units>(lon1, lat1, lon2, lat2, strategy, alp1);
+
+ convert_polar::post(lat1, lat2);
+
create_box<Units>(lon1, lat1, lon2, lat2, mbr);
}
};
@@ -383,8 +426,6 @@ struct envelope_one_segment
envelope_one_point<Dimension, DimensionCount>::apply(p1, mbr, strategy);
detail::expand::point_loop
<
- strategy::compare::default_strategy,
- strategy::compare::default_strategy,
Dimension,
DimensionCount
>::apply(mbr, p2, strategy);
@@ -409,13 +450,14 @@ struct envelope_segment
envelope_one_segment<2, DimensionCount>::apply(p1, p2, mbr, strategy);
}
- template <typename Segment, typename Box>
- static inline void apply(Segment const& segment, Box& mbr)
+ template <typename Segment, typename Box, typename Strategy>
+ static inline void apply(Segment const& segment, Box& mbr,
+ Strategy const& strategy)
{
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]);
- apply(p[0], p[1], mbr);
+ apply(p[0], p[1], mbr, strategy);
}
};
diff --git a/boost/geometry/algorithms/detail/expand/box.hpp b/boost/geometry/algorithms/detail/expand/box.hpp
index 3edb23f5ae..485f4d25e6 100644
--- a/boost/geometry/algorithms/detail/expand/box.hpp
+++ b/boost/geometry/algorithms/detail/expand/box.hpp
@@ -5,11 +5,12 @@
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// Copyright (c) 2014-2015 Samuel Debionne, Grenoble, France.
-// This file was modified by Oracle on 2015, 2016.
-// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates.
+// This file was modified by Oracle on 2015, 2016, 2017.
+// Modifications copyright (c) 2015-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
@@ -73,48 +74,54 @@ namespace dispatch
template
<
typename BoxOut, typename BoxIn,
- typename StrategyLess, typename StrategyGreater,
typename CSTagOut, typename CSTag
>
struct expand
<
BoxOut, BoxIn,
- StrategyLess, StrategyGreater,
box_tag, box_tag,
CSTagOut, CSTag
- > : detail::expand::expand_indexed
- <
- 0, dimension<BoxIn>::value, StrategyLess, StrategyGreater
- >
+ >
{
- BOOST_MPL_ASSERT_MSG((boost::is_same<CSTagOut, CSTag>::value),
- COORDINATE_SYSTEMS_MUST_BE_THE_SAME,
+ BOOST_MPL_ASSERT_MSG((false),
+ NOT_IMPLEMENTED_FOR_THESE_COORDINATE_SYSTEMS,
(types<CSTagOut, CSTag>()));
};
-template
-<
- typename BoxOut, typename BoxIn,
- typename StrategyLess, typename StrategyGreater
->
+template <typename BoxOut, typename BoxIn>
+struct expand
+ <
+ BoxOut, BoxIn,
+ box_tag, box_tag,
+ cartesian_tag, cartesian_tag
+ > : detail::expand::expand_indexed
+ <
+ 0, dimension<BoxIn>::value
+ >
+{};
+
+template <typename BoxOut, typename BoxIn>
struct expand
<
BoxOut, BoxIn,
- StrategyLess, StrategyGreater,
box_tag, box_tag,
spherical_equatorial_tag, spherical_equatorial_tag
> : detail::expand::box_on_spheroid
{};
-template
-<
- typename BoxOut, typename BoxIn,
- typename StrategyLess, typename StrategyGreater
->
+template <typename BoxOut, typename BoxIn>
+struct expand
+ <
+ BoxOut, BoxIn,
+ box_tag, box_tag,
+ spherical_polar_tag, spherical_polar_tag
+ > : detail::expand::box_on_spheroid
+{};
+
+template <typename BoxOut, typename BoxIn>
struct expand
<
BoxOut, BoxIn,
- StrategyLess, StrategyGreater,
box_tag, box_tag,
geographic_tag, geographic_tag
> : detail::expand::box_on_spheroid
diff --git a/boost/geometry/algorithms/detail/expand/indexed.hpp b/boost/geometry/algorithms/detail/expand/indexed.hpp
index 28cf0e2e4f..fe7ee4f781 100644
--- a/boost/geometry/algorithms/detail/expand/indexed.hpp
+++ b/boost/geometry/algorithms/detail/expand/indexed.hpp
@@ -5,11 +5,12 @@
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// Copyright (c) 2014-2015 Samuel Debionne, Grenoble, France.
-// This file was modified by Oracle on 2015, 2016.
-// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates.
+// This file was modified by Oracle on 2015, 2016, 2017.
+// Modifications copyright (c) 2015-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -22,15 +23,13 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_INDEXED_HPP
#include <cstddef>
+#include <functional>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/util/select_coordinate_type.hpp>
-#include <boost/geometry/strategies/compare.hpp>
-#include <boost/geometry/policies/compare.hpp>
-
#include <boost/geometry/algorithms/dispatch/expand.hpp>
@@ -44,7 +43,6 @@ namespace detail { namespace expand
template
<
- typename StrategyLess, typename StrategyGreater,
std::size_t Index,
std::size_t Dimension, std::size_t DimensionCount
>
@@ -53,27 +51,17 @@ struct indexed_loop
template <typename Box, typename Geometry, typename Strategy>
static inline void apply(Box& box, Geometry const& source, Strategy const& strategy)
{
- typedef typename strategy::compare::detail::select_strategy
- <
- StrategyLess, 1, Box, Dimension
- >::type less_type;
-
- typedef typename strategy::compare::detail::select_strategy
- <
- StrategyGreater, -1, Box, Dimension
- >::type greater_type;
-
typedef typename select_coordinate_type
<
Box,
Geometry
>::type coordinate_type;
- less_type less;
- greater_type greater;
-
coordinate_type const coord = get<Index, Dimension>(source);
+ std::less<coordinate_type> less;
+ std::greater<coordinate_type> greater;
+
if (less(coord, get<min_corner, Dimension>(box)))
{
set<min_corner, Dimension>(box, coord);
@@ -86,21 +74,15 @@ struct indexed_loop
indexed_loop
<
- StrategyLess, StrategyGreater,
Index, Dimension + 1, DimensionCount
>::apply(box, source, strategy);
}
};
-template
-<
- typename StrategyLess, typename StrategyGreater,
- std::size_t Index, std::size_t DimensionCount
->
+template <std::size_t Index, std::size_t DimensionCount>
struct indexed_loop
<
- StrategyLess, StrategyGreater,
Index, DimensionCount, DimensionCount
>
{
@@ -111,11 +93,7 @@ struct indexed_loop
// Changes a box such that the other box is also contained by the box
-template
-<
- std::size_t Dimension, std::size_t DimensionCount,
- typename StrategyLess, typename StrategyGreater
->
+template <std::size_t Dimension, std::size_t DimensionCount>
struct expand_indexed
{
template <typename Box, typename Geometry, typename Strategy>
@@ -125,13 +103,11 @@ struct expand_indexed
{
indexed_loop
<
- StrategyLess, StrategyGreater,
0, Dimension, DimensionCount
>::apply(box, geometry, strategy);
indexed_loop
<
- StrategyLess, StrategyGreater,
1, Dimension, DimensionCount
>::apply(box, geometry, strategy);
}
diff --git a/boost/geometry/algorithms/detail/expand/point.hpp b/boost/geometry/algorithms/detail/expand/point.hpp
index f0cbd1db02..2d8b0feff6 100644
--- a/boost/geometry/algorithms/detail/expand/point.hpp
+++ b/boost/geometry/algorithms/detail/expand/point.hpp
@@ -5,11 +5,12 @@
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// Copyright (c) 2014-2015 Samuel Debionne, Grenoble, France.
-// This file was modified by Oracle on 2015, 2016.
-// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates.
+// This file was modified by Oracle on 2015, 2016, 2017.
+// Modifications copyright (c) 2015-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -23,6 +24,7 @@
#include <cstddef>
#include <algorithm>
+#include <functional>
#include <boost/mpl/assert.hpp>
#include <boost/type_traits/is_same.hpp>
@@ -36,9 +38,6 @@
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/select_coordinate_type.hpp>
-#include <boost/geometry/strategies/compare.hpp>
-#include <boost/geometry/policies/compare.hpp>
-
#include <boost/geometry/algorithms/detail/normalize.hpp>
#include <boost/geometry/algorithms/detail/envelope/transform_units.hpp>
@@ -53,33 +52,19 @@ namespace detail { namespace expand
{
-template
-<
- typename StrategyLess, typename StrategyGreater,
- std::size_t Dimension, std::size_t DimensionCount
->
+template <std::size_t Dimension, std::size_t DimensionCount>
struct point_loop
{
template <typename Box, typename Point, typename Strategy>
static inline void apply(Box& box, Point const& source, Strategy const& strategy)
{
- typedef typename strategy::compare::detail::select_strategy
- <
- StrategyLess, 1, Point, Dimension
- >::type less_type;
-
- typedef typename strategy::compare::detail::select_strategy
- <
- StrategyGreater, -1, Point, Dimension
- >::type greater_type;
-
typedef typename select_coordinate_type
<
Point, Box
>::type coordinate_type;
- less_type less;
- greater_type greater;
+ std::less<coordinate_type> less;
+ std::greater<coordinate_type> greater;
coordinate_type const coord = get<Dimension>(source);
@@ -93,37 +78,21 @@ struct point_loop
set<max_corner, Dimension>(box, coord);
}
- point_loop
- <
- StrategyLess, StrategyGreater, Dimension + 1, DimensionCount
- >::apply(box, source, strategy);
+ point_loop<Dimension + 1, DimensionCount>::apply(box, source, strategy);
}
};
-template
-<
- typename StrategyLess,
- typename StrategyGreater,
- std::size_t DimensionCount
->
-struct point_loop
- <
- StrategyLess, StrategyGreater, DimensionCount, DimensionCount
- >
+template <std::size_t DimensionCount>
+struct point_loop<DimensionCount, DimensionCount>
{
template <typename Box, typename Point, typename Strategy>
static inline void apply(Box&, Point const&, Strategy const&) {}
};
-// implementation for the spherical equatorial and geographic coordinate systems
-template
-<
- typename StrategyLess,
- typename StrategyGreater,
- std::size_t DimensionCount
->
+// implementation for the spherical and geographic coordinate systems
+template <std::size_t DimensionCount, bool IsEquatorial = true>
struct point_loop_on_spheroid
{
template <typename Box, typename Point, typename Strategy>
@@ -133,11 +102,12 @@ struct point_loop_on_spheroid
{
typedef typename point_type<Box>::type box_point_type;
typedef typename coordinate_type<Box>::type box_coordinate_type;
+ typedef typename coordinate_system<Box>::type::units units_type;
typedef math::detail::constants_on_spheroid
<
box_coordinate_type,
- typename coordinate_system<Box>::type::units
+ units_type
> constants;
// normalize input point and input box
@@ -157,7 +127,7 @@ struct point_loop_on_spheroid
b_lon_max = geometry::get<max_corner, 0>(box),
b_lat_max = geometry::get<max_corner, 1>(box);
- if (math::equals(math::abs(p_lat), constants::max_latitude()))
+ if (math::is_latitude_pole<units_type, IsEquatorial>(p_lat))
{
// the point of expansion is the either the north or the
// south pole; the only important coordinate here is the
@@ -169,7 +139,7 @@ struct point_loop_on_spheroid
}
if (math::equals(b_lat_min, b_lat_max)
- && math::equals(math::abs(b_lat_min), constants::max_latitude()))
+ && math::is_latitude_pole<units_type, IsEquatorial>(b_lat_min))
{
// the box degenerates to either the north or the south pole;
// the only important coordinate here is the pole's latitude,
@@ -228,7 +198,7 @@ struct point_loop_on_spheroid
point_loop
<
- StrategyLess, StrategyGreater, 2, DimensionCount
+ 2, DimensionCount
>::apply(box, point, strategy);
}
};
@@ -246,56 +216,70 @@ namespace dispatch
template
<
typename BoxOut, typename Point,
- typename StrategyLess, typename StrategyGreater,
typename CSTagOut, typename CSTag
>
struct expand
<
BoxOut, Point,
- StrategyLess, StrategyGreater,
box_tag, point_tag,
CSTagOut, CSTag
- > : detail::expand::point_loop
- <
- StrategyLess, StrategyGreater, 0, dimension<Point>::value
- >
+ >
{
- BOOST_MPL_ASSERT_MSG((boost::is_same<CSTagOut, CSTag>::value),
- COORDINATE_SYSTEMS_MUST_BE_THE_SAME,
+ BOOST_MPL_ASSERT_MSG((false),
+ NOT_IMPLEMENTED_FOR_THESE_COORDINATE_SYSTEMS,
(types<CSTagOut, CSTag>()));
};
-template
-<
- typename BoxOut, typename Point,
- typename StrategyLess, typename StrategyGreater
->
+
+template <typename BoxOut, typename Point>
+struct expand
+ <
+ BoxOut, Point,
+ box_tag, point_tag,
+ cartesian_tag, cartesian_tag
+ > : detail::expand::point_loop
+ <
+ 0, dimension<Point>::value
+ >
+{};
+
+template <typename BoxOut, typename Point>
struct expand
<
BoxOut, Point,
- StrategyLess, StrategyGreater,
box_tag, point_tag,
spherical_equatorial_tag, spherical_equatorial_tag
> : detail::expand::point_loop_on_spheroid
<
- StrategyLess, StrategyGreater, dimension<Point>::value
+ dimension<Point>::value
+ >
+{};
+
+template <typename BoxOut, typename Point>
+struct expand
+ <
+ BoxOut, Point,
+ box_tag, point_tag,
+ spherical_polar_tag, spherical_polar_tag
+ > : detail::expand::point_loop_on_spheroid
+ <
+ dimension<Point>::value,
+ false
>
{};
template
<
- typename BoxOut, typename Point,
- typename StrategyLess, typename StrategyGreater
+ typename BoxOut, typename Point
>
struct expand
<
BoxOut, Point,
- StrategyLess, StrategyGreater,
box_tag, point_tag,
geographic_tag, geographic_tag
> : detail::expand::point_loop_on_spheroid
<
- StrategyLess, StrategyGreater, dimension<Point>::value
+ dimension<Point>::value
>
{};
diff --git a/boost/geometry/algorithms/detail/expand/segment.hpp b/boost/geometry/algorithms/detail/expand/segment.hpp
index 0570e944d4..dddd3d2c7a 100644
--- a/boost/geometry/algorithms/detail/expand/segment.hpp
+++ b/boost/geometry/algorithms/detail/expand/segment.hpp
@@ -5,11 +5,12 @@
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// Copyright (c) 2014-2015 Samuel Debionne, Grenoble, France.
-// This file was modified by Oracle on 2015, 2016.
-// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates.
+// This file was modified by Oracle on 2015, 2016, 2017.
+// Modifications copyright (c) 2015-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
@@ -77,48 +78,57 @@ namespace dispatch
template
<
typename Box, typename Segment,
- typename StrategyLess, typename StrategyGreater,
typename CSTagOut, typename CSTag
>
struct expand
<
Box, Segment,
- StrategyLess, StrategyGreater,
box_tag, segment_tag,
CSTagOut, CSTag
- > : detail::expand::expand_indexed
- <
- 0, dimension<Segment>::value, StrategyLess, StrategyGreater
- >
+ >
{
- BOOST_MPL_ASSERT_MSG((boost::is_same<CSTagOut, CSTag>::value),
- COORDINATE_SYSTEMS_MUST_BE_THE_SAME,
+ BOOST_MPL_ASSERT_MSG((false),
+ NOT_IMPLEMENTED_FOR_THESE_COORDINATE_SYSTEMS,
(types<CSTagOut, CSTag>()));
};
template
<
- typename Box, typename Segment,
- typename StrategyLess, typename StrategyGreater
+ typename Box, typename Segment
>
struct expand
<
Box, Segment,
- StrategyLess, StrategyGreater,
+ box_tag, segment_tag,
+ cartesian_tag, cartesian_tag
+ > : detail::expand::expand_indexed
+ <
+ 0, dimension<Segment>::value
+ >
+{};
+
+template <typename Box, typename Segment>
+struct expand
+ <
+ Box, Segment,
+ box_tag, segment_tag,
+ spherical_polar_tag, spherical_polar_tag
+ > : detail::expand::segment
+{};
+
+template <typename Box, typename Segment>
+struct expand
+ <
+ Box, Segment,
box_tag, segment_tag,
spherical_equatorial_tag, spherical_equatorial_tag
> : detail::expand::segment
{};
-template
-<
- typename Box, typename Segment,
- typename StrategyLess, typename StrategyGreater
->
+template <typename Box, typename Segment>
struct expand
<
Box, Segment,
- StrategyLess, StrategyGreater,
box_tag, segment_tag,
geographic_tag, geographic_tag
> : detail::expand::segment
diff --git a/boost/geometry/algorithms/detail/has_self_intersections.hpp b/boost/geometry/algorithms/detail/has_self_intersections.hpp
index c34bb217a6..1289d946a5 100644
--- a/boost/geometry/algorithms/detail/has_self_intersections.hpp
+++ b/boost/geometry/algorithms/detail/has_self_intersections.hpp
@@ -81,7 +81,11 @@ inline bool has_self_intersections(Geometry const& geometry,
std::deque<turn_info> turns;
detail::disjoint::disjoint_interrupt_policy policy;
- detail::self_get_turn_points::self_turns<false, detail::overlay::assign_null_policy>(geometry, strategy, robust_policy, turns, policy);
+ detail::self_get_turn_points::self_turns
+ <
+ false,
+ detail::overlay::assign_null_policy
+ >(geometry, strategy, robust_policy, turns, policy, 0, false);
#ifdef BOOST_GEOMETRY_DEBUG_HAS_SELF_INTERSECTIONS
bool first = true;
diff --git a/boost/geometry/algorithms/detail/intersection/multi.hpp b/boost/geometry/algorithms/detail/intersection/multi.hpp
index 88b49b0167..92ce89bb2d 100644
--- a/boost/geometry/algorithms/detail/intersection/multi.hpp
+++ b/boost/geometry/algorithms/detail/intersection/multi.hpp
@@ -237,7 +237,7 @@ struct intersection_insert
OverlayType,
Reverse1, Reverse2, ReverseOut,
multi_linestring_tag, multi_linestring_tag, point_tag,
- false, false, false
+ linear_tag, linear_tag, pointlike_tag
> : detail::intersection::intersection_multi_linestring_multi_linestring_point
<
GeometryOut
@@ -259,7 +259,7 @@ struct intersection_insert
OverlayType,
Reverse1, Reverse2, ReverseOut,
linestring_tag, multi_linestring_tag, point_tag,
- false, false, false
+ linear_tag, linear_tag, pointlike_tag
> : detail::intersection::intersection_linestring_multi_linestring_point
<
GeometryOut
@@ -281,7 +281,7 @@ struct intersection_insert
OverlayType,
Reverse1, Reverse2, ReverseOut,
multi_linestring_tag, box_tag, linestring_tag,
- false, true, false
+ linear_tag, areal_tag, linear_tag
> : detail::intersection::clip_multi_linestring
<
GeometryOut
@@ -303,7 +303,7 @@ struct intersection_insert
OverlayType,
ReverseLinestring, ReverseMultiPolygon, ReverseOut,
linestring_tag, multi_polygon_tag, linestring_tag,
- false, true, false
+ linear_tag, areal_tag, linear_tag
> : detail::intersection::intersection_of_linestring_with_areal
<
ReverseMultiPolygon,
@@ -329,7 +329,7 @@ struct intersection_insert
OverlayType,
ReversePolygon, ReverseMultiLinestring, ReverseOut,
polygon_tag, multi_linestring_tag, linestring_tag,
- true, false, false
+ areal_tag, linear_tag, linear_tag
> : detail::intersection::intersection_of_areal_with_multi_linestring
<
ReversePolygon,
@@ -353,7 +353,7 @@ struct intersection_insert
OverlayType,
ReverseMultiLinestring, ReverseRing, ReverseOut,
multi_linestring_tag, ring_tag, linestring_tag,
- false, true, false
+ linear_tag, areal_tag, linear_tag
> : detail::intersection::intersection_of_multi_linestring_with_areal
<
ReverseRing,
@@ -376,7 +376,7 @@ struct intersection_insert
OverlayType,
ReverseMultiLinestring, ReverseRing, ReverseOut,
multi_linestring_tag, polygon_tag, linestring_tag,
- false, true, false
+ linear_tag, areal_tag, linear_tag
> : detail::intersection::intersection_of_multi_linestring_with_areal
<
ReverseRing,
@@ -401,7 +401,7 @@ struct intersection_insert
OverlayType,
ReverseMultiLinestring, ReverseMultiPolygon, ReverseOut,
multi_linestring_tag, multi_polygon_tag, linestring_tag,
- false, true, false
+ linear_tag, areal_tag, linear_tag
> : detail::intersection::intersection_of_multi_linestring_with_areal
<
ReverseMultiPolygon,
diff --git a/boost/geometry/algorithms/detail/intersects/implementation.hpp b/boost/geometry/algorithms/detail/intersects/implementation.hpp
index 2379168e83..f9b5402d0c 100644
--- a/boost/geometry/algorithms/detail/intersects/implementation.hpp
+++ b/boost/geometry/algorithms/detail/intersects/implementation.hpp
@@ -72,10 +72,11 @@ struct self_intersects
rescale_policy_type robust_policy;
detail::disjoint::disjoint_interrupt_policy policy;
+ // TODO: skip_adjacent should be set to false
detail::self_get_turn_points::get_turns
<
false, turn_policy
- >::apply(geometry, strategy, robust_policy, turns, policy, 0);
+ >::apply(geometry, strategy, robust_policy, turns, policy, 0, true);
return policy.has_intersections;
}
};
diff --git a/boost/geometry/algorithms/detail/is_simple/linear.hpp b/boost/geometry/algorithms/detail/is_simple/linear.hpp
index 5acf56c5b1..e36049a961 100644
--- a/boost/geometry/algorithms/detail/is_simple/linear.hpp
+++ b/boost/geometry/algorithms/detail/is_simple/linear.hpp
@@ -217,6 +217,7 @@ inline bool has_self_intersections(Linear const& linear, Strategy const& strateg
is_acceptable_turn<Linear>
> interrupt_policy(predicate);
+ // TODO: skip_adjacent should be set to false
detail::self_get_turn_points::get_turns
<
false, turn_policy
@@ -224,7 +225,7 @@ inline bool has_self_intersections(Linear const& linear, Strategy const& strateg
strategy,
detail::no_rescale_policy(),
turns,
- interrupt_policy, 0);
+ interrupt_policy, 0, true);
detail::is_valid::debug_print_turns(turns.begin(), turns.end());
debug_print_boundary_points(linear);
diff --git a/boost/geometry/algorithms/detail/normalize.hpp b/boost/geometry/algorithms/detail/normalize.hpp
index 913fe324b7..7a761d42bb 100644
--- a/boost/geometry/algorithms/detail/normalize.hpp
+++ b/boost/geometry/algorithms/detail/normalize.hpp
@@ -1,8 +1,9 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2015, Oracle and/or its affiliates.
+// Copyright (c) 2015-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
@@ -120,7 +121,7 @@ struct assign_loop<1, DimensionCount>
};
-template <typename PointIn, typename PointOut>
+template <typename PointIn, typename PointOut, bool IsEquatorial = true>
struct normalize_point
{
static inline void apply(PointIn const& point_in, PointOut& point_out)
@@ -133,6 +134,7 @@ struct normalize_point
math::normalize_spheroidal_coordinates
<
typename coordinate_system<PointIn>::type::units,
+ IsEquatorial,
in_coordinate_type
>(longitude, latitude);
@@ -144,7 +146,7 @@ struct normalize_point
};
-template <typename BoxIn, typename BoxOut>
+template <typename BoxIn, typename BoxOut, bool IsEquatorial = true>
class normalize_box
{
template <typename UnitsIn, typename UnitsOut, typename CoordinateInType>
@@ -193,6 +195,7 @@ public:
math::normalize_spheroidal_box_coordinates
<
typename coordinate_system<BoxIn>::type::units,
+ IsEquatorial,
in_coordinate_type
>(lon_min, lat_min, lon_max, lat_max);
@@ -237,6 +240,15 @@ struct normalize
template <typename PointIn, typename PointOut>
struct normalize
<
+ PointIn, PointOut, point_tag, point_tag,
+ spherical_polar_tag, spherical_polar_tag
+ > : detail::normalization::normalize_point<PointIn, PointOut, false>
+{};
+
+
+template <typename PointIn, typename PointOut>
+struct normalize
+ <
PointIn, PointOut, point_tag, point_tag, geographic_tag, geographic_tag
> : detail::normalization::normalize_point<PointIn, PointOut>
{};
@@ -254,6 +266,15 @@ struct normalize
template <typename BoxIn, typename BoxOut>
struct normalize
<
+ BoxIn, BoxOut, box_tag, box_tag,
+ spherical_polar_tag, spherical_polar_tag
+ > : detail::normalization::normalize_box<BoxIn, BoxOut, false>
+{};
+
+
+template <typename BoxIn, typename BoxOut>
+struct normalize
+ <
BoxIn, BoxOut, box_tag, box_tag, geographic_tag, geographic_tag
> : detail::normalization::normalize_box<BoxIn, BoxOut>
{};
diff --git a/boost/geometry/algorithms/detail/overlay/add_rings.hpp b/boost/geometry/algorithms/detail/overlay/add_rings.hpp
index fcb240941f..f64eb0b069 100644
--- a/boost/geometry/algorithms/detail/overlay/add_rings.hpp
+++ b/boost/geometry/algorithms/detail/overlay/add_rings.hpp
@@ -62,6 +62,13 @@ inline void convert_and_add(GeometryOut& result,
}
}
+enum add_rings_error_handling
+{
+ add_rings_ignore_unordered,
+ add_rings_add_unordered,
+ add_rings_throw_if_reversed
+};
+
template
<
typename GeometryOut,
@@ -69,16 +76,18 @@ template
typename Geometry1,
typename Geometry2,
typename RingCollection,
- typename OutputIterator
+ typename OutputIterator,
+ typename AreaStrategy
>
inline OutputIterator add_rings(SelectionMap const& map,
Geometry1 const& geometry1, Geometry2 const& geometry2,
RingCollection const& collection,
- OutputIterator out)
+ OutputIterator out,
+ AreaStrategy const& area_strategy,
+ add_rings_error_handling error_handling = add_rings_ignore_unordered)
{
typedef typename SelectionMap::const_iterator iterator;
- typedef typename SelectionMap::mapped_type property_type;
- typedef typename property_type::area_type area_type;
+ typedef typename AreaStrategy::return_type area_type;
area_type const zero = 0;
std::size_t const min_num_points = core_detail::closure::minimum_ring_size
@@ -122,10 +131,22 @@ inline OutputIterator add_rings(SelectionMap const& map,
// Only add rings if they satisfy minimal requirements.
// This cannot be done earlier (during traversal), not
// everything is figured out yet (sum of positive/negative rings)
- if (geometry::num_points(result) >= min_num_points
- && math::larger(geometry::area(result), zero))
+ if (geometry::num_points(result) >= min_num_points)
{
- *out++ = result;
+ area_type const area = geometry::area(result, area_strategy);
+ // Ignore if area is 0
+ if (! math::equals(area, zero))
+ {
+ if (error_handling == add_rings_add_unordered
+ || area > zero)
+ {
+ *out++ = result;
+ }
+ else if (error_handling == add_rings_throw_if_reversed)
+ {
+ BOOST_THROW_EXCEPTION(invalid_output_exception());
+ }
+ }
}
}
}
@@ -139,15 +160,17 @@ template
typename SelectionMap,
typename Geometry,
typename RingCollection,
- typename OutputIterator
+ typename OutputIterator,
+ typename AreaStrategy
>
inline OutputIterator add_rings(SelectionMap const& map,
Geometry const& geometry,
RingCollection const& collection,
- OutputIterator out)
+ OutputIterator out,
+ AreaStrategy const& area_strategy)
{
Geometry empty;
- return add_rings<GeometryOut>(map, geometry, empty, collection, out);
+ return add_rings<GeometryOut>(map, geometry, empty, collection, out, area_strategy);
}
diff --git a/boost/geometry/algorithms/detail/overlay/aggregate_operations.hpp b/boost/geometry/algorithms/detail/overlay/aggregate_operations.hpp
index 106ecaad07..3f2aea1b1d 100644
--- a/boost/geometry/algorithms/detail/overlay/aggregate_operations.hpp
+++ b/boost/geometry/algorithms/detail/overlay/aggregate_operations.hpp
@@ -25,7 +25,7 @@ struct ring_with_direction
ring_identifier ring_id;
direction_type direction;
- std::size_t turn_index;
+ signed_size_type turn_index;
int operation_index;
operation_type operation;
signed_size_type region_id;
@@ -50,8 +50,12 @@ struct ring_with_direction
struct rank_with_rings
{
+ // Define a set having a ring, with its direction (from/to). Each ring
+ // arrive at / leaves a cluster only once. TODO: this is not true for
+ // invalid ring. The rank needs to be considered too.
+ typedef std::set<ring_with_direction> container_type;
std::size_t rank;
- std::set<ring_with_direction> rings;
+ container_type rings;
rank_with_rings()
: rank(0)
@@ -60,7 +64,7 @@ struct rank_with_rings
inline bool all_equal(direction_type dir_type) const
{
- for (std::set<ring_with_direction>::const_iterator it = rings.begin();
+ for (container_type::const_iterator it = rings.begin();
it != rings.end(); ++it)
{
if (it->direction != dir_type)
@@ -83,7 +87,7 @@ struct rank_with_rings
inline bool has_only(operation_type op) const
{
- for (std::set<ring_with_direction>::const_iterator it = rings.begin();
+ for (container_type::const_iterator it = rings.begin();
it != rings.end(); ++it)
{
const ring_with_direction& rwd = *it;
@@ -100,7 +104,7 @@ struct rank_with_rings
{
bool has1 = false;
bool has2 = false;
- for (std::set<ring_with_direction>::const_iterator it = rings.begin();
+ for (container_type::const_iterator it = rings.begin();
it != rings.end(); ++it)
{
const ring_with_direction& rwd = *it;
@@ -114,7 +118,7 @@ struct rank_with_rings
inline bool is_isolated() const
{
- for (std::set<ring_with_direction>::const_iterator it = rings.begin();
+ for (container_type::const_iterator it = rings.begin();
it != rings.end(); ++it)
{
const ring_with_direction& rwd = *it;
@@ -128,8 +132,8 @@ struct rank_with_rings
inline bool has_unique_region_id() const
{
- int region_id = -1;
- for (std::set<ring_with_direction>::const_iterator it = rings.begin();
+ signed_size_type region_id = -1;
+ for (container_type::const_iterator it = rings.begin();
it != rings.end(); ++it)
{
const ring_with_direction& rwd = *it;
@@ -145,10 +149,10 @@ struct rank_with_rings
return true;
}
- inline int region_id() const
+ inline signed_size_type region_id() const
{
- int region_id = -1;
- for (std::set<ring_with_direction>::const_iterator it = rings.begin();
+ signed_size_type region_id = -1;
+ for (container_type::const_iterator it = rings.begin();
it != rings.end(); ++it)
{
const ring_with_direction& rwd = *it;
@@ -170,7 +174,7 @@ struct rank_with_rings
typedef typename boost::range_value<Turns>::type turn_type;
typedef typename turn_type::turn_operation_type turn_operation_type;
- for (std::set<ring_with_direction>::const_iterator it = rings.begin();
+ for (container_type::const_iterator it = rings.begin();
it != rings.end(); ++it)
{
const ring_with_direction& rwd = *it;
diff --git a/boost/geometry/algorithms/detail/overlay/assign_parents.hpp b/boost/geometry/algorithms/detail/overlay/assign_parents.hpp
index 78160f5204..c8ce651007 100644
--- a/boost/geometry/algorithms/detail/overlay/assign_parents.hpp
+++ b/boost/geometry/algorithms/detail/overlay/assign_parents.hpp
@@ -224,7 +224,8 @@ inline void assign_parents(Geometry1 const& geometry1,
RingCollection const& collection,
RingMap& ring_map,
Strategy const& strategy,
- bool check_for_orientation = false)
+ bool check_for_orientation = false,
+ bool discard_double_negative = false)
{
typedef typename geometry::tag<Geometry1>::type tag1;
typedef typename geometry::tag<Geometry2>::type tag2;
@@ -334,28 +335,38 @@ inline void assign_parents(Geometry1 const& geometry1,
for (map_iterator_type it = boost::begin(ring_map);
it != boost::end(ring_map); ++it)
{
- if (geometry::math::equals(it->second.get_area(), 0))
+ ring_info_type& info = it->second;
+ if (geometry::math::equals(info.get_area(), 0))
{
- it->second.discarded = true;
+ info.discarded = true;
}
- else if (it->second.parent.source_index >= 0
- && math::larger(it->second.get_area(), 0))
+ else if (info.parent.source_index >= 0)
{
- const ring_info_type& parent = ring_map[it->second.parent];
+ const ring_info_type& parent = ring_map[info.parent];
+ bool const pos = math::larger(info.get_area(), 0);
+ bool const parent_pos = math::larger(parent.area, 0);
- if (math::larger(parent.area, 0))
+ bool const double_neg = discard_double_negative && ! pos && ! parent_pos;
+
+ if ((pos && parent_pos) || double_neg)
{
// Discard positive inner ring with positive parent
- it->second.discarded = true;
+ // Also, for some cases (dissolve), negative inner ring
+ // with negative parent shouild be discarded
+ info.discarded = true;
+ }
+
+ if (pos || info.discarded)
+ {
+ // Remove parent ID from any positive or discarded inner rings
+ info.parent.source_index = -1;
}
- // Remove parent ID from any positive inner ring
- it->second.parent.source_index = -1;
}
- else if (it->second.parent.source_index < 0
- && math::smaller(it->second.get_area(), 0))
+ else if (info.parent.source_index < 0
+ && math::smaller(info.get_area(), 0))
{
// Reverse negative ring without parent
- it->second.reversed = true;
+ info.reversed = true;
}
}
}
@@ -372,7 +383,7 @@ inline void assign_parents(Geometry1 const& geometry1,
}
-// Version for one geometry (called by buffer)
+// Version for one geometry (called by buffer/dissolve)
template
<
typename Geometry,
@@ -384,13 +395,15 @@ inline void assign_parents(Geometry const& geometry,
RingCollection const& collection,
RingMap& ring_map,
Strategy const& strategy,
- bool check_for_orientation)
+ bool check_for_orientation,
+ bool discard_double_negative)
{
// Call it with an empty geometry as second geometry (source_id == 1)
// (ring_map should be empty for source_id==1)
Geometry empty;
- assign_parents(geometry, empty, collection, ring_map, strategy, check_for_orientation);
+ assign_parents(geometry, empty, collection, ring_map, strategy,
+ check_for_orientation, discard_double_negative);
}
diff --git a/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp b/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp
index 47225328df..e25445651a 100644
--- a/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp
+++ b/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp
@@ -118,7 +118,7 @@ inline void enrich_assign(Operations& operations, Turns& turns)
// Cluster behaviour: next should point after cluster, unless
// their seg_ids are not the same
- while (turn.cluster_id != -1
+ while (turn.is_clustered()
&& it->turn_index != next->turn_index
&& turn.cluster_id == turns[next->turn_index].cluster_id
&& op.seg_id == turns[next->turn_index].operations[next->operation_index].seg_id)
@@ -245,10 +245,6 @@ inline void calculate_remaining_distance(Turns& turns)
++it)
{
turn_type& turn = *it;
- if (! turn.both(detail::overlay::operation_continue))
- {
- continue;
- }
op_type& op0 = turn.operations[0];
op_type& op1 = turn.operations[1];
@@ -261,7 +257,7 @@ inline void calculate_remaining_distance(Turns& turns)
int const to_index0 = op0.enriched.get_next_turn_index();
int const to_index1 = op1.enriched.get_next_turn_index();
- if (to_index1 >= 0
+ if (to_index0 >= 0
&& to_index1 >= 0
&& to_index0 != to_index1)
{
@@ -359,12 +355,11 @@ inline void enrich_intersection_points(Turns& turns,
}
if (detail::overlay::is_self_turn<OverlayType>(turn)
- && turn.cluster_id < 0
+ && ! turn.is_clustered()
&& ! turn.both(target_operation))
{
// Only keep self-uu-turns or self-ii-turns
turn.discarded = true;
- turn.cluster_id = -1;
continue;
}
@@ -379,12 +374,12 @@ inline void enrich_intersection_points(Turns& turns,
<
OverlayType,
target_operation
- >::apply(turns, geometry1, geometry2);
+ >::apply(turns, clusters, geometry1, geometry2);
detail::overlay::discard_open_turns
<
OverlayType,
target_operation
- >::apply(turns, geometry1, geometry2);
+ >::apply(turns, clusters, geometry1, geometry2);
// Create a map of vectors of indexed operation-types to be able
// to sort intersection points PER RING
@@ -421,6 +416,9 @@ inline void enrich_intersection_points(Turns& turns,
detail::overlay::enrich_assign(mit->second, turns);
}
+ // Check some specific type of self-turns (after getting enriched info)
+ detail::overlay::discard_self_turns_which_loop<OverlayType>(turns);
+
if (has_colocations)
{
// First gather cluster properties (using even clusters with
diff --git a/boost/geometry/algorithms/detail/overlay/follow.hpp b/boost/geometry/algorithms/detail/overlay/follow.hpp
index 589e12cc2b..4a5993ea31 100644
--- a/boost/geometry/algorithms/detail/overlay/follow.hpp
+++ b/boost/geometry/algorithms/detail/overlay/follow.hpp
@@ -26,6 +26,7 @@
#include <boost/geometry/algorithms/covered_by.hpp>
#include <boost/geometry/algorithms/clear.hpp>
+#include <boost/geometry/algorithms/detail/relate/turns.hpp>
namespace boost { namespace geometry
@@ -343,6 +344,7 @@ template
class follow
{
+#ifdef BOOST_GEOMETRY_SETOPS_LA_OLD_BEHAVIOR
template <typename Turn>
struct sort_on_segment
{
@@ -389,7 +391,7 @@ class follow
}
};
-
+#endif // BOOST_GEOMETRY_SETOPS_LA_OLD_BEHAVIOR
public :
@@ -433,7 +435,15 @@ public :
// Sort intersection points on segments-along-linestring, and distance
// (like in enrich is done for poly/poly)
+ // 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
+#ifdef BOOST_GEOMETRY_SETOPS_LA_OLD_BEHAVIOR
std::sort(boost::begin(turns), boost::end(turns), sort_on_segment<turn_type>());
+#else
+ typedef relate::turns::less<0, relate::turns::less_op_linear_areal_single<0> > turn_less;
+ std::sort(boost::begin(turns), boost::end(turns), turn_less());
+#endif
LineStringOut current_piece;
geometry::segment_identifier current_segment_id(0, -1, -1, -1);
diff --git a/boost/geometry/algorithms/detail/overlay/get_turns.hpp b/boost/geometry/algorithms/detail/overlay/get_turns.hpp
index f88dfe8422..fd1e49ca24 100644
--- a/boost/geometry/algorithms/detail/overlay/get_turns.hpp
+++ b/boost/geometry/algorithms/detail/overlay/get_turns.hpp
@@ -144,7 +144,7 @@ class get_turns_in_sections
template <typename Geometry, typename Section>
- static inline bool neighbouring(Section const& section,
+ static inline bool adjacent(Section const& section,
signed_size_type index1, signed_size_type index2)
{
// About n-2:
@@ -152,7 +152,7 @@ class get_turns_in_sections
// -> 0-3 are adjacent, don't check on intersections)
// Also tested for open polygons, and/or duplicates
// About first condition: will be optimized by compiler (static)
- // It checks if it is areal (box,ring,(multi)polygon
+ // It checks if it is areal (box, ring, (multi)polygon)
signed_size_type const n = static_cast<signed_size_type>(section.range_count);
boost::ignore_unused_variable_warning(n);
@@ -180,7 +180,7 @@ public :
static inline bool apply(
int source_id1, Geometry1 const& geometry1, Section1 const& sec1,
int source_id2, Geometry2 const& geometry2, Section2 const& sec2,
- bool skip_larger,
+ bool skip_larger, bool skip_adjacent,
IntersectionStrategy const& intersection_strategy,
RobustPolicy const& robust_policy,
Turns& turns,
@@ -214,11 +214,6 @@ public :
signed_size_type index1 = sec1.begin_index;
signed_size_type ndi1 = sec1.non_duplicate_index;
- bool const same_source =
- source_id1 == source_id2
- && sec1.ring_id.multi_index == sec2.ring_id.multi_index
- && sec1.ring_id.ring_index == sec2.ring_id.ring_index;
-
range1_iterator prev1, it1, end1;
get_start_point_iterator(sec1, view1, prev1, it1, end1,
@@ -254,22 +249,32 @@ public :
it2 != end2 && ! detail::section::exceeding<0>(dir2, *prev2, sec2.bounding_box, sec1.bounding_box, robust_policy);
++prev2, ++it2, ++index2, ++next2, ++ndi2)
{
- bool skip = same_source;
- if (skip)
+ bool skip = false;
+
+ if (source_id1 == source_id2
+ && sec1.ring_id.multi_index == sec2.ring_id.multi_index
+ && sec1.ring_id.ring_index == sec2.ring_id.ring_index)
{
- // If sources are the same (possibly self-intersecting):
- // skip if it is a neighbouring segment.
- // (including first-last segment
- // and two segments with one or more degenerate/duplicate
- // (zero-length) segments in between)
-
- // Also skip if index1 < index2 to avoid getting all
- // intersections twice (only do this on same source!)
-
- skip = (skip_larger && index1 >= index2)
- || ndi2 == ndi1 + 1
- || neighbouring<Geometry1>(sec1, index1, index2)
- ;
+ // Sources and rings are the same
+
+ if (skip_larger && index1 >= index2)
+ {
+ // Skip to avoid getting all intersections twice
+ skip = true;
+ }
+ else if (skip_adjacent)
+ {
+ // In some cases (dissolve, has_self_intersections)
+ // neighbouring segments should be checked
+ // (for example to detect spikes properly)
+
+ // skip if it is a neighbouring segment.
+ // (including, for areas, first-last segment
+ // and two segments with one or more degenerate/duplicate
+ // (zero-length) segments in between)
+ skip = ndi2 == ndi1 + 1
+ || adjacent<Geometry1>(sec1, index1, index2);
+ }
}
if (! skip)
@@ -431,7 +436,7 @@ struct section_visitor
TurnPolicy
>::apply(m_source_id1, m_geometry1, sec1,
m_source_id2, m_geometry2, sec2,
- false,
+ false, false,
m_intersection_strategy,
m_rescale_policy,
m_turns, m_interrupt_policy);
diff --git a/boost/geometry/algorithms/detail/overlay/handle_colocations.hpp b/boost/geometry/algorithms/detail/overlay/handle_colocations.hpp
index f3311b34e9..c634fc450f 100644
--- a/boost/geometry/algorithms/detail/overlay/handle_colocations.hpp
+++ b/boost/geometry/algorithms/detail/overlay/handle_colocations.hpp
@@ -24,6 +24,7 @@
#include <boost/geometry/core/point_order.hpp>
#include <boost/geometry/algorithms/detail/overlay/cluster_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/do_reverse.hpp>
+#include <boost/geometry/algorithms/detail/overlay/is_self_turn.hpp>
#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
#include <boost/geometry/algorithms/detail/overlay/sort_by_side.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
@@ -181,6 +182,7 @@ inline signed_size_type add_turn_to_cluster(Turn const& turn,
if (cid0 == -1 && cid1 == -1)
{
+ // Because of this, first cluster ID will be 1
++cluster_id;
add_cluster_id(turn.operations[0], cluster_per_segment, cluster_id);
add_cluster_id(turn.operations[1], cluster_per_segment, cluster_id);
@@ -314,7 +316,7 @@ inline void assign_cluster_to_turns(Turns& turns,
if (it != cluster_per_segment.end())
{
#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_COLOCATIONS)
- if (turn.cluster_id != -1
+ if (turn.is_clustered()
&& turn.cluster_id != it->second)
{
std::cout << " CONFLICT " << std::endl;
@@ -503,6 +505,7 @@ inline void discard_interior_exterior_turns(Turns& turns, Clusters& clusters)
template
<
+ overlay_type OverlayType,
typename Turns,
typename Clusters
>
@@ -517,38 +520,65 @@ inline void set_colocation(Turns& turns, Clusters const& clusters)
cluster_info const& cinfo = cit->second;
std::set<signed_size_type> const& ids = cinfo.turn_indices;
- bool has_ii = false;
- bool has_uu = false;
+ bool both_target = false;
for (set_iterator it = ids.begin(); it != ids.end(); ++it)
{
turn_type const& turn = turns[*it];
- if (turn.both(operation_intersection))
- {
- has_ii = true;
- }
- if (turn.both(operation_union) || turn.combination(operation_union, operation_blocked))
+ if (turn.both(operation_from_overlay<OverlayType>::value))
{
- has_uu = true;
+ both_target = true;
+ break;
}
}
- if (has_ii || has_uu)
+
+ if (both_target)
{
for (set_iterator it = ids.begin(); it != ids.end(); ++it)
{
turn_type& turn = turns[*it];
- if (has_ii)
- {
- turn.colocated_ii = true;
- }
- if (has_uu)
+
+ if (both_target)
{
- turn.colocated_uu = true;
+ turn.has_colocated_both = true;
}
}
}
}
}
+template
+<
+ typename Turns,
+ typename Clusters
+>
+inline void check_colocation(bool& has_blocked,
+ int cluster_id, Turns const& turns, Clusters const& clusters)
+{
+ typedef typename boost::range_value<Turns>::type turn_type;
+
+ has_blocked = false;
+
+ typename Clusters::const_iterator mit = clusters.find(cluster_id);
+ if (mit == clusters.end())
+ {
+ return;
+ }
+
+ cluster_info const& cinfo = mit->second;
+
+ for (std::set<signed_size_type>::const_iterator it
+ = cinfo.turn_indices.begin();
+ it != cinfo.turn_indices.end(); ++it)
+ {
+ turn_type const& turn = turns[*it];
+ if (turn.any_blocked())
+ {
+ has_blocked = true;
+ }
+ }
+}
+
+
// Checks colocated turns and flags combinations of uu/other, possibly a
// combination of a ring touching another geometry's interior ring which is
// tangential to the exterior ring
@@ -627,6 +657,10 @@ inline bool handle_colocations(Turns& turns, Clusters& clusters,
> cluster_per_segment_type;
cluster_per_segment_type cluster_per_segment;
+
+ // Assign to zero, because of pre-increment later the cluster_id
+ // effectively starts with 1
+ // (and can later be negated to use uniquely with turn_index)
signed_size_type cluster_id = 0;
for (typename map_type::const_iterator it = map.begin();
@@ -640,7 +674,9 @@ inline bool handle_colocations(Turns& turns, Clusters& clusters,
}
assign_cluster_to_turns(turns, clusters, cluster_per_segment);
- set_colocation(turns, clusters);
+ // Get colocated information here and not later, to keep information
+ // on turns which are discarded afterwards
+ set_colocation<OverlayType>(turns, clusters);
discard_interior_exterior_turns
<
do_reverse<geometry::point_order<Geometry1>::value>::value != Reverse1,
@@ -758,14 +794,21 @@ inline void gather_cluster_properties(Clusters& clusters, Turns& turns,
cinfo.open_count = sbs.open_count(for_operation);
- // Unset the startable flag for all 'closed' zones
+ bool const set_startable
+ = OverlayType != overlay_dissolve_union
+ && OverlayType != overlay_dissolve_intersection;
+
+ // Unset the startable flag for all 'closed' zones. This does not
+ // apply for self-turns, because those counts are not from both
+ // polygons
for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++)
{
const typename sbs_type::rp& ranked = sbs.m_ranked_points[i];
turn_type& turn = turns[ranked.turn_index];
turn_operation_type& op = turn.operations[ranked.operation_index];
- if (for_operation == operation_union && cinfo.open_count == 0)
+ if (set_startable
+ && for_operation == operation_union && cinfo.open_count == 0)
{
op.enriched.startable = false;
}
@@ -780,6 +823,18 @@ inline void gather_cluster_properties(Clusters& clusters, Turns& turns,
op.enriched.rank = ranked.rank;
op.enriched.zone = ranked.zone;
+ if (! set_startable)
+ {
+ continue;
+ }
+
+ if (OverlayType != overlay_difference
+ && is_self_turn<OverlayType>(turn))
+ {
+ // Difference needs the self-turns, TODO: investigate
+ continue;
+ }
+
if ((for_operation == operation_union
&& ranked.count_left != 0)
|| (for_operation == operation_intersection
diff --git a/boost/geometry/algorithms/detail/overlay/handle_self_turns.hpp b/boost/geometry/algorithms/detail/overlay/handle_self_turns.hpp
index 39c55db759..9c4a3094e0 100644
--- a/boost/geometry/algorithms/detail/overlay/handle_self_turns.hpp
+++ b/boost/geometry/algorithms/detail/overlay/handle_self_turns.hpp
@@ -11,6 +11,7 @@
#include <boost/range.hpp>
+#include <boost/geometry/algorithms/detail/overlay/cluster_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/is_self_turn.hpp>
#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
#include <boost/geometry/algorithms/within.hpp>
@@ -24,9 +25,9 @@ namespace detail { namespace overlay
struct discard_turns
{
- template <typename Turns, typename Geometry0, typename Geometry1>
+ template <typename Turns, typename Clusters, typename Geometry0, typename Geometry1>
static inline
- void apply(Turns& , Geometry0 const& , Geometry1 const& )
+ void apply(Turns& , Clusters const& , Geometry0 const& , Geometry1 const& )
{}
};
@@ -38,9 +39,9 @@ template <>
struct discard_closed_turns<overlay_union, operation_union>
{
- template <typename Turns, typename Geometry0, typename Geometry1>
+ template <typename Turns, typename Clusters, typename Geometry0, typename Geometry1>
static inline
- void apply(Turns& turns,
+ void apply(Turns& turns, Clusters const& clusters,
Geometry0 const& geometry0, Geometry1 const& geometry1)
{
typedef typename boost::range_value<Turns>::type turn_type;
@@ -52,9 +53,7 @@ struct discard_closed_turns<overlay_union, operation_union>
{
turn_type& turn = *it;
- if (turn.cluster_id >= 0
- || turn.discarded
- || ! is_self_turn<overlay_union>(turn))
+ if (turn.discarded || ! is_self_turn<overlay_union>(turn))
{
continue;
}
@@ -75,11 +74,106 @@ struct discard_closed_turns<overlay_union, operation_union>
struct discard_self_intersection_turns
{
- template <typename Turns, typename Geometry0, typename Geometry1>
+private :
+
+ template <typename Turns, typename Clusters>
+ static inline
+ bool any_blocked(signed_size_type cluster_id,
+ const Turns& turns, Clusters const& clusters)
+ {
+ typename Clusters::const_iterator cit = clusters.find(cluster_id);
+ if (cit == clusters.end())
+ {
+ return false;
+ }
+ cluster_info const& cinfo = cit->second;
+ for (std::set<signed_size_type>::const_iterator it
+ = cinfo.turn_indices.begin();
+ it != cinfo.turn_indices.end(); ++it)
+ {
+ typename boost::range_value<Turns>::type const& turn = turns[*it];
+ if (turn.any_blocked())
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ template <typename Turns, typename Clusters>
+ static inline
+ bool is_self_cluster(signed_size_type cluster_id,
+ const Turns& turns, Clusters const& clusters)
+ {
+ typename Clusters::const_iterator cit = clusters.find(cluster_id);
+ if (cit == clusters.end())
+ {
+ return false;
+ }
+
+ cluster_info const& cinfo = cit->second;
+ for (std::set<signed_size_type>::const_iterator it
+ = cinfo.turn_indices.begin();
+ it != cinfo.turn_indices.end(); ++it)
+ {
+ if (! is_self_turn<overlay_intersection>(turns[*it]))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ template <typename Turn, typename Geometry0, typename Geometry1>
+ static inline
+ bool within(Turn const& turn, Geometry0 const& geometry0,
+ Geometry1 const& geometry1)
+ {
+ return turn.operations[0].seg_id.source_index == 0
+ ? geometry::within(turn.point, geometry1)
+ : geometry::within(turn.point, geometry0);
+ }
+
+ template <typename Turns, typename Clusters,
+ typename Geometry0, typename Geometry1>
+ static inline
+ void discard_clusters(Turns& turns, Clusters const& clusters,
+ Geometry0 const& geometry0, Geometry1 const& geometry1)
+ {
+ for (typename Clusters::const_iterator cit = clusters.begin();
+ cit != clusters.end(); ++cit)
+ {
+ signed_size_type cluster_id = cit->first;
+
+ // If there are only self-turns in the cluster, the cluster should
+ // be located within the other geometry, for intersection
+ if (is_self_cluster(cluster_id, turns, clusters))
+ {
+ cluster_info const& cinfo = cit->second;
+ if (! within(turns[*cinfo.turn_indices.begin()], geometry0, geometry1))
+ {
+ // Discard all turns in cluster
+ for (std::set<signed_size_type>::const_iterator sit = cinfo.turn_indices.begin();
+ sit != cinfo.turn_indices.end(); ++sit)
+ {
+ turns[*sit].discarded = true;
+ }
+ }
+ }
+ }
+ }
+
+public :
+
+ template <typename Turns, typename Clusters,
+ typename Geometry0, typename Geometry1>
static inline
- void apply(Turns& turns,
+ void apply(Turns& turns, Clusters const& clusters,
Geometry0 const& geometry0, Geometry1 const& geometry1)
{
+ discard_clusters(turns, clusters, geometry0, geometry1);
+
typedef typename boost::range_value<Turns>::type turn_type;
for (typename boost::range_iterator<Turns>::type
@@ -89,9 +183,7 @@ struct discard_self_intersection_turns
{
turn_type& turn = *it;
- if (turn.cluster_id >= 0
- || turn.discarded
- || ! is_self_turn<overlay_intersection>(turn))
+ if (turn.discarded || ! is_self_turn<overlay_intersection>(turn))
{
continue;
}
@@ -106,16 +198,22 @@ struct discard_self_intersection_turns
continue;
}
- // It is a non co-located ii self-turn
+ if (turn.is_clustered() && turn.has_colocated_both)
+ {
+ // Don't delete a self-ii-turn colocated with another ii-turn
+ // (for example #case_recursive_boxes_70)
+ // But for some cases (#case_58_iet) they should be deleted,
+ // there are many self-turns there and also blocked turns there
+ if (! any_blocked(turn.cluster_id, turns, clusters))
+ {
+ continue;
+ }
+ }
+
+ // It is a ii self-turn
// Check if it is within the other geometry
// If not, it can be ignored
-
- bool const within =
- turn.operations[0].seg_id.source_index == 0
- ? geometry::within(turn.point, geometry1)
- : geometry::within(turn.point, geometry0);
-
- if (! within)
+ if (! within(turn, geometry0, geometry1))
{
// It is not within another geometry, discard the turn
turn.discarded = true;
@@ -134,6 +232,61 @@ struct discard_open_turns<overlay_intersection, operation_intersection>
// For difference, it should be done in a different way (TODO)
+
+template <overlay_type OverlayType, typename Turns>
+inline void discard_self_turns_which_loop(Turns& turns)
+{
+ if (operation_from_overlay<OverlayType>::value == operation_union)
+ {
+ // For union, self-turn i/u traveling to itself are allowed to form
+ // holes. #case_recursive_boxes_37
+ // TODO: this can be finetuned by inspecting the cluster too,
+ // and if there are non-self-turns the polygons on their sides can
+ // be checked
+ return;
+ }
+
+ typedef typename boost::range_value<Turns>::type turn_type;
+ typedef typename turn_type::turn_operation_type op_type;
+
+ signed_size_type turn_index = 0;
+ for (typename boost::range_iterator<Turns>::type
+ it = boost::begin(turns);
+ it != boost::end(turns);
+ ++it, ++turn_index)
+ {
+ turn_type& turn = *it;
+
+ if (! is_self_turn<OverlayType>(turn))
+ {
+ continue;
+ }
+ if (! turn.combination(operation_intersection, operation_union))
+ {
+ // ii may travel to itself
+ continue;
+ }
+
+ for (int i = 0; i < 2; i++)
+ {
+ op_type& op = turn.operations[i];
+
+ if (op.enriched.startable
+ && op.operation == operation_intersection
+ && op.enriched.get_next_turn_index() == turn_index)
+ {
+ // Self-turn i/u, i part traveling to itself. Discard it.
+ // (alternatively it might be made unstartable - but the
+ // intersection-operation may not be traveled anyway, and the
+ // union-operation is not traveled at all in intersections
+ // #case_recursive_boxes_77
+ turn.discarded = true;
+ }
+ }
+ }
+
+}
+
}} // namespace detail::overlay
#endif //DOXYGEN_NO_DETAIL
diff --git a/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp b/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp
index 7106e7b480..60255cd953 100644
--- a/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp
+++ b/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp
@@ -208,6 +208,8 @@ struct intersection_of_linestring_with_areal
}
#endif
+#ifdef BOOST_GEOMETRY_SETOPS_LA_OLD_BEHAVIOR
+
class is_crossing_turn
{
// return true is the operation is intersection or blocked
@@ -310,6 +312,91 @@ struct intersection_of_linestring_with_areal
return 0;
}
+#else // BOOST_GEOMETRY_SETOPS_LA_OLD_BEHAVIOR
+
+ template <typename Linestring, typename Areal, typename Strategy, typename Turns>
+ static inline bool simple_turns_analysis(Linestring const& linestring,
+ Areal const& areal,
+ Strategy const& strategy,
+ Turns const& turns,
+ int & inside_value)
+ {
+ using namespace overlay;
+
+ bool found_continue = false;
+ bool found_intersection = false;
+ bool found_union = false;
+ bool found_front = false;
+
+ for (typename Turns::const_iterator it = turns.begin();
+ it != turns.end(); ++it)
+ {
+ method_type const method = it->method;
+ operation_type const op = it->operations[0].operation;
+
+ if (method == method_crosses)
+ {
+ return false;
+ }
+ else if (op == operation_intersection)
+ {
+ found_intersection = true;
+ }
+ else if (op == operation_union)
+ {
+ found_union = true;
+ }
+ else if (op == operation_continue)
+ {
+ found_continue = true;
+ }
+
+ if ((found_intersection || found_continue) && found_union)
+ {
+ return false;
+ }
+
+ if (it->operations[0].position == position_front)
+ {
+ found_front = true;
+ }
+ }
+
+ if (found_front)
+ {
+ if (found_intersection)
+ {
+ inside_value = 1; // inside
+ }
+ else if (found_union)
+ {
+ inside_value = -1; // outside
+ }
+ else // continue and blocked
+ {
+ inside_value = 0;
+ }
+ return true;
+ }
+
+ // if needed analyse points of a linestring
+ // NOTE: range_in_geometry checks points of a linestring
+ // until a point inside/outside areal is found
+ // TODO: Could be replaced with point_in_geometry() because found_front is false
+ inside_value = range_in_geometry(linestring, areal, strategy);
+
+ if ( (found_intersection && inside_value == -1) // going in from outside
+ || (found_continue && inside_value == -1) // going on boundary from outside
+ || (found_union && inside_value == 1) ) // going out from inside
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+#endif // BOOST_GEOMETRY_SETOPS_LA_OLD_BEHAVIOR
+
template
<
typename LineString, typename Areal,
@@ -336,14 +423,30 @@ struct intersection_of_linestring_with_areal
> follower;
typedef typename point_type<LineStringOut>::type point_type;
+#ifdef BOOST_GEOMETRY_SETOPS_LA_OLD_BEHAVIOR
typedef detail::overlay::traversal_turn_info
- <
- point_type,
- typename geometry::segment_ratio_type<point_type, RobustPolicy>::type
- > turn_info;
+ <
+ point_type,
+ typename geometry::segment_ratio_type<point_type, RobustPolicy>::type
+ > turn_info;
+#else
+ typedef detail::overlay::turn_info
+ <
+ point_type,
+ typename geometry::segment_ratio_type<point_type, RobustPolicy>::type,
+ detail::overlay::turn_operation_linear
+ <
+ point_type,
+ typename geometry::segment_ratio_type<point_type, RobustPolicy>::type
+ >
+ > turn_info;
+#endif
std::deque<turn_info> turns;
detail::get_turns::no_interrupt_policy policy;
+
+#ifdef BOOST_GEOMETRY_SETOPS_LA_OLD_BEHAVIOR
+
geometry::get_turns
<
false,
@@ -366,7 +469,7 @@ struct intersection_of_linestring_with_areal
// until a point inside/outside areal is found
inside_value = overlay::range_in_geometry(linestring, areal, strategy);
}
- // add point to the output if conditions are met
+ // add linestring to the output if conditions are met
if (inside_value != 0 && follower::included(inside_value))
{
LineStringOut copy;
@@ -376,6 +479,47 @@ struct intersection_of_linestring_with_areal
return out;
}
+#else // BOOST_GEOMETRY_SETOPS_LA_OLD_BEHAVIOR
+
+ typedef detail::overlay::get_turn_info_linear_areal
+ <
+ detail::overlay::assign_null_policy
+ > turn_policy;
+
+ dispatch::get_turns
+ <
+ typename geometry::tag<LineString>::type,
+ typename geometry::tag<Areal>::type,
+ LineString,
+ Areal,
+ false,
+ (OverlayType == overlay_intersection ? ReverseAreal : !ReverseAreal),
+ turn_policy
+ >::apply(0, linestring, 1, areal,
+ strategy, robust_policy,
+ turns, policy);
+
+ int inside_value = 0;
+ if (simple_turns_analysis(linestring, areal, strategy, turns, inside_value))
+ {
+ // No crossing the boundary, it is either
+ // inside (interior + borders)
+ // or outside (exterior + borders)
+ // or on boundary
+
+ // add linestring to the output if conditions are met
+ if (follower::included(inside_value))
+ {
+ LineStringOut copy;
+ geometry::convert(linestring, copy);
+ *out++ = copy;
+ }
+
+ return out;
+ }
+
+#endif // BOOST_GEOMETRY_SETOPS_LA_OLD_BEHAVIOR
+
#if defined(BOOST_GEOMETRY_DEBUG_FOLLOW)
int index = 0;
for(typename std::deque<turn_info>::const_iterator
@@ -395,6 +539,135 @@ struct intersection_of_linestring_with_areal
};
+template <typename Turns, typename OutputIterator>
+inline OutputIterator intersection_output_turn_points(Turns const& turns,
+ OutputIterator out)
+{
+ for (typename Turns::const_iterator
+ it = turns.begin(); it != turns.end(); ++it)
+ {
+ *out++ = it->point;
+ }
+
+ return out;
+}
+
+template <typename PointOut>
+struct intersection_areal_areal_point
+{
+ template
+ <
+ typename Geometry1, typename Geometry2,
+ typename RobustPolicy,
+ typename OutputIterator,
+ typename Strategy
+ >
+ static inline OutputIterator apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ RobustPolicy const& robust_policy,
+ OutputIterator out,
+ Strategy const& strategy)
+ {
+ typedef detail::overlay::turn_info
+ <
+ PointOut,
+ typename segment_ratio_type<PointOut, RobustPolicy>::type
+ > turn_info;
+ std::vector<turn_info> turns;
+
+ detail::get_turns::no_interrupt_policy policy;
+
+ geometry::get_turns
+ <
+ false, false, detail::overlay::assign_null_policy
+ >(geometry1, geometry2, strategy, robust_policy, turns, policy);
+
+ return intersection_output_turn_points(turns, out);
+ }
+};
+
+template <typename PointOut>
+struct intersection_linear_areal_point
+{
+ template
+ <
+ typename Geometry1, typename Geometry2,
+ typename RobustPolicy,
+ typename OutputIterator,
+ typename Strategy
+ >
+ static inline OutputIterator apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ RobustPolicy const& robust_policy,
+ OutputIterator out,
+ Strategy const& strategy)
+ {
+ typedef typename geometry::segment_ratio_type
+ <
+ PointOut, RobustPolicy
+ >::type segment_ratio_type;
+
+ typedef detail::overlay::turn_info
+ <
+ PointOut,
+ segment_ratio_type,
+ detail::overlay::turn_operation_linear
+ <
+ PointOut,
+ segment_ratio_type
+ >
+ > turn_info;
+
+ typedef detail::overlay::get_turn_info_linear_areal
+ <
+ detail::overlay::assign_null_policy
+ > turn_policy;
+
+ std::vector<turn_info> turns;
+
+ detail::get_turns::no_interrupt_policy interrupt_policy;
+
+ dispatch::get_turns
+ <
+ typename geometry::tag<Geometry1>::type,
+ typename geometry::tag<Geometry2>::type,
+ Geometry1,
+ Geometry2,
+ false,
+ false,
+ turn_policy
+ >::apply(0, geometry1, 1, geometry2,
+ strategy, robust_policy,
+ turns, interrupt_policy);
+
+ return intersection_output_turn_points(turns, out);
+ }
+};
+
+template <typename PointOut>
+struct intersection_areal_linear_point
+{
+ template
+ <
+ typename Geometry1, typename Geometry2,
+ typename RobustPolicy,
+ typename OutputIterator,
+ typename Strategy
+ >
+ static inline OutputIterator apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ RobustPolicy const& robust_policy,
+ OutputIterator out,
+ Strategy const& strategy)
+ {
+ return intersection_linear_areal_point
+ <
+ PointOut
+ >::apply(geometry2, geometry1, robust_policy, out, strategy);
+ }
+};
+
+
}} // namespace detail::intersection
#endif // DOXYGEN_NO_DETAIL
@@ -420,9 +693,9 @@ template
typename TagIn2 = typename geometry::tag<Geometry2>::type,
typename TagOut = typename geometry::tag<GeometryOut>::type,
// metafunction finetuning helpers:
- bool Areal1 = geometry::is_areal<Geometry1>::value,
- bool Areal2 = geometry::is_areal<Geometry2>::value,
- bool ArealOut = geometry::is_areal<GeometryOut>::value
+ typename CastedTagIn1 = typename geometry::tag_cast<TagIn1, areal_tag, linear_tag, pointlike_tag>::type,
+ typename CastedTagIn2 = typename geometry::tag_cast<TagIn2, areal_tag, linear_tag, pointlike_tag>::type,
+ typename CastedTagOut = typename geometry::tag_cast<TagOut, areal_tag, linear_tag, pointlike_tag>::type
>
struct intersection_insert
{
@@ -449,7 +722,7 @@ struct intersection_insert
OverlayType,
Reverse1, Reverse2, ReverseOut,
TagIn1, TagIn2, TagOut,
- true, true, true
+ areal_tag, areal_tag, areal_tag
> : detail::overlay::overlay
<Geometry1, Geometry2, Reverse1, Reverse2, ReverseOut, GeometryOut, OverlayType>
{};
@@ -471,7 +744,7 @@ struct intersection_insert
OverlayType,
Reverse1, Reverse2, ReverseOut,
TagIn, box_tag, TagOut,
- true, true, true
+ areal_tag, areal_tag, areal_tag
> : detail::overlay::overlay
<Geometry, Box, Reverse1, Reverse2, ReverseOut, GeometryOut, OverlayType>
{};
@@ -491,7 +764,7 @@ struct intersection_insert
OverlayType,
Reverse1, Reverse2, ReverseOut,
segment_tag, segment_tag, point_tag,
- false, false, false
+ linear_tag, linear_tag, pointlike_tag
> : detail::intersection::intersection_segment_segment_point<GeometryOut>
{};
@@ -510,7 +783,7 @@ struct intersection_insert
OverlayType,
Reverse1, Reverse2, ReverseOut,
linestring_tag, linestring_tag, point_tag,
- false, false, false
+ linear_tag, linear_tag, pointlike_tag
> : detail::intersection::intersection_linestring_linestring_point<GeometryOut>
{};
@@ -528,7 +801,7 @@ struct intersection_insert
overlay_intersection,
Reverse1, Reverse2, ReverseOut,
linestring_tag, box_tag, linestring_tag,
- false, true, false
+ linear_tag, areal_tag, linear_tag
>
{
template <typename RobustPolicy, typename OutputIterator, typename Strategy>
@@ -559,7 +832,7 @@ struct intersection_insert
OverlayType,
ReverseLinestring, ReversePolygon, ReverseOut,
linestring_tag, polygon_tag, linestring_tag,
- false, true, false
+ linear_tag, areal_tag, linear_tag
> : detail::intersection::intersection_of_linestring_with_areal
<
ReversePolygon,
@@ -583,7 +856,7 @@ struct intersection_insert
OverlayType,
ReverseLinestring, ReverseRing, ReverseOut,
linestring_tag, ring_tag, linestring_tag,
- false, true, false
+ linear_tag, areal_tag, linear_tag
> : detail::intersection::intersection_of_linestring_with_areal
<
ReverseRing,
@@ -606,7 +879,7 @@ struct intersection_insert
OverlayType,
Reverse1, Reverse2, ReverseOut,
segment_tag, box_tag, linestring_tag,
- false, true, false
+ linear_tag, areal_tag, linear_tag
>
{
template <typename RobustPolicy, typename OutputIterator, typename Strategy>
@@ -630,8 +903,7 @@ template
typename PointOut,
overlay_type OverlayType,
bool Reverse1, bool Reverse2, bool ReverseOut,
- typename Tag1, typename Tag2,
- bool Areal1, bool Areal2
+ typename Tag1, typename Tag2
>
struct intersection_insert
<
@@ -640,38 +912,59 @@ struct intersection_insert
OverlayType,
Reverse1, Reverse2, ReverseOut,
Tag1, Tag2, point_tag,
- Areal1, Areal2, false
+ areal_tag, areal_tag, pointlike_tag
>
-{
- template <typename RobustPolicy, typename OutputIterator, typename Strategy>
- static inline OutputIterator apply(Geometry1 const& geometry1,
- Geometry2 const& geometry2,
- RobustPolicy const& robust_policy,
- OutputIterator out, Strategy const& strategy)
- {
-
- typedef detail::overlay::turn_info
- <
- PointOut,
- typename segment_ratio_type<PointOut, RobustPolicy>::type
- > turn_info;
- std::vector<turn_info> turns;
-
- detail::get_turns::no_interrupt_policy policy;
- geometry::get_turns
- <
- false, false, detail::overlay::assign_null_policy
- >(geometry1, geometry2, strategy, robust_policy, turns, policy);
- for (typename std::vector<turn_info>::const_iterator it
- = turns.begin(); it != turns.end(); ++it)
- {
- *out++ = it->point;
- }
+ : public detail::intersection::intersection_areal_areal_point
+ <
+ PointOut
+ >
+{};
- return out;
- }
-};
+template
+<
+ typename Geometry1, typename Geometry2,
+ typename PointOut,
+ overlay_type OverlayType,
+ bool Reverse1, bool Reverse2, bool ReverseOut,
+ typename Tag1, typename Tag2
+>
+struct intersection_insert
+ <
+ Geometry1, Geometry2,
+ PointOut,
+ OverlayType,
+ Reverse1, Reverse2, ReverseOut,
+ Tag1, Tag2, point_tag,
+ linear_tag, areal_tag, pointlike_tag
+ >
+ : public detail::intersection::intersection_linear_areal_point
+ <
+ PointOut
+ >
+{};
+template
+<
+ typename Geometry1, typename Geometry2,
+ typename PointOut,
+ overlay_type OverlayType,
+ bool Reverse1, bool Reverse2, bool ReverseOut,
+ typename Tag1, typename Tag2
+>
+struct intersection_insert
+ <
+ Geometry1, Geometry2,
+ PointOut,
+ OverlayType,
+ Reverse1, Reverse2, ReverseOut,
+ Tag1, Tag2, point_tag,
+ areal_tag, linear_tag, pointlike_tag
+ >
+ : public detail::intersection::intersection_areal_linear_point
+ <
+ PointOut
+ >
+{};
template
<
@@ -713,7 +1006,7 @@ struct intersection_insert
overlay_intersection,
Reverse1, Reverse2, ReverseOut,
Tag1, Tag2, linestring_tag,
- true, true, false
+ areal_tag, areal_tag, linear_tag
>
{
template
@@ -739,47 +1032,20 @@ struct intersection_insert
}
};
-// dispatch for non-areal geometries
-template
-<
- typename Geometry1, typename Geometry2, typename GeometryOut,
- overlay_type OverlayType,
- bool Reverse1, bool Reverse2, bool ReverseOut,
- typename TagIn1, typename TagIn2
->
-struct intersection_insert
- <
- Geometry1, Geometry2, GeometryOut,
- OverlayType,
- Reverse1, Reverse2, ReverseOut,
- TagIn1, TagIn2, linestring_tag,
- false, false, false
- > : intersection_insert
- <
- Geometry1, Geometry2, GeometryOut,
- OverlayType,
- Reverse1, Reverse2, ReverseOut,
- typename tag_cast<TagIn1, pointlike_tag, linear_tag>::type,
- typename tag_cast<TagIn2, pointlike_tag, linear_tag>::type,
- linestring_tag,
- false, false, false
- >
-{};
-
-
// dispatch for difference/intersection of linear geometries
template
<
typename Linear1, typename Linear2, typename LineStringOut,
overlay_type OverlayType,
- bool Reverse1, bool Reverse2, bool ReverseOut
+ bool Reverse1, bool Reverse2, bool ReverseOut,
+ typename TagIn1, typename TagIn2
>
struct intersection_insert
<
Linear1, Linear2, LineStringOut, OverlayType,
Reverse1, Reverse2, ReverseOut,
- linear_tag, linear_tag, linestring_tag,
- false, false, false
+ TagIn1, TagIn2, linestring_tag,
+ linear_tag, linear_tag, linear_tag
> : detail::overlay::linear_linear_linestring
<
Linear1, Linear2, LineStringOut, OverlayType
@@ -800,7 +1066,7 @@ struct intersection_insert
Point1, Point2, PointOut, OverlayType,
Reverse1, Reverse2, ReverseOut,
point_tag, point_tag, point_tag,
- false, false, false
+ pointlike_tag, pointlike_tag, pointlike_tag
> : detail::overlay::point_point_point
<
Point1, Point2, PointOut, OverlayType
@@ -819,7 +1085,7 @@ struct intersection_insert
MultiPoint, Point, PointOut, OverlayType,
Reverse1, Reverse2, ReverseOut,
multi_point_tag, point_tag, point_tag,
- false, false, false
+ pointlike_tag, pointlike_tag, pointlike_tag
> : detail::overlay::multipoint_point_point
<
MultiPoint, Point, PointOut, OverlayType
@@ -838,7 +1104,7 @@ struct intersection_insert
Point, MultiPoint, PointOut, OverlayType,
Reverse1, Reverse2, ReverseOut,
point_tag, multi_point_tag, point_tag,
- false, false, false
+ pointlike_tag, pointlike_tag, pointlike_tag
> : detail::overlay::point_multipoint_point
<
Point, MultiPoint, PointOut, OverlayType
@@ -857,7 +1123,7 @@ struct intersection_insert
MultiPoint1, MultiPoint2, PointOut, OverlayType,
Reverse1, Reverse2, ReverseOut,
multi_point_tag, multi_point_tag, point_tag,
- false, false, false
+ pointlike_tag, pointlike_tag, pointlike_tag
> : detail::overlay::multipoint_multipoint_point
<
MultiPoint1, MultiPoint2, PointOut, OverlayType
@@ -878,7 +1144,7 @@ struct intersection_insert
Point, Linear, PointOut, OverlayType,
Reverse1, Reverse2, ReverseOut,
point_tag, Tag, point_tag,
- false, false, false
+ pointlike_tag, linear_tag, pointlike_tag
> : detail_dispatch::overlay::pointlike_linear_point
<
Point, Linear, PointOut, OverlayType,
@@ -899,7 +1165,7 @@ struct intersection_insert
MultiPoint, Linear, PointOut, OverlayType,
Reverse1, Reverse2, ReverseOut,
multi_point_tag, Tag, point_tag,
- false, false, false
+ pointlike_tag, linear_tag, pointlike_tag
> : detail_dispatch::overlay::pointlike_linear_point
<
MultiPoint, Linear, PointOut, OverlayType,
@@ -919,7 +1185,7 @@ struct intersection_insert
Linestring, MultiPoint, PointOut, overlay_intersection,
Reverse1, Reverse2, ReverseOut,
linestring_tag, multi_point_tag, point_tag,
- false, false, false
+ linear_tag, pointlike_tag, pointlike_tag
>
{
template <typename RobustPolicy, typename OutputIterator, typename Strategy>
diff --git a/boost/geometry/algorithms/detail/overlay/is_self_turn.hpp b/boost/geometry/algorithms/detail/overlay/is_self_turn.hpp
index 9cb7a0fca9..9423a24b33 100644
--- a/boost/geometry/algorithms/detail/overlay/is_self_turn.hpp
+++ b/boost/geometry/algorithms/detail/overlay/is_self_turn.hpp
@@ -41,7 +41,7 @@ struct is_self_turn_check<overlay_buffer>
};
template <>
-struct is_self_turn_check<overlay_dissolve>
+struct is_self_turn_check<overlay_dissolve_union>
{
template <typename Turn>
static inline bool apply(Turn const& turn)
@@ -50,6 +50,15 @@ struct is_self_turn_check<overlay_dissolve>
}
};
+template <>
+struct is_self_turn_check<overlay_dissolve_intersection>
+{
+ template <typename Turn>
+ static inline bool apply(Turn const& turn)
+ {
+ return false;
+ }
+};
template <overlay_type OverlayType, typename Turn>
bool is_self_turn(Turn const& turn)
diff --git a/boost/geometry/algorithms/detail/overlay/needs_self_turns.hpp b/boost/geometry/algorithms/detail/overlay/needs_self_turns.hpp
new file mode 100644
index 0000000000..87fdd00d58
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/needs_self_turns.hpp
@@ -0,0 +1,83 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2017-2017 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_NEEDS_SELF_TURNS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_NEEDS_SELF_TURNS_HPP
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/algorithms/num_interior_rings.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+template
+<
+ typename Geometry,
+ typename Tag = typename tag<Geometry>::type
+>
+struct needs_self_turns
+{
+};
+
+template <typename Geometry>
+struct needs_self_turns<Geometry, box_tag>
+{
+ static inline bool apply(Geometry const&)
+ {
+ return false;
+ }
+};
+
+template <typename Geometry>
+struct needs_self_turns<Geometry, ring_tag>
+{
+ static inline bool apply(Geometry const&)
+ {
+ return false;
+ }
+};
+
+template <typename Geometry>
+struct needs_self_turns<Geometry, polygon_tag>
+{
+ static inline bool apply(Geometry const& polygon)
+ {
+ return geometry::num_interior_rings(polygon) > 0;
+ }
+};
+
+template <typename Geometry>
+struct needs_self_turns<Geometry, multi_polygon_tag>
+{
+ static inline bool apply(Geometry const& multi)
+ {
+ typedef typename boost::range_value<Geometry>::type polygon_type;
+ std::size_t const n = boost::size(multi);
+ return n > 1 || (n == 1
+ && needs_self_turns<polygon_type>
+ ::apply(*boost::begin(multi)));
+ }
+};
+
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_NEEDS_SELF_TURNS_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/overlay.hpp b/boost/geometry/algorithms/detail/overlay/overlay.hpp
index 10829abd4f..f24cde8b8f 100644
--- a/boost/geometry/algorithms/detail/overlay/overlay.hpp
+++ b/boost/geometry/algorithms/detail/overlay/overlay.hpp
@@ -29,6 +29,7 @@
#include <boost/geometry/algorithms/detail/overlay/enrichment_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
#include <boost/geometry/algorithms/detail/overlay/is_self_turn.hpp>
+#include <boost/geometry/algorithms/detail/overlay/needs_self_turns.hpp>
#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
#include <boost/geometry/algorithms/detail/overlay/traverse.hpp>
#include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp>
@@ -99,89 +100,88 @@ template
inline void get_ring_turn_info(TurnInfoMap& turn_info_map, Turns const& turns, Clusters const& clusters)
{
typedef typename boost::range_value<Turns>::type turn_type;
+ typedef typename turn_type::turn_operation_type turn_operation_type;
typedef typename turn_type::container_type container_type;
static const operation_type target_operation
= operation_from_overlay<OverlayType>::value;
static const operation_type opposite_operation
- = target_operation == operation_union ? operation_intersection : operation_union;
+ = target_operation == operation_union
+ ? operation_intersection
+ : operation_union;
- signed_size_type turn_index = 0;
for (typename boost::range_iterator<Turns const>::type
it = boost::begin(turns);
it != boost::end(turns);
- ++it, turn_index++)
+ ++it)
{
- typename boost::range_value<Turns>::type const& turn = *it;
-
- bool const colocated_target = target_operation == operation_union
- ? turn.colocated_uu : turn.colocated_ii;
- bool const colocated_opp = target_operation == operation_union
- ? turn.colocated_ii : turn.colocated_uu;
- bool const both_opposite = turn.both(opposite_operation);
-
- bool const traversed
- = turn.operations[0].visited.finalized()
- || turn.operations[0].visited.rejected()
- || turn.operations[1].visited.finalized()
- || turn.operations[1].visited.rejected()
- || turn.both(operation_blocked)
- || turn.combination(opposite_operation, operation_blocked);
-
- bool is_closed = false;
- if (turn.cluster_id >= 0 && target_operation == operation_union)
- {
- typename Clusters::const_iterator mit = clusters.find(turn.cluster_id);
- BOOST_ASSERT(mit != clusters.end());
+ turn_type const& turn = *it;
- cluster_info const& cinfo = mit->second;
- is_closed = cinfo.open_count == 0;
- }
+ bool cluster_checked = false;
+ bool has_blocked = false;
for (typename boost::range_iterator<container_type const>::type
op_it = boost::begin(turn.operations);
op_it != boost::end(turn.operations);
++op_it)
{
+ turn_operation_type const& op = *op_it;
ring_identifier const ring_id
(
- op_it->seg_id.source_index,
- op_it->seg_id.multi_index,
- op_it->seg_id.ring_index
+ op.seg_id.source_index,
+ op.seg_id.multi_index,
+ op.seg_id.ring_index
);
- if (traversed || is_closed || ! op_it->enriched.startable)
+ if (! is_self_turn<OverlayType>(turn)
+ && (
+ (target_operation == operation_union
+ && op.enriched.count_left > 0)
+ || (target_operation == operation_intersection
+ && op.enriched.count_right <= 2)))
{
- turn_info_map[ring_id].has_traversed_turn = true;
+ // Avoid including untraversed rings which have polygons on
+ // their left side (union) or not two on their right side (int)
+ // This can only be done for non-self-turns because of count
+ // information
+ turn_info_map[ring_id].has_blocked_turn = true;
+ continue;
}
- else if (both_opposite && colocated_target)
- {
- // For union: ii, colocated with a uu
- // For example, two interior rings touch where two exterior rings also touch.
- // The interior rings are not yet traversed, and should be taken from the input
-
- // For intersection: uu, colocated with an ii
- // unless it is two interior inner rings colocated with a uu
- // So don't set has_traversed_turn here
+ if (turn.any_blocked())
+ {
+ turn_info_map[ring_id].has_blocked_turn = true;
+ }
+ if (turn_info_map[ring_id].has_traversed_turn
+ || turn_info_map[ring_id].has_blocked_turn)
+ {
+ continue;
}
- else if (both_opposite && ! is_self_turn<OverlayType>(turn))
+
+ // Check information in colocated turns
+ if (! cluster_checked && turn.is_clustered())
{
- // For union, mark any ring with a ii turn as traversed
- // For intersection, any uu - but not if it is a self-turn
- turn_info_map[ring_id].has_traversed_turn = true;
+ check_colocation(has_blocked, turn.cluster_id, turns, clusters);
+ cluster_checked = true;
}
- else if (colocated_opp && ! colocated_target)
+
+ // Block rings where any other turn is blocked,
+ // and (with exceptions): i for union and u for intersection
+ // Exceptions: don't block self-uu for intersection
+ // don't block self-ii for union
+ // don't block (for union) i/u if there is an self-ii too
+ if (has_blocked
+ || (op.operation == opposite_operation
+ && ! turn.has_colocated_both
+ && ! (turn.both(opposite_operation)
+ && is_self_turn<OverlayType>(turn))))
{
- // For union, a turn colocated with ii and NOT with uu/ux
- // For intersection v.v.
- turn_info_map[ring_id].has_traversed_turn = true;
+ turn_info_map[ring_id].has_blocked_turn = true;
}
}
}
}
-
template
<
typename GeometryOut, overlay_type OverlayType, bool ReverseOut,
@@ -234,7 +234,8 @@ inline OutputIterator return_if_one_input_is_empty(Geometry1 const& geometry1,
select_rings<OverlayType>(geometry1, geometry2, empty, all_of_one_of_them, strategy);
ring_container_type rings;
assign_parents(geometry1, geometry2, rings, all_of_one_of_them, strategy);
- return add_rings<GeometryOut>(all_of_one_of_them, geometry1, geometry2, rings, out);
+ return add_rings<GeometryOut>(all_of_one_of_them, geometry1, geometry2, rings, out,
+ strategy.template get_area_strategy<point_type1>());
}
@@ -306,9 +307,13 @@ std::cout << "get turns" << std::endl;
visitor.visit_turns(1, turns);
#ifdef BOOST_GEOMETRY_INCLUDE_SELF_TURNS
+ if (needs_self_turns<Geometry1>::apply(geometry1))
{
self_get_turn_points::self_turns<Reverse1, assign_null_policy>(geometry1,
strategy, robust_policy, turns, policy, 0);
+ }
+ if (needs_self_turns<Geometry2>::apply(geometry2))
+ {
self_get_turn_points::self_turns<Reverse2, assign_null_policy>(geometry2,
strategy, robust_policy, turns, policy, 1);
}
@@ -320,6 +325,7 @@ std::cout << "enrich" << std::endl;
#endif
typename Strategy::side_strategy_type side_strategy = strategy.get_side_strategy();
cluster_type clusters;
+ std::map<ring_identifier, ring_turn_info> turn_info_per_ring;
geometry::enrich_intersection_points<Reverse1, Reverse2, OverlayType>(turns,
clusters, geometry1, geometry2,
@@ -343,11 +349,12 @@ std::cout << "traverse" << std::endl;
strategy,
robust_policy,
turns, rings,
+ turn_info_per_ring,
clusters,
visitor
);
+ visitor.visit_turns(3, turns);
- std::map<ring_identifier, ring_turn_info> turn_info_per_ring;
get_ring_turn_info<OverlayType>(turn_info_per_ring, turns, clusters);
typedef typename Strategy::template area_strategy<point_type>::type area_strategy_type;
@@ -364,9 +371,8 @@ std::cout << "traverse" << std::endl;
selected_ring_properties, strategy);
// Add rings created during traversal
+ area_strategy_type const area_strategy = strategy.template get_area_strategy<point_type>();
{
- area_strategy_type const area_strategy = strategy.template get_area_strategy<point_type>();
-
ring_identifier id(2, 0, -1);
for (typename boost::range_iterator<ring_container_type>::type
it = boost::begin(rings);
@@ -381,7 +387,24 @@ std::cout << "traverse" << std::endl;
assign_parents(geometry1, geometry2, rings, selected_ring_properties, strategy);
- return add_rings<GeometryOut>(selected_ring_properties, geometry1, geometry2, rings, out);
+ // NOTE: There is no need to check result area for union because
+ // as long as the polygons in the input are valid the resulting
+ // polygons should be valid as well.
+ // By default the area is checked (this is old behavior) however this
+ // can be changed with #define. This may be important in non-cartesian CSes.
+ // The result may be too big, so the area is negative. In this case either
+ // it can be returned or an exception can be thrown.
+ return add_rings<GeometryOut>(selected_ring_properties, geometry1, geometry2, rings, out,
+ area_strategy,
+ OverlayType == overlay_union ?
+#if defined(BOOST_GEOMETRY_UNION_THROW_INVALID_OUTPUT_EXCEPTION)
+ add_rings_throw_if_reversed
+#elif defined(BOOST_GEOMETRY_UNION_RETURN_INVALID)
+ add_rings_add_unordered
+#else
+ add_rings_ignore_unordered
+#endif
+ : add_rings_ignore_unordered);
}
template <typename RobustPolicy, typename OutputIterator, typename Strategy>
diff --git a/boost/geometry/algorithms/detail/overlay/overlay_type.hpp b/boost/geometry/algorithms/detail/overlay/overlay_type.hpp
index 0f60840973..f3ec9eaa64 100644
--- a/boost/geometry/algorithms/detail/overlay/overlay_type.hpp
+++ b/boost/geometry/algorithms/detail/overlay/overlay_type.hpp
@@ -21,7 +21,8 @@ enum overlay_type
overlay_intersection,
overlay_difference,
overlay_buffer,
- overlay_dissolve
+ overlay_dissolve_union,
+ overlay_dissolve_intersection
};
#ifndef DOXYGEN_NO_DETAIL
@@ -42,6 +43,17 @@ enum operation_type
template <overlay_type OverlayType>
struct operation_from_overlay
{
+};
+
+template <>
+struct operation_from_overlay<overlay_union>
+{
+ static const operation_type value = operation_union;
+};
+
+template <>
+struct operation_from_overlay<overlay_buffer>
+{
static const operation_type value = operation_union;
};
@@ -57,6 +69,19 @@ struct operation_from_overlay<overlay_difference>
static const operation_type value = operation_intersection;
};
+template <>
+struct operation_from_overlay<overlay_dissolve_union>
+{
+ static const operation_type value = operation_union;
+};
+
+template <>
+struct operation_from_overlay<overlay_dissolve_intersection>
+{
+ static const operation_type value = operation_intersection;
+};
+
+
}} // namespace detail::overlay
#endif //DOXYGEN_NO_DETAIL
diff --git a/boost/geometry/algorithms/detail/overlay/pointlike_linear.hpp b/boost/geometry/algorithms/detail/overlay/pointlike_linear.hpp
index 0a7c3bc469..6f8fdd32b8 100644
--- a/boost/geometry/algorithms/detail/overlay/pointlike_linear.hpp
+++ b/boost/geometry/algorithms/detail/overlay/pointlike_linear.hpp
@@ -32,7 +32,6 @@
#include <boost/geometry/algorithms/detail/not.hpp>
#include <boost/geometry/algorithms/detail/partition.hpp>
-#include <boost/geometry/algorithms/detail/relate/less.hpp>
#include <boost/geometry/algorithms/detail/disjoint/point_geometry.hpp>
#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
diff --git a/boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp b/boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp
index 438a377876..88aedecf86 100644
--- a/boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp
+++ b/boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp
@@ -1,12 +1,13 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2014-2015, Oracle and/or its affiliates.
+// Copyright (c) 2014-2017, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
-// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
-
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_POINTLIKE_POINTLIKE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_POINTLIKE_POINTLIKE_HPP
@@ -24,10 +25,11 @@
#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/algorithms/not_implemented.hpp>
-#include <boost/geometry/algorithms/detail/relate/less.hpp>
#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
+#include <boost/geometry/policies/compare.hpp>
+
namespace boost { namespace geometry
{
@@ -264,17 +266,20 @@ struct multipoint_multipoint_point
>::apply(multipoint2, multipoint1, robust_policy, oit, strategy);
}
- std::vector<typename boost::range_value<MultiPoint2>::type>
- points2(boost::begin(multipoint2), boost::end(multipoint2));
+ typedef typename boost::range_value<MultiPoint2>::type point2_type;
+
+ std::vector<point2_type> points2(boost::begin(multipoint2),
+ boost::end(multipoint2));
- std::sort(points2.begin(), points2.end(), detail::relate::less());
+ geometry::less<> const less = geometry::less<>();
+ std::sort(points2.begin(), points2.end(), less);
for (typename boost::range_iterator<MultiPoint1 const>::type
it1 = boost::begin(multipoint1);
it1 != boost::end(multipoint1); ++it1)
{
bool found = std::binary_search(points2.begin(), points2.end(),
- *it1, detail::relate::less());
+ *it1, less);
action_selector_pl_pl
<
diff --git a/boost/geometry/algorithms/detail/overlay/segment_identifier.hpp b/boost/geometry/algorithms/detail/overlay/segment_identifier.hpp
index 5447c8813e..14e84c9496 100644
--- a/boost/geometry/algorithms/detail/overlay/segment_identifier.hpp
+++ b/boost/geometry/algorithms/detail/overlay/segment_identifier.hpp
@@ -57,6 +57,7 @@ struct segment_identifier
return source_index != other.source_index ? source_index < other.source_index
: multi_index !=other.multi_index ? multi_index < other.multi_index
: ring_index != other.ring_index ? ring_index < other.ring_index
+ : piece_index != other.piece_index ? piece_index < other.piece_index
: segment_index < other.segment_index
;
}
@@ -66,6 +67,7 @@ struct segment_identifier
return source_index == other.source_index
&& segment_index == other.segment_index
&& ring_index == other.ring_index
+ && piece_index == other.piece_index
&& multi_index == other.multi_index
;
}
@@ -79,6 +81,7 @@ struct segment_identifier
;
if (seg_id.ring_index >= 0) os << ", r:" << seg_id.ring_index;
if (seg_id.multi_index >= 0) os << ", m:" << seg_id.multi_index;
+ if (seg_id.piece_index >= 0) os << ", p:" << seg_id.piece_index;
return os;
}
#endif
diff --git a/boost/geometry/algorithms/detail/overlay/select_rings.hpp b/boost/geometry/algorithms/detail/overlay/select_rings.hpp
index 67a4f4bb75..262ba748ab 100644
--- a/boost/geometry/algorithms/detail/overlay/select_rings.hpp
+++ b/boost/geometry/algorithms/detail/overlay/select_rings.hpp
@@ -41,10 +41,12 @@ namespace detail { namespace overlay
struct ring_turn_info
{
bool has_traversed_turn;
+ bool has_blocked_turn;
bool within_other;
ring_turn_info()
: has_traversed_turn(false)
+ , has_blocked_turn(false)
, within_other(false)
{}
};
@@ -265,9 +267,9 @@ inline void update_ring_selection(Geometry1 const& geometry1,
info = tcit->second; // Copy by value
}
- if (info.has_traversed_turn)
+ if (info.has_traversed_turn || info.has_blocked_turn)
{
- // This turn is traversed (or blocked),
+ // This turn is traversed or blocked,
// don't include the original ring
continue;
}
diff --git a/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp b/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp
index 5e9d8efa8e..a00606b087 100644
--- a/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp
+++ b/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp
@@ -78,19 +78,22 @@ struct self_section_visitor
Turns& m_turns;
InterruptPolicy& m_interrupt_policy;
std::size_t m_source_index;
+ bool m_skip_adjacent;
inline self_section_visitor(Geometry const& g,
IntersectionStrategy const& is,
RobustPolicy const& rp,
Turns& turns,
InterruptPolicy& ip,
- std::size_t source_index)
+ std::size_t source_index,
+ bool skip_adjacent)
: m_geometry(g)
, m_intersection_strategy(is)
, m_rescale_policy(rp)
, m_turns(turns)
, m_interrupt_policy(ip)
, m_source_index(source_index)
+ , m_skip_adjacent(skip_adjacent)
{}
template <typename Section>
@@ -109,7 +112,7 @@ struct self_section_visitor
TurnPolicy
>::apply(m_source_index, m_geometry, sec1,
m_source_index, m_geometry, sec2,
- false,
+ false, m_skip_adjacent,
m_intersection_strategy,
m_rescale_policy,
m_turns, m_interrupt_policy);
@@ -132,7 +135,7 @@ struct get_turns
RobustPolicy const& robust_policy,
Turns& turns,
InterruptPolicy& interrupt_policy,
- std::size_t source_index)
+ std::size_t source_index, bool skip_adjacent)
{
typedef model::box
<
@@ -143,9 +146,11 @@ struct get_turns
>::type
> box_type;
- typedef geometry::sections<box_type, 1> sections_type;
+ // sectionalize in two dimensions to detect
+ // all potential spikes correctly
+ typedef geometry::sections<box_type, 2> sections_type;
- typedef boost::mpl::vector_c<std::size_t, 0> dimensions;
+ typedef boost::mpl::vector_c<std::size_t, 0, 1> dimensions;
sections_type sec;
geometry::sectionalize<Reverse, dimensions>(geometry, robust_policy, sec,
@@ -155,7 +160,7 @@ struct get_turns
<
Reverse, Geometry,
Turns, TurnPolicy, IntersectionStrategy, RobustPolicy, InterruptPolicy
- > visitor(geometry, intersection_strategy, robust_policy, turns, interrupt_policy, source_index);
+ > visitor(geometry, intersection_strategy, robust_policy, turns, interrupt_policy, source_index, skip_adjacent);
// false if interrupted
geometry::partition
@@ -224,7 +229,8 @@ struct self_get_turn_points
RobustPolicy const& ,
Turns& ,
InterruptPolicy& ,
- std::size_t)
+ std::size_t /*source_index*/,
+ bool /*skip_adjacent*/)
{
return true;
}
@@ -286,7 +292,8 @@ inline void self_turns(Geometry const& geometry,
RobustPolicy const& robust_policy,
Turns& turns,
InterruptPolicy& interrupt_policy,
- std::size_t source_index = 0)
+ std::size_t source_index = 0,
+ bool skip_adjacent = false)
{
concepts::check<Geometry const>();
@@ -298,7 +305,8 @@ inline void self_turns(Geometry const& geometry,
typename tag<Geometry>::type,
Geometry,
turn_policy
- >::apply(geometry, strategy, robust_policy, turns, interrupt_policy, source_index);
+ >::apply(geometry, strategy, robust_policy, turns, interrupt_policy,
+ source_index, skip_adjacent);
}
}} // namespace detail::self_get_turn_points
@@ -331,7 +339,8 @@ inline void self_turns(Geometry const& geometry,
RobustPolicy const& robust_policy,
Turns& turns,
InterruptPolicy& interrupt_policy,
- std::size_t source_index = 0)
+ std::size_t source_index = 0,
+ bool skip_adjacent = false)
{
concepts::check<Geometry const>();
@@ -344,7 +353,8 @@ inline void self_turns(Geometry const& geometry,
<
reverse,
AssignPolicy
- >(geometry, strategy, robust_policy, turns, interrupt_policy, source_index);
+ >(geometry, strategy, robust_policy, turns, interrupt_policy,
+ source_index, skip_adjacent);
}
diff --git a/boost/geometry/algorithms/detail/overlay/sort_by_side.hpp b/boost/geometry/algorithms/detail/overlay/sort_by_side.hpp
index 5ad2e41b12..fea5698ae1 100644
--- a/boost/geometry/algorithms/detail/overlay/sort_by_side.hpp
+++ b/boost/geometry/algorithms/detail/overlay/sort_by_side.hpp
@@ -91,13 +91,20 @@ struct less_by_index
template <typename T>
inline bool operator()(const T& first, const T& second) const
{
+ // Length might be considered too
// First order by from/to
if (first.direction != second.direction)
{
return first.direction < second.direction;
}
- // All the same, order by turn index (we might consider length too)
- return first.turn_index < second.turn_index;
+ // Then by turn index
+ if (first.turn_index != second.turn_index)
+ {
+ return first.turn_index < second.turn_index;
+ }
+ // This can also be the same (for example in buffer), but seg_id is
+ // never the same
+ return first.seg_id < second.seg_id;
}
};
diff --git a/boost/geometry/algorithms/detail/overlay/traversal.hpp b/boost/geometry/algorithms/detail/overlay/traversal.hpp
index 69d62b788b..6a9b1def99 100644
--- a/boost/geometry/algorithms/detail/overlay/traversal.hpp
+++ b/boost/geometry/algorithms/detail/overlay/traversal.hpp
@@ -131,7 +131,8 @@ struct traversal
{
}
- inline void finalize_visit_info()
+ template <typename TurnInfoMap>
+ inline void finalize_visit_info(TurnInfoMap& turn_info_map)
{
for (typename boost::range_iterator<Turns>::type
it = boost::begin(m_turns);
@@ -142,6 +143,32 @@ struct traversal
for (int i = 0; i < 2; i++)
{
turn_operation_type& op = turn.operations[i];
+ if (op.visited.visited()
+ || op.visited.started()
+ || op.visited.finished() )
+ {
+ ring_identifier const ring_id
+ (
+ op.seg_id.source_index,
+ op.seg_id.multi_index,
+ op.seg_id.ring_index
+ );
+ turn_info_map[ring_id].has_traversed_turn = true;
+
+ if (op.operation == operation_continue)
+ {
+ // Continue operations should mark the other operation
+ // as traversed too
+ turn_operation_type& other_op = turn.operations[1 - i];
+ ring_identifier const other_ring_id
+ (
+ other_op.seg_id.source_index,
+ other_op.seg_id.multi_index,
+ other_op.seg_id.ring_index
+ );
+ turn_info_map[other_ring_id].has_traversed_turn = true;
+ }
+ }
op.visited.finalize();
}
}
@@ -192,7 +219,7 @@ struct traversal
{
op.visited.set_visited();
}
- if (turn.cluster_id >= 0)
+ if (turn.is_clustered())
{
set_visited_in_cluster(turn.cluster_id, op.enriched.rank);
}
@@ -204,6 +231,16 @@ struct traversal
return op.visited.visited();
}
+ template <signed_size_type segment_identifier::*Member>
+ inline bool select_source_generic(bool switch_source,
+ segment_identifier const& current,
+ segment_identifier const& previous) const
+ {
+ return switch_source
+ ? current.*Member != previous.*Member
+ : current.*Member == previous.*Member;
+ }
+
inline bool select_source(signed_size_type turn_index,
segment_identifier const& candidate_seg_id,
segment_identifier const& previous_seg_id) const
@@ -211,22 +248,6 @@ struct traversal
// For uu/ii, only switch sources if indicated
turn_type const& turn = m_turns[turn_index];
- if (OverlayType == overlay_buffer)
- {
- // Buffer does not use source_index (always 0)
- return turn.switch_source
- ? candidate_seg_id.multi_index != previous_seg_id.multi_index
- : candidate_seg_id.multi_index == previous_seg_id.multi_index;
- }
-
- if (is_self_turn<OverlayType>(turn))
- {
- // Also, if it is a self-turn, stay on same ring (multi/ring)
- return turn.switch_source
- ? candidate_seg_id.multi_index != previous_seg_id.multi_index
- : candidate_seg_id.multi_index == previous_seg_id.multi_index;
- }
-
#if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR)
if (turn.switch_source)
{
@@ -237,9 +258,24 @@ struct traversal
std::cout << "DON'T SWITCH SOURCES at " << turn_index << std::endl;
}
#endif
- return turn.switch_source
- ? candidate_seg_id.source_index != previous_seg_id.source_index
- : candidate_seg_id.source_index == previous_seg_id.source_index;
+ if (OverlayType == overlay_buffer
+ || OverlayType == overlay_dissolve_union)
+ {
+ // Buffer does not use source_index (always 0).
+ return select_source_generic<&segment_identifier::multi_index>(
+ turn.switch_source, candidate_seg_id, previous_seg_id);
+ }
+
+ if (is_self_turn<OverlayType>(turn))
+ {
+ // Also, if it is a self-turn, stay on same ring (multi/ring)
+ return select_source_generic<&segment_identifier::multi_index>(
+ turn.switch_source, candidate_seg_id, previous_seg_id);
+ }
+
+ // Use source_index
+ return select_source_generic<&segment_identifier::source_index>(
+ turn.switch_source, candidate_seg_id, previous_seg_id);
}
inline bool traverse_possible(signed_size_type turn_index) const
@@ -253,7 +289,7 @@ struct traversal
// It is not a dead end if there is an operation to continue, or of
// there is a cluster (assuming for now we can get out of the cluster)
- return turn.cluster_id >= 0
+ return turn.is_clustered()
|| turn.has(target_operation)
|| turn.has(operation_continue);
}
@@ -318,6 +354,7 @@ struct traversal
if (op.operation == target_operation
&& ! op.visited.finished()
+ && ! op.visited.visited()
&& (! result || select_source(turn_index, op.seg_id, previous_seg_id)))
{
selected_op_index = i;
@@ -380,13 +417,51 @@ struct traversal
return true;
}
+ inline int select_turn_in_cluster_union(std::size_t selected_rank,
+ typename sbs_type::rp const& ranked_point,
+ signed_size_type start_turn_index, int start_op_index) const
+ {
+ // Returns 0 if it not OK
+ // Returns 1 if it OK
+ // Returns 2 if it OK and start turn matches
+ // Returns 3 if it OK and start turn and start op both match
+ if (ranked_point.rank != selected_rank
+ || ranked_point.direction != sort_by_side::dir_to)
+ {
+ return 0;
+ }
+
+ turn_type const& turn = m_turns[ranked_point.turn_index];
+ turn_operation_type const& op = turn.operations[ranked_point.operation_index];
+
+ // Check finalized: TODO: this should be finetuned, it is not necessary
+ if (op.visited.finalized())
+ {
+ return 0;
+ }
+
+ if (OverlayType != overlay_dissolve_union
+ && (op.enriched.count_left != 0 || op.enriched.count_right == 0))
+ {
+ // Check counts: in some cases interior rings might be generated with
+ // polygons on both sides. For dissolve it can be anything.
+ return 0;
+ }
+
+ return ranked_point.turn_index == start_turn_index
+ && ranked_point.operation_index == start_op_index ? 3
+ : ranked_point.turn_index == start_turn_index ? 2
+ : 1
+ ;
+ }
+
inline bool select_from_cluster_union(signed_size_type& turn_index,
- int& op_index, sbs_type& sbs) const
+ int& op_index, sbs_type& sbs,
+ signed_size_type start_turn_index, int start_op_index) const
{
std::vector<sort_by_side::rank_with_rings> aggregation;
sort_by_side::aggregate_operations(sbs, aggregation, m_turns, operation_union);
-
sort_by_side::rank_with_rings const& incoming = aggregation.front();
// Take the first one outgoing for the incoming region
@@ -402,62 +477,32 @@ struct traversal
}
}
+ int best_code = 0;
+ bool result = false;
for (std::size_t i = 1; i < sbs.m_ranked_points.size(); i++)
{
typename sbs_type::rp const& ranked_point = sbs.m_ranked_points[i];
- if (ranked_point.rank == selected_rank
- && ranked_point.direction == sort_by_side::dir_to)
- {
- turn_index = ranked_point.turn_index;
- op_index = ranked_point.operation_index;
-
- turn_type const& turn = m_turns[turn_index];
- turn_operation_type const& op = turn.operations[op_index];
-
- if (op.enriched.count_left == 0
- && op.enriched.count_right > 0
- && ! op.visited.finalized())
- {
- // In some cases interior rings might be generated with polygons
- // on both sides
-
- // TODO: this should be finetuned such that checking
- // finalized is not necessary
- return true;
- }
- }
- }
- return false;
- }
-
- inline bool all_operations_of_type(sort_by_side::rank_with_rings const& rwr,
- operation_type op_type,
- sort_by_side::direction_type dir) const
- {
- typedef std::set<sort_by_side::ring_with_direction>::const_iterator sit_type;
- for (sit_type it = rwr.rings.begin(); it != rwr.rings.end(); ++it)
- {
- sort_by_side::ring_with_direction const& rwd = *it;
- if (rwd.direction != dir)
+ if (ranked_point.rank > selected_rank)
{
- return false;
- }
- turn_type const& turn = m_turns[rwd.turn_index];
- if (! turn.both(op_type))
- {
- return false;
+ // Sorted on rank, so it makes no sense to continue
+ break;
}
- // Check if this is not yet taken
- turn_operation_type const& op = turn.operations[rwd.operation_index];
- if (op.visited.finalized())
+ int const code
+ = select_turn_in_cluster_union(selected_rank, ranked_point,
+ start_turn_index, start_op_index);
+
+ if (code > best_code)
{
- return false;
+ // It is 1 or higher and matching better than previous
+ best_code = code;
+ turn_index = ranked_point.turn_index;
+ op_index = ranked_point.operation_index;
+ result = true;
}
-
}
- return true;
+ return result;
}
inline bool analyze_cluster_intersection(signed_size_type& turn_index,
@@ -475,12 +520,14 @@ struct traversal
|| intersection_pattern_common_interior2(selected_rank, aggregation)
|| intersection_pattern_common_interior3(selected_rank, aggregation)
|| intersection_pattern_common_interior4(selected_rank, aggregation)
+ || intersection_pattern_common_interior5(selected_rank, aggregation)
+ || intersection_pattern_common_interior6(selected_rank, aggregation)
;
if (! detected)
{
- int incoming_region_id = 0;
- std::set<int> outgoing_region_ids;
+ signed_size_type incoming_region_id = 0;
+ std::set<signed_size_type> outgoing_region_ids;
for (std::size_t i = 0; i < aggregation.size(); i++)
{
@@ -530,7 +577,7 @@ struct traversal
{
for (int i = 0; i < 2; i++)
{
- int const region_id = turn.operations[i].enriched.region_id;
+ signed_size_type const region_id = turn.operations[i].enriched.region_id;
if (outgoing_region_ids.count(region_id) == 1)
{
selected_rank = 0;
@@ -545,6 +592,9 @@ struct traversal
if (selected_rank > 0)
{
+ typename turn_operation_type::comparable_distance_type
+ min_remaining_distance = 0;
+
std::size_t selected_index = sbs.m_ranked_points.size();
for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++)
{
@@ -562,8 +612,13 @@ struct traversal
continue;
}
- // Take the last turn from this rank
- selected_index = i;
+ // Take turn with the smallest remaining distance
+ if (selected_index == sbs.m_ranked_points.size()
+ || ranked_op.remaining_distance < min_remaining_distance)
+ {
+ selected_index = i;
+ min_remaining_distance = ranked_op.remaining_distance;
+ }
}
}
@@ -581,13 +636,13 @@ struct traversal
inline bool select_turn_from_cluster(signed_size_type& turn_index,
int& op_index,
- signed_size_type start_turn_index,
+ signed_size_type start_turn_index, int start_op_index,
segment_identifier const& previous_seg_id) const
{
bool const is_union = target_operation == operation_union;
turn_type const& turn = m_turns[turn_index];
- BOOST_ASSERT(turn.cluster_id >= 0);
+ BOOST_ASSERT(turn.is_clustered());
typename Clusters::const_iterator mit = m_clusters.find(turn.cluster_id);
BOOST_ASSERT(mit != m_clusters.end());
@@ -628,7 +683,8 @@ struct traversal
if (is_union)
{
- result = select_from_cluster_union(turn_index, op_index, sbs);
+ result = select_from_cluster_union(turn_index, op_index, sbs,
+ start_turn_index, start_op_index);
}
else
{
@@ -669,11 +725,15 @@ struct traversal
turn_operation_type const& start_op,
int start_op_index) const
{
- if (OverlayType != overlay_buffer)
+ if (OverlayType != overlay_buffer
+ && OverlayType != overlay_dissolve_union
+ && OverlayType != overlay_dissolve_intersection)
{
return;
}
+ const bool allow_uu = OverlayType != overlay_buffer;
+
// It travels to itself, can happen. If this is a buffer, it can
// sometimes travel to itself in the following configuration:
//
@@ -696,7 +756,10 @@ struct traversal
= start_turn.operations[1 - start_op_index];
bool const correct
- = ! start_turn.both(operation_union)
+ = (allow_uu || ! start_turn.both(operation_union))
+ && start_op.seg_id.source_index == other_op.seg_id.source_index
+ && start_op.seg_id.multi_index == other_op.seg_id.multi_index
+ && start_op.seg_id.ring_index == other_op.seg_id.ring_index
&& start_op.seg_id.segment_index == to_vertex_index;
#if defined(BOOST_GEOMETRY_DEBUG_TRAVERSE)
@@ -770,7 +833,7 @@ struct traversal
if (target_operation == operation_intersection)
{
bool const back_at_start_cluster
- = current_turn.cluster_id >= 0
+ = current_turn.is_clustered()
&& m_turns[start_turn_index].cluster_id == current_turn.cluster_id;
if (turn_index == start_turn_index || back_at_start_cluster)
@@ -781,7 +844,7 @@ struct traversal
return true;
}
- if (current_turn.cluster_id < 0
+ if (! current_turn.is_clustered()
&& current_turn.both(operation_intersection))
{
if (analyze_ii_intersection(turn_index, op_index,
@@ -792,10 +855,10 @@ struct traversal
}
}
- if (current_turn.cluster_id >= 0)
+ if (current_turn.is_clustered())
{
if (! select_turn_from_cluster(turn_index, op_index,
- start_turn_index, previous_seg_id))
+ start_turn_index, start_op_index, previous_seg_id))
{
return false;
}
diff --git a/boost/geometry/algorithms/detail/overlay/traversal_intersection_patterns.hpp b/boost/geometry/algorithms/detail/overlay/traversal_intersection_patterns.hpp
index 12279d762f..a8abea230e 100644
--- a/boost/geometry/algorithms/detail/overlay/traversal_intersection_patterns.hpp
+++ b/boost/geometry/algorithms/detail/overlay/traversal_intersection_patterns.hpp
@@ -32,8 +32,8 @@ inline bool check_pairs(std::vector<sort_by_side::rank_with_rings> const& aggreg
{
sort_by_side::rank_with_rings const& curr = aggregation[i];
sort_by_side::rank_with_rings const& next = aggregation[i + 1];
- int const curr_id = curr.region_id();
- int const next_id = next.region_id();
+ signed_size_type const curr_id = curr.region_id();
+ signed_size_type const next_id = next.region_id();
bool const possible =
curr.rings.size() == 2
@@ -249,7 +249,7 @@ inline bool intersection_pattern_common_interior4(std::size_t& selected_rank,
//Rank 1 {13[0] (s:0, r:0, m:0) i T rgn: 2 ISO ->15} {11[1] (s:1, r:1, m:0) i T rgn: 2 ISO ->15}
//Rank 2 {13[0] (s:0, r:0, m:0) i F rgn: 2 ISO} {11[1] (s:1, r:1, m:0) i F rgn: 2 ISO}
- // LEAVING (in two different directions, take last one)
+ // LEAVING (in two different directions, take penultimate one)
//Rank 3 {10[1] (s:1, m:0) i T rgn: 1 ISO ->0}
//Rank 4 {11[0] (s:0, m:0) i T rgn: 1 ISO ->12}
@@ -292,12 +292,157 @@ inline bool intersection_pattern_common_interior4(std::size_t& selected_rank,
// Check if pairs 1,2 (and possibly 3,4 and 5,6 etc) satisfy
if (check_pairs(aggregation, incoming.region_id(), 1, n - 3))
{
- selected_rank = n - 1;
+ selected_rank = n - 2;
return true;
}
return false;
}
+inline bool intersection_pattern_common_interior5(std::size_t& selected_rank,
+ std::vector<sort_by_side::rank_with_rings> const& aggregation)
+{
+ // Pattern: isolated regions
+
+ // See #case_recursive_boxes_65
+
+ // INCOMING:
+ // Rank 0 {19[0] (s:0, r:2, m:0) i F rgn: 4 ISO}
+
+ // Rank 1 {19[1] (s:1, m:0) i T rgn: 1 ISO FIN ->18 (2.5)}
+ // Rank 2 {21[1] (s:1, m:2) i F rgn: 1 ISO}
+ // Rank 3 {21[1] (s:1, m:2) i T rgn: 1 ISO ->17 (2)}
+ // Rank 4 {19[1] (s:1, m:0) i F rgn: 1 ISO FIN}
+
+ // LEAVING (take this one):
+ // Rank 5 {19[0] (s:0, r:2, m:0) i T rgn: 4 ISO ->22 (1)}
+
+ std::size_t const n = aggregation.size();
+ if (n < 3)
+ {
+ return false;
+ }
+
+ sort_by_side::rank_with_rings const& incoming = aggregation.front();
+ sort_by_side::rank_with_rings const& outgoing = aggregation.back();
+
+ bool const incoming_ok =
+ incoming.all_from()
+ && incoming.has_unique_region_id()
+ && incoming.is_isolated();
+
+ if (! incoming_ok)
+ {
+ return false;
+ }
+
+ signed_size_type const incoming_region_id = incoming.region_id();
+
+ bool const outgoing_ok =
+ outgoing.all_to()
+ && outgoing.has_unique_region_id()
+ && outgoing.is_isolated()
+ && outgoing.region_id() == incoming_region_id;
+
+ if (! outgoing_ok)
+ {
+ return false;
+ }
+
+ selected_rank = n - 1;
+ bool other_region = true;
+
+ // Assumed is that other regions go (T) and come back (F)
+ for (std::size_t i = 1; i < n - 1; i++)
+ {
+ sort_by_side::rank_with_rings const& rwr = aggregation[i];
+ if (! rwr.has_unique_region_id() || ! rwr.is_isolated())
+ {
+ return false;
+ }
+ signed_size_type const region_id = rwr.region_id();
+ if (other_region && region_id != incoming_region_id)
+ {
+ // OK
+ }
+ else if (other_region && region_id == incoming_region_id)
+ {
+ // OK, next phase (same region as incoming region)
+ selected_rank = i;
+ other_region = false;
+ }
+ else if (! other_region && region_id != incoming_region_id)
+ {
+ // After that the region is the same is incoming, it should
+ // stay like that
+ return false;
+ }
+ }
+
+ return true;
+}
+
+inline bool intersection_pattern_common_interior6(std::size_t& selected_rank,
+ std::vector<sort_by_side::rank_with_rings> const& aggregation)
+{
+ // Pattern: isolated regions in between
+
+ // See #case_recursive_boxes_75
+
+ // Incoming: one region
+ // In between: several rings having isolated region, all the same
+ // Outging == incoming
+
+ std::size_t const n = aggregation.size();
+ if (n < 3)
+ {
+ return false;
+ }
+
+ sort_by_side::rank_with_rings const& incoming = aggregation.front();
+ sort_by_side::rank_with_rings const& outgoing = aggregation.back();
+ sort_by_side::rank_with_rings const& first_isolated = aggregation[2];
+
+ bool const incoming_ok =
+ incoming.all_from()
+ && incoming.has_unique_region_id()
+ && ! incoming.is_isolated();
+
+ if (! incoming_ok)
+ {
+ return false;
+ }
+
+ signed_size_type const incoming_region_id = incoming.region_id();
+
+ bool const outgoing_ok =
+ outgoing.all_to()
+ && outgoing.has_unique_region_id()
+ && ! outgoing.is_isolated()
+ && outgoing.region_id() == incoming_region_id;
+
+ if (! outgoing_ok)
+ {
+ return false;
+ }
+
+ const signed_size_type isolated_region_id = first_isolated.region_id();
+
+ for (std::size_t i = 1; i < n - 1; i++)
+ {
+ sort_by_side::rank_with_rings const& rwr = aggregation[i];
+ if (! rwr.has_unique_region_id()
+ || ! rwr.is_isolated()
+ || rwr.region_id() != isolated_region_id)
+ {
+ return false;
+ }
+ }
+
+ selected_rank = n - 1;
+
+ return true;
+}
+
}} // namespace detail::overlay
#endif // DOXYGEN_NO_DETAIL
diff --git a/boost/geometry/algorithms/detail/overlay/traversal_ring_creator.hpp b/boost/geometry/algorithms/detail/overlay/traversal_ring_creator.hpp
index af643a822b..4df3f6e7ac 100644
--- a/boost/geometry/algorithms/detail/overlay/traversal_ring_creator.hpp
+++ b/boost/geometry/algorithms/detail/overlay/traversal_ring_creator.hpp
@@ -41,6 +41,7 @@ template
typename Geometry1,
typename Geometry2,
typename Turns,
+ typename TurnInfoMap,
typename Clusters,
typename IntersectionStrategy,
typename RobustPolicy,
@@ -64,7 +65,8 @@ struct traversal_ring_creator
= operation_from_overlay<OverlayType>::value;
inline traversal_ring_creator(Geometry1 const& geometry1, Geometry2 const& geometry2,
- Turns& turns, Clusters const& clusters,
+ Turns& turns, TurnInfoMap& turn_info_map,
+ Clusters const& clusters,
IntersectionStrategy const& intersection_strategy,
RobustPolicy const& robust_policy, Visitor& visitor)
: m_trav(geometry1, geometry2, turns, clusters,
@@ -73,6 +75,7 @@ struct traversal_ring_creator
, m_geometry1(geometry1)
, m_geometry2(geometry2)
, m_turns(turns)
+ , m_turn_info_map(turn_info_map)
, m_clusters(clusters)
, m_intersection_strategy(intersection_strategy)
, m_robust_policy(robust_policy)
@@ -203,7 +206,7 @@ struct traversal_ring_creator
return traverse_error_none;
}
- if (start_turn.cluster_id >= 0)
+ if (start_turn.is_clustered())
{
turn_type const& turn = m_turns[current_turn_index];
if (turn.cluster_id == start_turn.cluster_id)
@@ -286,7 +289,7 @@ struct traversal_ring_creator
m_robust_policy);
rings.push_back(ring);
- m_trav.finalize_visit_info();
+ m_trav.finalize_visit_info(m_turn_info_map);
finalized_ring_size++;
}
}
@@ -347,6 +350,7 @@ private:
Geometry1 const& m_geometry1;
Geometry2 const& m_geometry2;
Turns& m_turns;
+ TurnInfoMap& m_turn_info_map; // contains turn-info information per ring
Clusters const& m_clusters;
IntersectionStrategy const& m_intersection_strategy;
RobustPolicy const& m_robust_policy;
diff --git a/boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp b/boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp
index 0b4f393ef4..72f9c4f12a 100644
--- a/boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp
+++ b/boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp
@@ -48,17 +48,24 @@ template
>
struct traversal_switch_detector
{
- enum isolation_type { isolation_unknown = -1, isolation_no = 0, isolation_yes = 1 };
+ enum isolation_type
+ {
+ isolation_unknown = -1,
+ isolation_no = 0,
+ isolation_yes = 1,
+ isolation_multiple = 2
+ };
typedef typename boost::range_value<Turns>::type turn_type;
typedef typename turn_type::turn_operation_type turn_operation_type;
+ typedef std::set<signed_size_type> set_type;
// Per ring, first turns are collected (in turn_indices), and later
// a region_id is assigned
struct merged_ring_properties
{
signed_size_type region_id;
- std::set<signed_size_type> turn_indices;
+ set_type turn_indices;
merged_ring_properties()
: region_id(-1)
@@ -68,7 +75,8 @@ struct traversal_switch_detector
struct connection_properties
{
std::size_t count;
- std::set<signed_size_type> cluster_indices;
+ // Contains turn-index OR, if clustered, minus-cluster_id
+ set_type unique_turn_ids;
connection_properties()
: count(0)
{}
@@ -82,6 +90,7 @@ struct traversal_switch_detector
{
signed_size_type region_id;
isolation_type isolated;
+ set_type unique_turn_ids;
// Maps from connected region_id to their properties
connection_map connected_region_counts;
@@ -96,7 +105,7 @@ struct traversal_switch_detector
typedef std::map<ring_identifier, merged_ring_properties > merge_map;
typedef std::map<signed_size_type, region_properties> region_connection_map;
- typedef std::set<signed_size_type>::const_iterator set_iterator;
+ typedef set_type::const_iterator set_iterator;
inline traversal_switch_detector(Geometry1 const& geometry1, Geometry2 const& geometry2,
Turns& turns, Clusters& clusters,
@@ -110,111 +119,232 @@ struct traversal_switch_detector
{
}
- isolation_type get_isolation(region_properties const& properties,
- signed_size_type parent_region_id,
- const std::set<signed_size_type>& visited)
+ bool inspect_difference(set_type& turn_id_difference,
+ set_type const& turn_ids,
+ set_type const& other_turn_ids) const
{
- if (properties.isolated != isolation_unknown)
+ // TODO: consider if std::set_difference can be used in the final version
+ int const turn_count = turn_ids.size();
+ int const other_turn_count = other_turn_ids.size();
+
+ // First quick check on size (TODO: implement multiple-multiple connections)
+ if (turn_count - other_turn_count > 1)
{
- return properties.isolated;
+ return false;
}
- bool all_colocated = true;
- int unique_cluster_id = -1;
- for (typename connection_map::const_iterator it = properties.connected_region_counts.begin();
- all_colocated && it != properties.connected_region_counts.end(); ++it)
+ // Check if all turns are also present in the connection.
+ // The difference is returned
+ for (set_iterator it = turn_ids.begin(); it != turn_ids.end(); ++it)
{
- connection_properties const& cprop = it->second;
- if (cprop.cluster_indices.size() != 1)
- {
- // Either no cluster (non colocated point), or more clusters
- all_colocated = false;
- }
- int const cluster_id = *cprop.cluster_indices.begin();
- if (cluster_id == -1)
+ signed_size_type const& id = *it;
+ if (other_turn_ids.count(id) == 0)
{
- all_colocated = false;
- }
- else if (unique_cluster_id == -1)
- {
- unique_cluster_id = cluster_id;
- }
- else if (unique_cluster_id != cluster_id)
- {
- all_colocated = false;
+ turn_id_difference.insert(id);
}
}
- if (all_colocated)
+ return true;
+ }
+
+ bool one_connection_to_another_region(region_properties const& region) const
+ {
+ // For example:
+ // +----------------------+
+ // | __ |
+ // | / \|
+ // | | x
+ // | \__/|
+ // | |
+ // +----------------------+
+
+ if (region.connected_region_counts.size() == 1)
{
- return isolation_yes;
+ connection_properties const& cprop = region.connected_region_counts.begin()->second;
+ return cprop.count <= 1;
}
+ return region.connected_region_counts.empty();
+ }
+ // TODO: might be combined with previous
+ bool multiple_connections_to_one_region(region_properties const& region) const
+ {
+ // For example:
+ // +----------------------+
+ // | __ |
+ // | / \|
+ // | | x
+ // | \ /|
+ // | / \|
+ // | | x
+ // | \__/|
+ // | |
+ // +----------------------+
+
+ if (region.connected_region_counts.size() == 1)
+ {
+ connection_properties const& cprop = region.connected_region_counts.begin()->second;
+ return cprop.count > 1;
+ }
+ return false;
+ }
- // It is isolated if there is only one connection, or if there are more connections but all
- // of them are isolated themselves, or if there are more connections
- // but they are all colocated
- std::size_t non_isolation_count = 0;
- bool child_not_isolated = false;
- for (typename connection_map::const_iterator it = properties.connected_region_counts.begin();
- it != properties.connected_region_counts.end(); ++it)
+ bool one_connection_to_multiple_regions(region_properties const& region) const
+ {
+ // For example:
+ // +----------------------+
+ // | __ | __
+ // | / \|/ |
+ // | | x |
+ // | \__/|\__|
+ // | |
+ // +----------------------+
+
+ bool first = true;
+ signed_size_type first_turn_id = 0;
+ for (typename connection_map::const_iterator it = region.connected_region_counts.begin();
+ it != region.connected_region_counts.end(); ++it)
{
- signed_size_type const region_id = it->first;
connection_properties const& cprop = it->second;
- if (region_id == parent_region_id)
+ if (cprop.count != 1)
{
- // Normal situation, skip its direct parent
- continue;
+ return false;
}
- if (visited.count(region_id) > 0)
+ signed_size_type const unique_turn_id = *cprop.unique_turn_ids.begin();
+ if (first)
{
- // Find one of its ancestors again, this is a ring. Not isolated.
- return isolation_no;
+ first_turn_id = unique_turn_id;
+ first = false;
}
- if (cprop.count > 1)
+ else if (first_turn_id != unique_turn_id)
{
- return isolation_no;
+ return false;
}
+ }
+ return true;
+ }
- typename region_connection_map::iterator mit = m_connected_regions.find(region_id);
+ bool has_only_isolated_children(region_properties const& region) const
+ {
+ bool first_with_turn = true;
+ bool first_with_multiple = true;
+ signed_size_type first_turn_id = 0;
+ signed_size_type first_multiple_region_id = 0;
+
+ for (typename connection_map::const_iterator it = region.connected_region_counts.begin();
+ it != region.connected_region_counts.end(); ++it)
+ {
+ signed_size_type const region_id = it->first;
+ connection_properties const& cprop = it->second;
+
+ typename region_connection_map::const_iterator mit = m_connected_regions.find(region_id);
if (mit == m_connected_regions.end())
{
// Should not occur
- continue;
+ return false;
}
- std::set<signed_size_type> vis = visited;
- vis.insert(parent_region_id);
+ region_properties const& connected_region = mit->second;
+
+ bool const multiple = connected_region.isolated == isolation_multiple;
- region_properties& prop = mit->second;
- if (prop.isolated == isolation_unknown)
+ if (cprop.count != 1)
{
- isolation_type const iso = get_isolation(prop, properties.region_id, vis);
- prop.isolated = iso;
- if (iso == isolation_no)
+ if (! multiple)
+ {
+ return false;
+ }
+
+ // It connects multiple times to an isolated region.
+ // This is allowed as long as it happens only once
+ if (first_with_multiple)
+ {
+ first_multiple_region_id = connected_region.region_id;
+ first_with_multiple = false;
+ }
+ else if (first_multiple_region_id != connected_region.region_id)
+ {
+ return false;
+ }
+
+ // Turns in region should be either present in the connection,
+ // of form part of the connection with the other region
+ set_type diff;
+ if (! inspect_difference(diff, region.unique_turn_ids,
+ connected_region.unique_turn_ids))
{
- child_not_isolated = true;
+ return false;
+ }
+ if (diff.size() > 1)
+ {
+ // For now:
+ return false;
}
}
- if (prop.isolated == isolation_no)
+
+ if (connected_region.isolated != isolation_yes && ! multiple)
{
- non_isolation_count++;
+ signed_size_type const unique_turn_id = *cprop.unique_turn_ids.begin();
+ if (first_with_turn)
+ {
+ first_turn_id = unique_turn_id;
+ first_with_turn = false;
+ }
+ else if (first_turn_id != unique_turn_id)
+ {
+ return false;
+ }
}
}
-
- return child_not_isolated || non_isolation_count > 1 ? isolation_no : isolation_yes;
+ // If there is only one connection (with a 'parent'), and all other
+ // connections are itself isolated, it is isolated
+ return true;
}
void get_isolated_regions()
{
- for (typename region_connection_map::iterator it = m_connected_regions.begin();
+ typedef typename region_connection_map::iterator it_type;
+
+ // First time: check regions isolated (one connection only),
+ // semi-isolated (multiple connections between same region),
+ // and complex isolated (connection with multiple rings but all
+ // at same point)
+ for (it_type it = m_connected_regions.begin();
it != m_connected_regions.end(); ++it)
{
region_properties& properties = it->second;
- if (properties.isolated == isolation_unknown)
+ if (one_connection_to_another_region(properties))
{
- std::set<signed_size_type> visited;
- properties.isolated = get_isolation(properties, properties.region_id, visited);
+ properties.isolated = isolation_yes;
+ }
+ else if (multiple_connections_to_one_region(properties))
+ {
+ properties.isolated = isolation_multiple;
+ }
+ else if (one_connection_to_multiple_regions(properties))
+ {
+ properties.isolated = isolation_yes;
+ }
+ }
+
+ // Propagate isolation to next level
+ // TODO: should be optimized
+ std::size_t defensive_check = 0;
+ bool changed = true;
+ while (changed && defensive_check++ < m_connected_regions.size())
+ {
+ changed = false;
+ for (it_type it = m_connected_regions.begin();
+ it != m_connected_regions.end(); ++it)
+ {
+ region_properties& properties = it->second;
+
+ if (properties.isolated == isolation_unknown
+ && has_only_isolated_children(properties))
+ {
+ properties.isolated = isolation_yes;
+ changed = true;
+ }
}
}
}
@@ -238,7 +368,7 @@ struct traversal_switch_detector
}
}
- void assign_regions()
+ void assign_region_ids()
{
for (typename merge_map::const_iterator it
= m_turns_per_ring.begin(); it != m_turns_per_ring.end(); ++it)
@@ -259,39 +389,53 @@ struct traversal_switch_detector
op.enriched.region_id = properties.region_id;
}
}
- signed_size_type const& id0 = turn.operations[0].enriched.region_id;
- signed_size_type const& id1 = turn.operations[1].enriched.region_id;
- if (id0 != id1 && id0 != -1 && id1 != -1)
- {
- // Force insertion
- m_connected_regions[id0].region_id = id0;
- m_connected_regions[id1].region_id = id1;
+ }
+ }
+ }
- connection_properties& prop0 = m_connected_regions[id0].connected_region_counts[id1];
- connection_properties& prop1 = m_connected_regions[id1].connected_region_counts[id0];
+ void assign_connected_regions()
+ {
+ for (std::size_t turn_index = 0; turn_index < m_turns.size(); ++turn_index)
+ {
+ turn_type const& turn = m_turns[turn_index];
- if (turn.cluster_id < 0)
- {
- // Turn is not colocated, add reference to connection
- prop0.count++;
- prop1.count++;
- }
- else
- {
- // Turn is colocated, only add region reference if it was not yet registered
- if (prop0.cluster_indices.count(turn.cluster_id) == 0)
- {
- prop0.count++;
- }
- if (prop1.cluster_indices.count(turn.cluster_id) == 0)
- {
- prop1.count++;
- }
- }
- // Insert cluster-id (also -1 is inserted - reinsertion of
- // same cluster id is OK)
- prop0.cluster_indices.insert(turn.cluster_id);
- prop1.cluster_indices.insert(turn.cluster_id);
+ signed_size_type const unique_turn_id
+ = turn.is_clustered() ? -turn.cluster_id : turn_index;
+
+ turn_operation_type op0 = turn.operations[0];
+ turn_operation_type op1 = turn.operations[1];
+
+ signed_size_type const& id0 = op0.enriched.region_id;
+ signed_size_type const& id1 = op1.enriched.region_id;
+
+ // Add region (by assigning) and add involved turns
+ if (id0 != -1)
+ {
+ m_connected_regions[id0].region_id = id0;
+ m_connected_regions[id0].unique_turn_ids.insert(unique_turn_id);
+ }
+ if (id1 != -1 && id0 != id1)
+ {
+ m_connected_regions[id1].region_id = id1;
+ m_connected_regions[id1].unique_turn_ids.insert(unique_turn_id);
+ }
+
+ if (id0 != id1 && id0 != -1 && id1 != -1)
+ {
+ // Assign connections
+ connection_properties& prop0 = m_connected_regions[id0].connected_region_counts[id1];
+ connection_properties& prop1 = m_connected_regions[id1].connected_region_counts[id0];
+
+ // Reference this turn or cluster to later check uniqueness on ring
+ if (prop0.unique_turn_ids.count(unique_turn_id) == 0)
+ {
+ prop0.count++;
+ prop0.unique_turn_ids.insert(unique_turn_id);
+ }
+ if (prop1.unique_turn_ids.count(unique_turn_id) == 0)
+ {
+ prop1.count++;
+ prop1.unique_turn_ids.insert(unique_turn_id);
}
}
}
@@ -306,7 +450,7 @@ struct traversal_switch_detector
return false;
}
- if (turn.cluster_id == -1)
+ if (! turn.is_clustered())
{
// If it is a uu/ii-turn (non clustered), it is never same region
return ! (turn.both(operation_union) || turn.both(operation_intersection));
@@ -320,39 +464,22 @@ struct traversal_switch_detector
== turn.operations[1].enriched.zone;
}
- // If a cluster contains an ii/cc it is not same region (for intersection)
- typename Clusters::const_iterator it = m_clusters.find(turn.cluster_id);
- if (it == m_clusters.end())
- {
- // Should not occur
- return true;
- }
-
- cluster_info const& cinfo = it->second;
- for (set_iterator sit = cinfo.turn_indices.begin();
- sit != cinfo.turn_indices.end(); ++sit)
- {
- turn_type const& cluster_turn = m_turns[*sit];
- if (cluster_turn.both(operation_union)
- || cluster_turn.both(operation_intersection))
- {
- return false;
- }
- }
-
- // It is the same region
- return false;
+ // For an intersection, two regions connect if they are not ii
+ // (ii-regions are isolated) or, in some cases, not iu (for example
+ // when a multi-polygon is inside an interior ring and connecting it)
+ return ! (turn.both(operation_intersection)
+ || turn.combination(operation_intersection, operation_union));
}
- inline int get_region_id(turn_operation_type const& op) const
+ inline signed_size_type get_region_id(turn_operation_type const& op) const
{
return op.enriched.region_id;
}
void create_region(signed_size_type& new_region_id, ring_identifier const& ring_id,
- merged_ring_properties& properties, int region_id = -1)
+ merged_ring_properties& properties, signed_size_type region_id = -1)
{
if (properties.region_id > 0)
{
@@ -400,7 +527,7 @@ struct traversal_switch_detector
}
void propagate_region(signed_size_type& new_region_id,
- ring_identifier const& ring_id, int region_id)
+ ring_identifier const& ring_id, signed_size_type region_id)
{
typename merge_map::iterator it = m_turns_per_ring.find(ring_id);
if (it != m_turns_per_ring.end())
@@ -438,7 +565,7 @@ struct traversal_switch_detector
}
}
- // All rings having turns are in the map. Now iterate them
+ // All rings having turns are in turns/ring map. Process them.
{
signed_size_type new_region_id = 1;
for (typename merge_map::iterator it
@@ -447,7 +574,8 @@ struct traversal_switch_detector
create_region(new_region_id, it->first, it->second);
}
- assign_regions();
+ assign_region_ids();
+ assign_connected_regions();
get_isolated_regions();
assign_isolation();
}
@@ -464,9 +592,8 @@ struct traversal_switch_detector
}
// A touching cluster, gather regions
- std::set<int> regions;
-
- std::set<signed_size_type> const& ids = cinfo.turn_indices;
+ set_type regions;
+ set_type const& ids = cinfo.turn_indices;
#if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR)
std::cout << "SWITCH EXAMINE CLUSTER " << it->first << std::endl;
@@ -476,14 +603,10 @@ struct traversal_switch_detector
{
signed_size_type turn_index = *sit;
turn_type const& turn = m_turns[turn_index];
- if (turn.colocated_ii && ! turn.colocated_uu)
- {
- continue;
- }
for (int oi = 0; oi < 2; oi++)
{
- int const region = get_region_id(turn.operations[oi]);
- regions.insert(region);
+ signed_size_type const region_id = get_region_id(turn.operations[oi]);
+ regions.insert(region_id);
}
}
// Switch source if this cluster connects the same region
@@ -497,24 +620,16 @@ struct traversal_switch_detector
if (turn.discarded
|| turn.blocked()
- || turn.cluster_id >= 0
+ || turn.is_clustered()
|| ! (turn.both(operation_union) || turn.both(operation_intersection)))
{
// Skip discarded, blocked, non-uu/ii and clustered turns
continue;
}
- if (OverlayType == overlay_buffer)
- {
- // For deflate, the region approach does not work because many
- // pieces are outside the real polygons
- // TODO: implement this in another way for buffer
- // (because now buffer might output invalid geometries)
- continue;
- }
- int const region0 = get_region_id(turn.operations[0]);
- int const region1 = get_region_id(turn.operations[1]);
+ signed_size_type const region0 = get_region_id(turn.operations[0]);
+ signed_size_type const region1 = get_region_id(turn.operations[1]);
// Switch sources for same region
turn.switch_source = region0 == region1;
@@ -529,7 +644,7 @@ struct traversal_switch_detector
turn_type const& turn = m_turns[turn_index];
if ((turn.both(operation_union) || turn.both(operation_intersection))
- && turn.cluster_id < 0)
+ && ! turn.is_clustered())
{
std::cout << "UU/II SWITCH RESULT "
<< turn_index << " -> "
diff --git a/boost/geometry/algorithms/detail/overlay/traverse.hpp b/boost/geometry/algorithms/detail/overlay/traverse.hpp
index 058f6c9458..b9cbea3127 100644
--- a/boost/geometry/algorithms/detail/overlay/traverse.hpp
+++ b/boost/geometry/algorithms/detail/overlay/traverse.hpp
@@ -62,14 +62,16 @@ public :
typename RobustPolicy,
typename Turns,
typename Rings,
- typename Visitor,
- typename Clusters
+ typename TurnInfoMap,
+ typename Clusters,
+ typename Visitor
>
static inline void apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
IntersectionStrategy const& intersection_strategy,
RobustPolicy const& robust_policy,
Turns& turns, Rings& rings,
+ TurnInfoMap& turn_info_map,
Clusters& clusters,
Visitor& visitor)
{
@@ -89,11 +91,11 @@ public :
<
Reverse1, Reverse2, OverlayType,
Geometry1, Geometry2,
- Turns, Clusters,
+ Turns, TurnInfoMap, Clusters,
IntersectionStrategy,
RobustPolicy, Visitor,
Backtrack
- > trav(geometry1, geometry2, turns, clusters,
+ > trav(geometry1, geometry2, turns, turn_info_map, clusters,
intersection_strategy, robust_policy, visitor);
std::size_t finalized_ring_size = boost::size(rings);
diff --git a/boost/geometry/algorithms/detail/overlay/turn_info.hpp b/boost/geometry/algorithms/detail/overlay/turn_info.hpp
index 3a4c2e94a1..3ed75cf09e 100644
--- a/boost/geometry/algorithms/detail/overlay/turn_info.hpp
+++ b/boost/geometry/algorithms/detail/overlay/turn_info.hpp
@@ -90,12 +90,10 @@ struct turn_info
Point point;
method_type method;
bool touch_only; // True in case of method touch(interior) and lines do not cross
- signed_size_type cluster_id; // For multiple turns on same location, >= 0. Else -1
+ signed_size_type cluster_id; // For multiple turns on same location, > 0. Else -1. 0 is unused.
bool discarded;
- // TODO: move this to enriched
- bool colocated_ii; // Colocated with a ii turn (TODO: or a ix turn)
- bool colocated_uu; // Colocated with a uu turn or a ux turn
+ bool has_colocated_both; // Colocated with a uu turn (for union) or ii (other)
bool switch_source; // For u/u turns which can either switch or not
Container operations;
@@ -105,8 +103,7 @@ struct turn_info
, touch_only(false)
, cluster_id(-1)
, discarded(false)
- , colocated_ii(false)
- , colocated_uu(false)
+ , has_colocated_both(false)
, switch_source(false)
{}
@@ -138,6 +135,10 @@ struct turn_info
{
return has(operation_blocked);
}
+ inline bool is_clustered() const
+ {
+ return cluster_id > 0;
+ }
private :
inline bool has12(operation_type type1, operation_type type2) const
diff --git a/boost/geometry/algorithms/detail/relate/less.hpp b/boost/geometry/algorithms/detail/relate/less.hpp
deleted file mode 100644
index 462fcc35f1..0000000000
--- a/boost/geometry/algorithms/detail/relate/less.hpp
+++ /dev/null
@@ -1,83 +0,0 @@
-// Boost.Geometry (aka GGL, Generic Geometry Library)
-
-// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
-
-// This file was modified by Oracle on 2014.
-// Modifications copyright (c) 2014, Oracle and/or its affiliates.
-
-// 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_LESS_HPP
-#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LESS_HPP
-
-#include <boost/geometry/core/coordinate_dimension.hpp>
-#include <boost/geometry/core/coordinate_type.hpp>
-#include <boost/geometry/util/math.hpp>
-
-namespace boost { namespace geometry
-{
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace detail_dispatch { namespace relate {
-
-// TODO: Integrate it with geometry::less?
-
-template <typename Point1,
- typename Point2,
- std::size_t I = 0,
- std::size_t D = geometry::dimension<Point1>::value>
-struct less
-{
- static inline bool apply(Point1 const& left, Point2 const& right)
- {
- typename geometry::coordinate_type<Point1>::type
- cleft = geometry::get<I>(left);
- typename geometry::coordinate_type<Point2>::type
- cright = geometry::get<I>(right);
-
- if ( geometry::math::equals(cleft, cright) )
- {
- return less<Point1, Point2, I + 1, D>::apply(left, right);
- }
- else
- {
- return cleft < cright;
- }
- }
-};
-
-template <typename Point1, typename Point2, std::size_t D>
-struct less<Point1, Point2, D, D>
-{
- static inline bool apply(Point1 const&, Point2 const&)
- {
- return false;
- }
-};
-
-}} // namespace detail_dispatch::relate
-
-#endif
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace relate {
-
-struct less
-{
- template <typename Point1, typename Point2>
- inline bool operator()(Point1 const& point1, Point2 const& point2) const
- {
- return detail_dispatch::relate::less<Point1, Point2>::apply(point1, point2);
- }
-};
-
-}} // namespace detail::relate
-#endif // DOXYGEN_NO_DETAIL
-
-}} // namespace boost::geometry
-
-#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LESS_HPP
diff --git a/boost/geometry/algorithms/detail/relate/linear_areal.hpp b/boost/geometry/algorithms/detail/relate/linear_areal.hpp
index f1b4fdf81a..ddbd7d615a 100644
--- a/boost/geometry/algorithms/detail/relate/linear_areal.hpp
+++ b/boost/geometry/algorithms/detail/relate/linear_areal.hpp
@@ -260,17 +260,19 @@ struct linear_areal
if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) )
return;
+ typedef typename IntersectionStrategy::template point_in_geometry_strategy<Geometry1, Geometry2>::type within_strategy_type;
+ within_strategy_type const within_strategy = intersection_strategy.template get_point_in_geometry_strategy<Geometry1, Geometry2>();
boundary_checker<Geometry1> boundary_checker1(geometry1);
no_turns_la_linestring_pred
<
Geometry2,
Result,
- typename IntersectionStrategy::template point_in_geometry_strategy<Geometry1, Geometry2>::type,
+ within_strategy_type,
boundary_checker<Geometry1>,
TransposeResult
> pred1(geometry2,
result,
- intersection_strategy.template get_point_in_geometry_strategy<Geometry1, Geometry2>(),
+ within_strategy,
boundary_checker1);
for_each_disjoint_geometry_if<0, Geometry1>::apply(turns.begin(), turns.end(), geometry1, pred1);
if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) )
diff --git a/boost/geometry/algorithms/detail/relate/multi_point_geometry.hpp b/boost/geometry/algorithms/detail/relate/multi_point_geometry.hpp
index 47c6963b87..8d5f21555c 100644
--- a/boost/geometry/algorithms/detail/relate/multi_point_geometry.hpp
+++ b/boost/geometry/algorithms/detail/relate/multi_point_geometry.hpp
@@ -121,7 +121,7 @@ struct multi_point_geometry_eb<Geometry, multi_linestring_tag>
template <typename Point>
bool apply(Point const& boundary_point)
{
- if (! std::binary_search(m_points.begin(), m_points.end(), boundary_point, relate::less()))
+ if (! std::binary_search(m_points.begin(), m_points.end(), boundary_point, geometry::less<>()))
{
m_boundary_found = true;
return false;
@@ -143,7 +143,7 @@ struct multi_point_geometry_eb<Geometry, multi_linestring_tag>
typedef typename boost::range_value<MultiPoint>::type point_type;
typedef std::vector<point_type> points_type;
points_type points(boost::begin(multi_point), boost::end(multi_point));
- std::sort(points.begin(), points.end(), relate::less());
+ std::sort(points.begin(), points.end(), geometry::less<>());
boundary_visitor<points_type> visitor(points);
tc.for_each_boundary_point(visitor);
diff --git a/boost/geometry/algorithms/detail/relate/point_point.hpp b/boost/geometry/algorithms/detail/relate/point_point.hpp
index 68d8be031e..e0bed72ba3 100644
--- a/boost/geometry/algorithms/detail/relate/point_point.hpp
+++ b/boost/geometry/algorithms/detail/relate/point_point.hpp
@@ -21,9 +21,10 @@
#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
#include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp>
-#include <boost/geometry/algorithms/detail/relate/less.hpp>
#include <boost/geometry/algorithms/detail/relate/result.hpp>
+#include <boost/geometry/policies/compare.hpp>
+
namespace boost { namespace geometry
{
@@ -213,7 +214,9 @@ struct multipoint_multipoint
// sort points from the 1 MPt
typedef typename geometry::point_type<SortedMultiPoint>::type point_type;
std::vector<point_type> points(boost::begin(sorted_mpt), boost::end(sorted_mpt));
- std::sort(points.begin(), points.end(), less());
+
+ geometry::less<> const less = geometry::less<>();
+ std::sort(points.begin(), points.end(), less);
bool found_inside = false;
bool found_outside = false;
@@ -224,7 +227,7 @@ struct multipoint_multipoint
it != boost::end(iterated_mpt) ; ++it )
{
bool ii =
- std::binary_search(points.begin(), points.end(), *it, less());
+ std::binary_search(points.begin(), points.end(), *it, less);
if ( ii )
found_inside = true;
else
diff --git a/boost/geometry/algorithms/detail/relate/topology_check.hpp b/boost/geometry/algorithms/detail/relate/topology_check.hpp
index 654999d8fb..810466ec05 100644
--- a/boost/geometry/algorithms/detail/relate/topology_check.hpp
+++ b/boost/geometry/algorithms/detail/relate/topology_check.hpp
@@ -13,7 +13,8 @@
#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
-#include <boost/geometry/algorithms/detail/relate/less.hpp>
+
+#include <boost/geometry/policies/compare.hpp>
#include <boost/geometry/util/has_nan_coordinate.hpp>
#include <boost/geometry/util/range.hpp>
@@ -214,7 +215,7 @@ private:
if (! m_endpoints.empty() )
{
- std::sort(m_endpoints.begin(), m_endpoints.end(), relate::less());
+ std::sort(m_endpoints.begin(), m_endpoints.end(), geometry::less<>());
m_has_boundary = find_odd_count(m_endpoints.begin(), m_endpoints.end());
}
@@ -224,7 +225,7 @@ private:
template <typename It, typename Point>
static inline std::size_t count_equal(It first, It last, Point const& point)
{
- std::pair<It, It> rng = std::equal_range(first, last, point, relate::less());
+ std::pair<It, It> rng = std::equal_range(first, last, point, geometry::less<>());
return (std::size_t)std::distance(rng.first, rng.second);
}
diff --git a/boost/geometry/algorithms/detail/sections/section_functions.hpp b/boost/geometry/algorithms/detail/sections/section_functions.hpp
index 67df3060c4..d283784e2c 100644
--- a/boost/geometry/algorithms/detail/sections/section_functions.hpp
+++ b/boost/geometry/algorithms/detail/sections/section_functions.hpp
@@ -19,6 +19,9 @@
#include <boost/geometry/algorithms/detail/recalculate.hpp>
#include <boost/geometry/policies/robustness/robust_point_type.hpp>
+// For spherical/geographic longitudes covered_by point/box
+#include <boost/geometry/strategies/cartesian/point_in_box.hpp>
+
namespace boost { namespace geometry
{
@@ -61,17 +64,33 @@ struct preceding_check<0, Geometry, spherical_tag>
calc_t const c0 = 0;
+ calc_t const value = get<0>(point);
+ calc_t const other_min = get<min_corner, 0>(other_box);
+ calc_t const other_max = get<max_corner, 0>(other_box);
+
+ bool const pt_covered = strategy::within::covered_by_range
+ <
+ Point, 0, spherical_tag
+ >::apply(value,
+ other_min,
+ other_max);
+
+ if (pt_covered)
+ {
+ return false;
+ }
+
if (dir == 1)
{
calc_t const diff_min = math::longitude_distance_signed
<
units_t, calc_t
- >(get<min_corner, 0>(other_box), get<0>(point));
+ >(other_min, value);
calc_t const diff_min_min = math::longitude_distance_signed
<
units_t, calc_t
- >(get<min_corner, 0>(other_box), get<min_corner, 0>(point_box));
+ >(other_min, get<min_corner, 0>(point_box));
return diff_min < c0 && diff_min_min <= c0 && diff_min_min <= diff_min;
}
@@ -80,12 +99,12 @@ struct preceding_check<0, Geometry, spherical_tag>
calc_t const diff_max = math::longitude_distance_signed
<
units_t, calc_t
- >(get<max_corner, 0>(other_box), get<0>(point));
+ >(other_max, value);
calc_t const diff_max_max = math::longitude_distance_signed
<
units_t, calc_t
- >(get<max_corner, 0>(other_box), get<max_corner, 0>(point_box));
+ >(other_max, get<max_corner, 0>(point_box));
return diff_max > c0 && diff_max_max >= c0 && diff_max <= diff_max_max;
}
diff --git a/boost/geometry/algorithms/detail/touches/implementation.hpp b/boost/geometry/algorithms/detail/touches/implementation.hpp
index 94f1fba581..0cdb8ad1d4 100644
--- a/boost/geometry/algorithms/detail/touches/implementation.hpp
+++ b/boost/geometry/algorithms/detail/touches/implementation.hpp
@@ -413,7 +413,8 @@ struct touches<Areal1, Areal2, ring_tag, ring_tag, areal_tag, areal_tag, false>
#endif // DOXYGEN_NO_DISPATCH
-namespace resolve_variant {
+namespace resolve_variant
+{
template <typename Geometry>
struct self_touches
@@ -443,10 +444,11 @@ struct self_touches
detail::touches::areal_interrupt_policy policy;
strategy_type strategy;
rescale_policy_type robust_policy;
+ // TODO: skip_adjacent should be set to false
detail::self_get_turn_points::get_turns
<
false, policy_type
- >::apply(geometry, strategy, robust_policy, turns, policy, 0);
+ >::apply(geometry, strategy, robust_policy, turns, policy, 0, true);
return policy.result();
}
diff --git a/boost/geometry/algorithms/detail/within/multi_point.hpp b/boost/geometry/algorithms/detail/within/multi_point.hpp
index 7e85f33383..359853f6a4 100644
--- a/boost/geometry/algorithms/detail/within/multi_point.hpp
+++ b/boost/geometry/algorithms/detail/within/multi_point.hpp
@@ -21,7 +21,6 @@
#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
#include <boost/geometry/algorithms/detail/disjoint/point_box.hpp>
#include <boost/geometry/algorithms/detail/expand_by_epsilon.hpp>
-#include <boost/geometry/algorithms/detail/relate/less.hpp>
#include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp>
#include <boost/geometry/algorithms/envelope.hpp>
#include <boost/geometry/algorithms/detail/partition.hpp>
@@ -33,6 +32,8 @@
#include <boost/geometry/index/rtree.hpp>
+#include <boost/geometry/policies/compare.hpp>
+
#include <boost/geometry/strategies/covered_by.hpp>
#include <boost/geometry/strategies/disjoint.hpp>
@@ -63,7 +64,7 @@ struct multi_point_point
}
};
-// NOTE: currently the strategy is ignored, math::equals() is used inside relate::less
+// NOTE: currently the strategy is ignored, math::equals() is used inside geometry::less<>
struct multi_point_multi_point
{
template <typename MultiPoint1, typename MultiPoint2, typename Strategy>
@@ -73,7 +74,7 @@ struct multi_point_multi_point
{
typedef typename boost::range_value<MultiPoint2>::type point2_type;
- relate::less const less = relate::less();
+ geometry::less<> const less = geometry::less<>();
std::vector<point2_type> points2(boost::begin(multi_point2), boost::end(multi_point2));
std::sort(points2.begin(), points2.end(), less);
diff --git a/boost/geometry/algorithms/dispatch/expand.hpp b/boost/geometry/algorithms/dispatch/expand.hpp
index 2c23d6a1ce..c7a7696480 100644
--- a/boost/geometry/algorithms/dispatch/expand.hpp
+++ b/boost/geometry/algorithms/dispatch/expand.hpp
@@ -5,10 +5,11 @@
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// Copyright (c) 2014-2015 Samuel Debionne, Grenoble, France.
-// This file was modified by Oracle on 2015.
-// Modifications copyright (c) 2015, Oracle and/or its affiliates.
+// This file was modified by Oracle on 2015, 2017.
+// Modifications copyright (c) 2015-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -39,8 +40,6 @@ namespace dispatch
template
<
typename GeometryOut, typename Geometry,
- typename StrategyLess = strategy::compare::default_strategy,
- typename StrategyGreater = strategy::compare::default_strategy,
typename TagOut = typename tag<GeometryOut>::type,
typename Tag = typename tag<Geometry>::type,
typename CSTagOut = typename cs_tag<GeometryOut>::type,
diff --git a/boost/geometry/core/exception.hpp b/boost/geometry/core/exception.hpp
index 21abbd577b..72bc598b2a 100644
--- a/boost/geometry/core/exception.hpp
+++ b/boost/geometry/core/exception.hpp
@@ -4,8 +4,8 @@
// 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.
+// This file was modified by Oracle on 2015, 2017.
+// Modifications copyright (c) 2015-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -83,6 +83,25 @@ public:
}
};
+/*!
+\brief Invalid Output Exception
+\ingroup core
+\details The invalid_output_exception is thrown if valid output cannot be
+ generated by a function even if arguments are valid, e.g. union of
+ geographic polygons covering more than half of the area of the globe.
+ */
+class invalid_output_exception : public geometry::exception
+{
+public:
+
+ inline invalid_output_exception() {}
+
+ virtual char const* what() const throw()
+ {
+ return "Boost.Geometry Invalid-Output exception";
+ }
+};
+
}} // namespace boost::geometry
diff --git a/boost/geometry/formulas/andoyer_inverse.hpp b/boost/geometry/formulas/andoyer_inverse.hpp
index 902fd7d8f6..d0056d16c6 100644
--- a/boost/geometry/formulas/andoyer_inverse.hpp
+++ b/boost/geometry/formulas/andoyer_inverse.hpp
@@ -123,13 +123,33 @@ public:
if ( BOOST_GEOMETRY_CONDITION(CalcAzimuths) )
{
- // sin_d = 0 <=> antipodal points
+ // sin_d = 0 <=> antipodal points (incl. poles)
if (math::equals(sin_d, c0))
{
// T = inf
// dA = inf
// azimuth = -inf
- result.azimuth = lat1 <= lat2 ? c0 : pi;
+
+ // TODO: The following azimuths are inconsistent with distance
+ // i.e. according to azimuths below a segment with antipodal endpoints
+ // travels through the north pole, however the distance returned above
+ // is the length of a segment traveling along the equator.
+ // Furthermore, this special case handling is only done in andoyer
+ // formula.
+ // The most correct way of fixing it is to handle antipodal regions
+ // correctly and consistently across all formulas.
+
+ // Set azimuth to 0 unless the first endpoint is the north pole
+ if (! math::equals(sin_lat1, c1))
+ {
+ result.azimuth = c0;
+ result.reverse_azimuth = pi;
+ }
+ else
+ {
+ result.azimuth = pi;
+ result.reverse_azimuth = 0;
+ }
}
else
{
@@ -188,11 +208,10 @@ public:
if (BOOST_GEOMETRY_CONDITION(CalcRevAzimuth))
{
CT const dB = -U*T + V;
- result.reverse_azimuth = pi - B - dB;
- if (result.reverse_azimuth > pi)
- {
- result.reverse_azimuth -= 2 * pi;
- }
+ if (B >= 0)
+ result.reverse_azimuth = pi - B - dB;
+ else
+ result.reverse_azimuth = -pi - B - dB;
normalize_azimuth(result.reverse_azimuth, B, dB);
}
}
@@ -214,7 +233,7 @@ private:
static inline void normalize_azimuth(CT & azimuth, CT const& A, CT const& dA)
{
CT const c0 = 0;
-
+
if (A >= c0) // A indicates Eastern hemisphere
{
if (dA >= c0) // A altered towards 0
diff --git a/boost/geometry/formulas/area_formulas.hpp b/boost/geometry/formulas/area_formulas.hpp
index 6a0b525e25..9243c7f749 100644
--- a/boost/geometry/formulas/area_formulas.hpp
+++ b/boost/geometry/formulas/area_formulas.hpp
@@ -1,8 +1,9 @@
// Boost.Geometry
-// Copyright (c) 2015-2016 Oracle and/or its affiliates.
+// Copyright (c) 2015-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -540,12 +541,11 @@ public:
return result;
}
- // Keep track whenever a segment crosses the prime meridian
+ // Check whenever a segment crosses the prime meridian
// First normalize to [0,360)
- template <typename PointOfSegment, typename StateType>
- static inline int crosses_prime_meridian(PointOfSegment const& p1,
- PointOfSegment const& p2,
- StateType& state)
+ template <typename PointOfSegment>
+ static inline bool crosses_prime_meridian(PointOfSegment const& p1,
+ PointOfSegment const& p2)
{
CT const pi
= geometry::math::pi<CT>();
@@ -562,12 +562,7 @@ public:
CT max_lon = (std::max)(p1_lon, p2_lon);
CT min_lon = (std::min)(p1_lon, p2_lon);
- if(max_lon > pi && min_lon < pi && max_lon - min_lon > pi)
- {
- state.m_crosses_prime_meridian++;
- }
-
- return state.m_crosses_prime_meridian;
+ return max_lon > pi && min_lon < pi && max_lon - min_lon > pi;
}
};
diff --git a/boost/geometry/formulas/authalic_radius_sqr.hpp b/boost/geometry/formulas/authalic_radius_sqr.hpp
new file mode 100644
index 0000000000..54da317611
--- /dev/null
+++ b/boost/geometry/formulas/authalic_radius_sqr.hpp
@@ -0,0 +1,96 @@
+// Boost.Geometry
+
+// Copyright (c) 2017 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_FORMULAS_AUTHALIC_RADIUS_SQR_HPP
+#define BOOST_GEOMETRY_FORMULAS_AUTHALIC_RADIUS_SQR_HPP
+
+#include <boost/geometry/core/radius.hpp>
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/formulas/eccentricity_sqr.hpp>
+
+#include <boost/geometry/util/math.hpp>
+
+#include <boost/geometry/algorithms/not_implemented.hpp>
+
+#include <boost/math/special_functions/atanh.hpp>
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace formula_dispatch
+{
+
+template <typename ResultType, typename Geometry, typename Tag = typename tag<Geometry>::type>
+struct authalic_radius_sqr
+ : not_implemented<Tag>
+{};
+
+template <typename ResultType, typename Geometry>
+struct authalic_radius_sqr<ResultType, Geometry, srs_sphere_tag>
+{
+ static inline ResultType apply(Geometry const& geometry)
+ {
+ return math::sqr<ResultType>(get_radius<0>(geometry));
+ }
+};
+
+template <typename ResultType, typename Geometry>
+struct authalic_radius_sqr<ResultType, Geometry, srs_spheroid_tag>
+{
+ static inline ResultType apply(Geometry const& geometry)
+ {
+ ResultType const a2 = math::sqr<ResultType>(get_radius<0>(geometry));
+ ResultType const e2 = formula::eccentricity_sqr<ResultType>(geometry);
+
+ return apply(a2, e2);
+ }
+
+ static inline ResultType apply(ResultType const& a2, ResultType const& e2)
+ {
+ ResultType const c0 = 0;
+
+ if (math::equals(e2, c0))
+ {
+ return a2;
+ }
+
+ ResultType const e = math::sqrt(e2);
+ ResultType const c2 = 2;
+
+ //ResultType const b2 = math::sqr(get_radius<2>(geometry));
+ //return a2 / c2 + b2 * boost::math::atanh(e) / (c2 * e);
+
+ ResultType const c1 = 1;
+ return (a2 / c2) * ( c1 + (c1 - e2) * boost::math::atanh(e) / e );
+ }
+};
+
+} // namespace formula_dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace formula
+{
+
+template <typename ResultType, typename Geometry>
+inline ResultType authalic_radius_sqr(Geometry const& geometry)
+{
+ return formula_dispatch::authalic_radius_sqr<ResultType, Geometry>::apply(geometry);
+}
+
+} // namespace formula
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_FORMULAS_AUTHALIC_RADIUS_SQR_HPP
diff --git a/boost/geometry/formulas/elliptic_arc_length.hpp b/boost/geometry/formulas/elliptic_arc_length.hpp
new file mode 100644
index 0000000000..75881f3d0d
--- /dev/null
+++ b/boost/geometry/formulas/elliptic_arc_length.hpp
@@ -0,0 +1,214 @@
+// Boost.Geometry
+
+// Copyright (c) 2017 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Vissarion Fysikopoulos, 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_FORMULAS_ELLIPTIC_ARC_LENGTH_HPP
+#define BOOST_GEOMETRY_FORMULAS_ELLIPTIC_ARC_LENGTH_HPP
+
+#include <boost/math/constants/constants.hpp>
+
+#include <boost/geometry/core/radius.hpp>
+#include <boost/geometry/core/srs.hpp>
+
+#include <boost/geometry/util/condition.hpp>
+#include <boost/geometry/util/math.hpp>
+#include <boost/geometry/util/normalize_spheroidal_coordinates.hpp>
+
+#include <boost/geometry/formulas/flattening.hpp>
+
+namespace boost { namespace geometry { namespace formula
+{
+
+/*!
+\brief Compute the arc length of an ellipse.
+*/
+
+template <typename CT, unsigned int Order = 1>
+class elliptic_arc_length
+{
+
+public :
+
+ struct result
+ {
+ result()
+ : distance(0)
+ , meridian(false)
+ {}
+
+ CT distance;
+ bool meridian;
+ };
+
+ template <typename T, typename Spheroid>
+ static result apply(T lon1, T lat1, T lon2, T lat2, Spheroid const& spheroid)
+ {
+ result res;
+
+ CT c0 = 0;
+ CT pi = math::pi<CT>();
+ CT half_pi = pi/CT(2);
+ CT diff = geometry::math::longitude_distance_signed<geometry::radian>(lon1, lon2);
+
+ if (lat1 > lat2)
+ {
+ std::swap(lat1, lat2);
+ }
+
+ if ( math::equals(diff, c0) ||
+ (math::equals(lat2, half_pi) && math::equals(lat1, -half_pi)) )
+ {
+ // single meridian not crossing pole
+ res.distance = apply(lat2, spheroid) - apply(lat1, spheroid);
+ res.meridian = true;
+ }
+
+ if (math::equals(math::abs(diff), pi))
+ {
+ // meridian crosses pole
+ CT lat_sign = 1;
+ if (lat1+lat2 < c0)
+ {
+ lat_sign = CT(-1);
+ }
+ res.distance = math::abs(lat_sign * CT(2) * apply(half_pi, spheroid)
+ - apply(lat1, spheroid) - apply(lat2, spheroid));
+ res.meridian = true;
+ }
+ return res;
+ }
+
+ // Distance computation on meridians using series approximations
+ // to elliptic integrals. Formula to compute distance from lattitude 0 to lat
+ // https://en.wikipedia.org/wiki/Meridian_arc
+ // latitudes are assumed to be in radians and in [-pi/2,pi/2]
+ template <typename T, typename Spheroid>
+ static CT apply(T lat, Spheroid const& spheroid)
+ {
+ CT const a = get_radius<0>(spheroid);
+ CT const f = formula::flattening<CT>(spheroid);
+ CT n = f / (CT(2) - f);
+ CT M = a/(1+n);
+ CT C0 = 1;
+
+ if (Order == 0)
+ {
+ return M * C0 * lat;
+ }
+
+ CT C2 = -1.5 * n;
+
+ if (Order == 1)
+ {
+ return M * (C0 * lat + C2 * sin(2*lat));
+ }
+
+ CT n2 = n * n;
+ C0 += .25 * n2;
+ CT C4 = 0.9375 * n2;
+
+ if (Order == 2)
+ {
+ return M * (C0 * lat + C2 * sin(2*lat) + C4 * sin(4*lat));
+ }
+
+ CT n3 = n2 * n;
+ C2 += 0.1875 * n3;
+ CT C6 = -0.729166667 * n3;
+
+ if (Order == 3)
+ {
+ return M * (C0 * lat + C2 * sin(2*lat) + C4 * sin(4*lat)
+ + C6 * sin(6*lat));
+ }
+
+ CT n4 = n2 * n2;
+ C4 -= 0.234375 * n4;
+ CT C8 = 0.615234375 * n4;
+
+ if (Order == 4)
+ {
+ return M * (C0 * lat + C2 * sin(2*lat) + C4 * sin(4*lat)
+ + C6 * sin(6*lat) + C8 * sin(8*lat));
+ }
+
+ CT n5 = n4 * n;
+ C6 += 0.227864583 * n5;
+ CT C10 = -0.54140625 * n5;
+
+ // Order 5 or higher
+ return M * (C0 * lat + C2 * sin(2*lat) + C4 * sin(4*lat)
+ + C6 * sin(6*lat) + C8 * sin(8*lat) + C10 * sin(10*lat));
+
+ }
+
+ // Iterative method to elliptic arc length based on
+ // http://www.codeguru.com/cpp/cpp/algorithms/article.php/c5115/
+ // Geographic-Distance-and-Azimuth-Calculations.htm
+ // latitudes are assumed to be in radians and in [-pi/2,pi/2]
+ template <typename T1, typename T2, typename Spheroid>
+ CT interative_method(T1 lat1,
+ T2 lat2,
+ Spheroid const& spheroid)
+ {
+ CT result = 0;
+ CT const zero = 0;
+ CT const one = 1;
+ CT const c1 = 2;
+ CT const c2 = 0.5;
+ CT const c3 = 4000;
+
+ CT const a = get_radius<0>(spheroid);
+ CT const f = formula::flattening<CT>(spheroid);
+
+ // how many steps to use
+
+ CT lat1_deg = lat1 * geometry::math::r2d<CT>();
+ CT lat2_deg = lat2 * geometry::math::r2d<CT>();
+
+ int steps = c1 + (c2 + (lat2_deg > lat1_deg) ? CT(lat2_deg - lat1_deg)
+ : CT(lat1_deg - lat2_deg));
+ steps = (steps > c3) ? c3 : steps;
+
+ //std::cout << "Steps=" << steps << std::endl;
+
+ CT snLat1 = sin(lat1);
+ CT snLat2 = sin(lat2);
+ CT twoF = 2 * f - f * f;
+
+ // limits of integration
+ CT x1 = a * cos(lat1) /
+ sqrt(1 - twoF * snLat1 * snLat1);
+ CT x2 = a * cos(lat2) /
+ sqrt(1 - twoF * snLat2 * snLat2);
+
+ CT dx = (x2 - x1) / (steps - one);
+ CT x, y1, y2, dy, dydx;
+ CT adx = (dx < zero) ? -dx : dx; // absolute value of dx
+
+ CT a2 = a * a;
+ CT oneF = 1 - f;
+
+ // now loop through each step adding up all the little
+ // hypotenuses
+ for (int i = 0; i < (steps - 1); i++){
+ x = x1 + dx * i;
+ dydx = ((a * oneF * sqrt((one - ((x+dx)*(x+dx))/a2))) -
+ (a * oneF * sqrt((one - (x*x)/a2)))) / dx;
+ result += adx * sqrt(one + dydx*dydx);
+ }
+
+ return result;
+ }
+};
+
+}}} // namespace boost::geometry::formula
+
+
+#endif // BOOST_GEOMETRY_FORMULAS_ELLIPTIC_ARC_LENGTH_HPP
diff --git a/boost/geometry/formulas/geographic.hpp b/boost/geometry/formulas/geographic.hpp
index f6feb66633..b338273f30 100644
--- a/boost/geometry/formulas/geographic.hpp
+++ b/boost/geometry/formulas/geographic.hpp
@@ -1,6 +1,6 @@
// Boost.Geometry
-// Copyright (c) 2016, Oracle and/or its affiliates.
+// Copyright (c) 2016-2017, 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,
@@ -22,6 +22,7 @@
#include <boost/geometry/formulas/eccentricity_sqr.hpp>
#include <boost/geometry/formulas/flattening.hpp>
+#include <boost/geometry/formulas/unit_spheroid.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/normalize_spheroidal_coordinates.hpp>
@@ -186,7 +187,7 @@ inline Point3d projected_to_surface(Point3d const& direction, Spheroid const& sp
//coord_t const b_sqr = math::sqr(get_radius<2>(spheroid));
// "unit" spheroid, a = 1
coord_t const a_sqr = 1;
- coord_t const b_sqr = math::sqr(get_radius<2>(spheroid) / get_radius<0>(spheroid));
+ coord_t const b_sqr = math::sqr(formula::unit_spheroid_b<coord_t>(spheroid));
coord_t const param_a = (dx*dx + dy*dy) / a_sqr + dz*dz / b_sqr;
coord_t const delta = c4 * param_a;
@@ -226,7 +227,7 @@ inline bool projected_to_surface(Point3d const& origin, Point3d const& direction
//coord_t const b_sqr = math::sqr(get_radius<2>(spheroid));
// "unit" spheroid, a = 1
coord_t const a_sqr = 1;
- coord_t const b_sqr = math::sqr(get_radius<2>(spheroid) / get_radius<0>(spheroid));
+ coord_t const b_sqr = math::sqr(formula::unit_spheroid_b<coord_t>(spheroid));
coord_t const param_a = (dx*dx + dy*dy) / a_sqr + dz*dz / b_sqr;
coord_t const param_b = c2 * ((ox*dx + oy*dy) / a_sqr + oz*dz / b_sqr);
diff --git a/boost/geometry/formulas/mean_radius.hpp b/boost/geometry/formulas/mean_radius.hpp
new file mode 100644
index 0000000000..83c9b5403f
--- /dev/null
+++ b/boost/geometry/formulas/mean_radius.hpp
@@ -0,0 +1,71 @@
+// Boost.Geometry
+
+// Copyright (c) 2017 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_FORMULAS_MEAN_RADIUS_HPP
+#define BOOST_GEOMETRY_FORMULAS_MEAN_RADIUS_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 formula_dispatch
+{
+
+template <typename ResultType, typename Geometry, typename Tag = typename tag<Geometry>::type>
+struct mean_radius
+ : not_implemented<Tag>
+{};
+
+template <typename ResultType, typename Geometry>
+struct mean_radius<ResultType, Geometry, srs_sphere_tag>
+{
+ static inline ResultType apply(Geometry const& geometry)
+ {
+ return ResultType(get_radius<0>(geometry));
+ }
+};
+
+template <typename ResultType, typename Geometry>
+struct mean_radius<ResultType, Geometry, srs_spheroid_tag>
+{
+ static inline ResultType apply(Geometry const& geometry)
+ {
+ // (2*a + b) / 3
+ return (ResultType(2) * ResultType(get_radius<0>(geometry))
+ + ResultType(get_radius<2>(geometry)))
+ / ResultType(3);
+ }
+};
+
+} // namespace formula_dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace formula
+{
+
+template <typename ResultType, typename Geometry>
+inline ResultType mean_radius(Geometry const& geometry)
+{
+ return formula_dispatch::mean_radius<ResultType, Geometry>::apply(geometry);
+}
+
+} // namespace formula
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_FORMULAS_MEAN_RADIUS_HPP
diff --git a/boost/geometry/formulas/sjoberg_intersection.hpp b/boost/geometry/formulas/sjoberg_intersection.hpp
index 92f9e8e78e..665d90308e 100644
--- a/boost/geometry/formulas/sjoberg_intersection.hpp
+++ b/boost/geometry/formulas/sjoberg_intersection.hpp
@@ -1,6 +1,6 @@
// Boost.Geometry
-// Copyright (c) 2016 Oracle and/or its affiliates.
+// Copyright (c) 2016-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -19,6 +19,7 @@
#include <boost/geometry/util/condition.hpp>
#include <boost/geometry/util/math.hpp>
+#include <boost/geometry/util/normalize_spheroidal_coordinates.hpp>
#include <boost/geometry/formulas/flattening.hpp>
#include <boost/geometry/formulas/spherical.hpp>
@@ -97,10 +98,16 @@ private:
CT const sin_dlon1 = sin(dlon1);
CT const dlon2 = lon_b2 - lon2;
CT const sin_dlon2 = sin(dlon2);
-
+
+ CT const cos_dlon1 = cos(dlon1);
+ CT const cos_dlon2 = cos(dlon2);
+
+ CT const tan_alpha1_x = cos_lat1 * tan_lat_a2 - sin_lat1 * cos_dlon1;
+ CT const tan_alpha2_x = cos_lat2 * tan_lat_b2 - sin_lat2 * cos_dlon2;
+
CT const c0 = 0;
- bool const is_vertical1 = math::equals(sin_dlon1, c0);
- bool const is_vertical2 = math::equals(sin_dlon2, c0);
+ bool const is_vertical1 = math::equals(sin_dlon1, c0) || math::equals(tan_alpha1_x, c0);
+ bool const is_vertical2 = math::equals(sin_dlon2, c0) || math::equals(tan_alpha2_x, c0);
CT tan_alpha1 = 0;
CT tan_alpha2 = 0;
@@ -112,27 +119,18 @@ private:
}
else if (is_vertical1)
{
- CT const cos_dlon2 = cos(dlon2);
- CT const tan_alpha2_x = cos_lat2 * tan_lat_b2 - sin_lat2 * cos_dlon2;
tan_alpha2 = sin_dlon2 / tan_alpha2_x;
lon = lon1;
}
else if (is_vertical2)
{
- CT const cos_dlon1 = cos(dlon1);
- CT const tan_alpha1_x = cos_lat1 * tan_lat_a2 - sin_lat1 * cos_dlon1;
tan_alpha1 = sin_dlon1 / tan_alpha1_x;
lon = lon2;
}
else
{
- CT const cos_dlon1 = cos(dlon1);
- CT const cos_dlon2 = cos(dlon2);
-
- CT const tan_alpha1_x = cos_lat1 * tan_lat_a2 - sin_lat1 * cos_dlon1;
- CT const tan_alpha2_x = cos_lat2 * tan_lat_b2 - sin_lat2 * cos_dlon2;
tan_alpha1 = sin_dlon1 / tan_alpha1_x;
tan_alpha2 = sin_dlon2 / tan_alpha2_x;
@@ -761,16 +759,36 @@ public:
sjoberg_intersection_spherical_02<CT>::apply_alt(lon_a1, lat_a1, lon_a2, lat_a2,
lon_b1, lat_b1, lon_b2, lat_b2,
lon_sph, tan_lat_sph);
+
+ // Return for sphere
+ if (math::equals(f, c0))
+ {
+ lon = lon_sph;
+ lat = atan(tan_lat_sph);
+ return true;
+ }
+
t = one_minus_f * tan_lat_sph; // tan(beta)
- }
+ }
// TODO: no need to calculate atan here if reduced latitudes were used
// instead of latitudes above, in sjoberg_intersection_spherical_02
CT const beta = atan(t);
- if (enable_02 && newton_method(geod1, geod2, beta, t, lon1_minus_lon2, lon, lat))
+ if (enable_02 && newton_method(geod1, geod2, beta, t, lon1_minus_lon2, lon_sph, lon, lat))
{
- return true;
+ // TODO: Newton's method may return wrong result in some specific cases
+ // Detected for sphere and nearly sphere, e.g. A=6371228, B=6371227
+ // and segments s1=(-121 -19,37 8) and s2=(-19 -15,-104 -58)
+ // It's unclear if this is a bug or a characteristic of this method
+ // so until this is investigated check if the resulting longitude is
+ // between endpoints of the segments. It should be since before calling
+ // this formula sides of endpoints WRT other segments are checked.
+ if ( is_result_longitude_ok(geod1, lon_a1, lon_a2, lon)
+ && is_result_longitude_ok(geod2, lon_b1, lon_b2, lon) )
+ {
+ return true;
+ }
}
return converge_07(geod1, geod2, beta, t, lon1_minus_lon2, lon_sph, lon, lat);
@@ -778,7 +796,7 @@ public:
private:
static inline bool newton_method(geodesic_type const& geod1, geodesic_type const& geod2, // in
- CT beta, CT t, CT const& lon1_minus_lon2, // in
+ CT beta, CT t, CT const& lon1_minus_lon2, CT const& lon_sph, // in
CT & lon, CT & lat) // out
{
CT const c0 = 0;
@@ -789,6 +807,13 @@ private:
CT lon1_diff = 0;
CT lon2_diff = 0;
+ // The segment is vertical and intersection point is behind the vertex
+ // this method is unable to calculate correct result
+ if (geod1.is_Cj_zero && math::abs(geod1.lonj - lon_sph) > math::half_pi<CT>())
+ return false;
+ if (geod2.is_Cj_zero && math::abs(geod2.lonj - lon_sph) > math::half_pi<CT>())
+ return false;
+
CT abs_dbeta_last = 0;
// [Sjoberg02] converges faster than solution in [Sjoberg07]
@@ -882,6 +907,28 @@ private:
return true;
}
+ static inline bool is_result_longitude_ok(geodesic_type const& geod,
+ CT const& lon1, CT const& lon2, CT const& lon)
+ {
+ CT const c0 = 0;
+
+ if (geod.is_Cj_zero)
+ return true; // don't check vertical segment
+
+ CT dist1p = math::longitude_distance_signed<radian>(lon1, lon);
+ CT dist12 = math::longitude_distance_signed<radian>(lon1, lon2);
+
+ if (dist12 < c0)
+ {
+ dist1p = -dist1p;
+ dist12 = -dist12;
+ }
+
+ return (c0 <= dist1p && dist1p <= dist12)
+ || math::equals(dist1p, c0)
+ || math::equals(dist1p, dist12);
+ }
+
struct geodesics_type
{
geodesics_type(geodesic_type const& g1, geodesic_type const& g2)
diff --git a/boost/geometry/formulas/thomas_direct.hpp b/boost/geometry/formulas/thomas_direct.hpp
index f208167cf5..748960b01b 100644
--- a/boost/geometry/formulas/thomas_direct.hpp
+++ b/boost/geometry/formulas/thomas_direct.hpp
@@ -1,6 +1,6 @@
// Boost.Geometry
-// Copyright (c) 2016 Oracle and/or its affiliates.
+// Copyright (c) 2016-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -169,7 +169,8 @@ public:
{
CT const sigma2 = S_sigma - sigma1;
//theta2 = asin(cos(sigma2)) <=> sin_theta0 = 1
- CT const tan_theta2 = cos(sigma2) / sin(sigma2);
+ // NOTE: cos(sigma2) defines the sign of tan_theta2
+ CT const tan_theta2 = cos(sigma2) / math::abs(sin(sigma2));
result.lat2 = atan(tan_theta2 / one_minus_f);
}
@@ -177,7 +178,7 @@ public:
{
result.lat2 = -result.lat2;
}
- }
+ }
if (BOOST_GEOMETRY_CONDITION(CalcQuantities))
{
diff --git a/boost/geometry/formulas/unit_spheroid.hpp b/boost/geometry/formulas/unit_spheroid.hpp
new file mode 100644
index 0000000000..7fdedb4581
--- /dev/null
+++ b/boost/geometry/formulas/unit_spheroid.hpp
@@ -0,0 +1,43 @@
+// Boost.Geometry
+
+// Copyright (c) 2017 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_FORMULAS_UNIT_SPHEROID_HPP
+#define BOOST_GEOMETRY_FORMULAS_UNIT_SPHEROID_HPP
+
+#include <boost/geometry/core/radius.hpp>
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace formula
+{
+
+template <typename ResultType, typename Spheroid>
+inline ResultType unit_spheroid_b(Spheroid const& spheroid)
+{
+ return ResultType(get_radius<2>(spheroid))
+ / ResultType(get_radius<0>(spheroid));
+}
+
+template <typename ResultSpheroid, typename Spheroid>
+inline ResultSpheroid unit_spheroid(Spheroid const& spheroid)
+{
+ typedef typename radius_type<ResultSpheroid>::type radius_t;
+ return ResultSpheroid(radius_t(1),
+ unit_spheroid_b<radius_t>(spheroid));
+}
+
+} // namespace formula
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_FORMULAS_UNIT_SPHEROID_HPP
diff --git a/boost/geometry/geometries/helper_geometry.hpp b/boost/geometry/geometries/helper_geometry.hpp
index 9cf14a9117..f3102fee93 100644
--- a/boost/geometry/geometries/helper_geometry.hpp
+++ b/boost/geometry/geometries/helper_geometry.hpp
@@ -1,8 +1,9 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2015, Oracle and/or its affiliates.
+// Copyright (c) 2015-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
@@ -10,6 +11,8 @@
#ifndef BOOST_GEOMETRY_GEOMETRIES_HELPER_GEOMETRY_HPP
#define BOOST_GEOMETRY_GEOMETRIES_HELPER_GEOMETRY_HPP
+#include <boost/mpl/assert.hpp>
+
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
@@ -53,6 +56,14 @@ struct default_units<Geometry, cartesian_tag>
template <typename Units, typename CS_Tag>
struct cs_tag_to_coordinate_system
{
+ BOOST_MPL_ASSERT_MSG((false),
+ NOT_IMPLEMENTED_FOR_THIS_COORDINATE_SYSTEM,
+ (types<CS_Tag>));
+};
+
+template <typename Units>
+struct cs_tag_to_coordinate_system<Units, cartesian_tag>
+{
typedef cs::cartesian type;
};
@@ -63,7 +74,7 @@ struct cs_tag_to_coordinate_system<Units, spherical_equatorial_tag>
};
template <typename Units>
-struct cs_tag_to_coordinate_system<Units, spherical_tag>
+struct cs_tag_to_coordinate_system<Units, spherical_polar_tag>
{
typedef cs::spherical<Units> type;
};
diff --git a/boost/geometry/index/rtree.hpp b/boost/geometry/index/rtree.hpp
index 439880ad5a..fb3bbe8a47 100644
--- a/boost/geometry/index/rtree.hpp
+++ b/boost/geometry/index/rtree.hpp
@@ -817,7 +817,7 @@ public:
If predicates copy throws.
\warning
- Only one \c nearest() perdicate may be passed to the query. Passing more of them results in compile-time error.
+ Only one \c nearest() predicate may be passed to the query. Passing more of them results in compile-time error.
\param predicates Predicates.
\param out_it The output iterator, e.g. generated by std::back_inserter().
@@ -1082,7 +1082,7 @@ private:
method, which most certainly will be faster than the type-erased iterator, you may get the type
e.g. by using C++11 decltype or Boost.Typeof library.
- The type of the iterator returned by this method is dfferent than the type returned by qbegin().
+ The type of the iterator returned by this method is different than the type returned by qbegin().
\par Example
\verbatim
@@ -1965,7 +1965,7 @@ tree.query(bgi::intersects(box),
If Value copy constructor or copy assignment throws.
\warning
-Only one \c nearest() perdicate may be passed to the query. Passing more of them results in compile-time error.
+Only one \c nearest() predicate may be passed to the query. Passing more of them results in compile-time error.
\ingroup rtree_functions
diff --git a/boost/geometry/io/wkt/write.hpp b/boost/geometry/io/wkt/write.hpp
index b98c894b38..34af432fc6 100644
--- a/boost/geometry/io/wkt/write.hpp
+++ b/boost/geometry/io/wkt/write.hpp
@@ -1,12 +1,12 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// 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.
-// Copyright (c) 2014-2015 Adam Wulkiewicz, Lodz, Poland.
+// Copyright (c) 2007-2017 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2017 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2017 Mateusz Loskot, London, UK.
+// Copyright (c) 2014-2017 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2015.
-// Modifications copyright (c) 2015, Oracle and/or its affiliates.
+// Modifications copyright (c) 2015-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
@@ -111,7 +111,7 @@ template <typename Point, typename Policy>
struct wkt_point
{
template <typename Char, typename Traits>
- static inline void apply(std::basic_ostream<Char, Traits>& os, Point const& p)
+ static inline void apply(std::basic_ostream<Char, Traits>& os, Point const& p, bool)
{
os << Policy::apply() << "(";
stream_coordinate<Point, 0, dimension<Point>::type::value>::apply(os, p);
@@ -123,12 +123,18 @@ struct wkt_point
\brief Stream ranges as WKT
\note policy is used to stream prefix/postfix, enabling derived classes to override this
*/
-template <typename Range, typename PrefixPolicy, typename SuffixPolicy>
+template
+<
+ typename Range,
+ bool ForceClosurePossible,
+ typename PrefixPolicy,
+ typename SuffixPolicy
+>
struct wkt_range
{
template <typename Char, typename Traits>
static inline void apply(std::basic_ostream<Char, Traits>& os,
- Range const& range, bool force_closed)
+ Range const& range, bool force_closure = ForceClosurePossible)
{
typedef typename boost::range_iterator<Range const>::type iterator_type;
@@ -153,7 +159,8 @@ struct wkt_range
}
// optionally, close range to ring by repeating the first point
- if (force_closed
+ if (ForceClosurePossible
+ && force_closure
&& boost::size(range) > 1
&& detail::disjoint::disjoint_point_point(*begin, *(end - 1)))
{
@@ -164,12 +171,6 @@ struct wkt_range
os << SuffixPolicy::apply();
}
- template <typename Char, typename Traits>
- static inline void apply(std::basic_ostream<Char, Traits>& os,
- Range const& range)
- {
- apply(os, range, false);
- }
private:
typedef typename boost::range_value<Range>::type point_type;
@@ -179,11 +180,12 @@ private:
\brief Stream sequence of points as WKT-part, e.g. (1 2),(3 4)
\note Used in polygon, all multi-geometries
*/
-template <typename Range>
+template <typename Range, bool ForceClosurePossible = true>
struct wkt_sequence
: wkt_range
<
Range,
+ ForceClosurePossible,
opening_parenthesis,
closing_parenthesis
>
@@ -194,15 +196,14 @@ struct wkt_poly
{
template <typename Char, typename Traits>
static inline void apply(std::basic_ostream<Char, Traits>& os,
- Polygon const& poly)
+ Polygon const& poly, bool force_closure)
{
typedef typename ring_type<Polygon const>::type ring;
- bool const force_closed = true;
os << PrefixPolicy::apply();
// TODO: check EMPTY here
os << "(";
- wkt_sequence<ring>::apply(os, exterior_ring(poly), force_closed);
+ wkt_sequence<ring>::apply(os, exterior_ring(poly), force_closure);
typename interior_return_type<Polygon const>::type
rings = interior_rings(poly);
@@ -210,10 +211,11 @@ struct wkt_poly
it = boost::begin(rings); it != boost::end(rings); ++it)
{
os << ",";
- wkt_sequence<ring>::apply(os, *it, force_closed);
+ wkt_sequence<ring>::apply(os, *it, force_closure);
}
os << ")";
}
+
};
template <typename Multi, typename StreamPolicy, typename PrefixPolicy>
@@ -221,7 +223,7 @@ struct wkt_multi
{
template <typename Char, typename Traits>
static inline void apply(std::basic_ostream<Char, Traits>& os,
- Multi const& geometry)
+ Multi const& geometry, bool force_closure)
{
os << PrefixPolicy::apply();
// TODO: check EMPTY here
@@ -236,7 +238,7 @@ struct wkt_multi
{
os << ",";
}
- StreamPolicy::apply(os, *it);
+ StreamPolicy::apply(os, *it, force_closure);
}
os << ")";
@@ -250,15 +252,19 @@ struct wkt_box
template <typename Char, typename Traits>
static inline void apply(std::basic_ostream<Char, Traits>& os,
- Box const& box)
+ Box const& box, bool force_closure)
{
- // Convert to ring, then stream
- typedef model::ring<point_type> ring_type;
- ring_type ring;
- geometry::convert(box, ring);
- os << "POLYGON(";
- wkt_sequence<ring_type>::apply(os, ring);
- os << ")";
+ // Convert to a clockwire ring, then stream.
+ // Never close it based on last point (box might be empty and
+ // that should result in POLYGON((0 0,0 0,0 0,0 0, ...)) )
+ if (force_closure)
+ {
+ do_apply<model::ring<point_type, true, true> >(os, box);
+ }
+ else
+ {
+ do_apply<model::ring<point_type, true, false> >(os, box);
+ }
}
private:
@@ -268,6 +274,18 @@ struct wkt_box
// Only streaming of boxes with two dimensions is support, otherwise it is a polyhedron!
//assert_dimension<B, 2>();
}
+
+ template <typename RingType, typename Char, typename Traits>
+ static inline void do_apply(std::basic_ostream<Char, Traits>& os,
+ Box const& box)
+ {
+ RingType ring;
+ geometry::convert(box, ring);
+ os << "POLYGON(";
+ wkt_sequence<RingType, false>::apply(os, ring);
+ os << ")";
+ }
+
};
@@ -278,7 +296,7 @@ struct wkt_segment
template <typename Char, typename Traits>
static inline void apply(std::basic_ostream<Char, Traits>& os,
- Segment const& segment)
+ Segment const& segment, bool)
{
// Convert to two points, then stream
typedef boost::array<point_type, 2> sequence;
@@ -290,7 +308,7 @@ struct wkt_segment
// In Boost.Geometry a segment is represented
// in WKT-format like (for 2D): LINESTRING(x y,x y)
os << "LINESTRING";
- wkt_sequence<sequence>::apply(os, points);
+ wkt_sequence<sequence, false>::apply(os, points);
}
private:
@@ -324,6 +342,7 @@ struct wkt<Linestring, linestring_tag>
: detail::wkt::wkt_range
<
Linestring,
+ false,
detail::wkt::prefix_linestring_par,
detail::wkt::closing_parenthesis
>
@@ -355,6 +374,7 @@ struct wkt<Ring, ring_tag>
: detail::wkt::wkt_range
<
Ring,
+ true,
detail::wkt::prefix_ring_par_par,
detail::wkt::double_closing_parenthesis
>
@@ -393,7 +413,8 @@ struct wkt<Multi, multi_linestring_tag>
Multi,
detail::wkt::wkt_sequence
<
- typename boost::range_value<Multi>::type
+ typename boost::range_value<Multi>::type,
+ false
>,
detail::wkt::prefix_multilinestring
>
@@ -418,9 +439,10 @@ template <typename Geometry>
struct devarianted_wkt
{
template <typename OutputStream>
- static inline void apply(OutputStream& os, Geometry const& geometry)
+ static inline void apply(OutputStream& os, Geometry const& geometry,
+ bool force_closure)
{
- wkt<Geometry>::apply(os, geometry);
+ wkt<Geometry>::apply(os, geometry, force_closure);
}
};
@@ -431,25 +453,27 @@ struct devarianted_wkt<variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
struct visitor: static_visitor<void>
{
OutputStream& m_os;
+ bool m_force_closure;
- visitor(OutputStream& os)
+ visitor(OutputStream& os, bool force_closure)
: m_os(os)
+ , m_force_closure(force_closure)
{}
template <typename Geometry>
inline void operator()(Geometry const& geometry) const
{
- devarianted_wkt<Geometry>::apply(m_os, geometry);
+ devarianted_wkt<Geometry>::apply(m_os, geometry, m_force_closure);
}
};
template <typename OutputStream>
static inline void apply(
OutputStream& os,
- variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry
- )
+ variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
+ bool force_closure)
{
- boost::apply_visitor(visitor<OutputStream>(os), geometry);
+ boost::apply_visitor(visitor<OutputStream>(os, force_closure), geometry);
}
};
@@ -471,10 +495,16 @@ Small example showing how to use the wkt class
template <typename Geometry>
class wkt_manipulator
{
+ static const bool is_ring = boost::is_same<typename tag<Geometry>::type, ring_tag>::value;
+
public:
- inline wkt_manipulator(Geometry const& g)
+ // Boost.Geometry, by default, closes polygons explictly, but not rings
+ // NOTE: this might change in the future!
+ inline wkt_manipulator(Geometry const& g,
+ bool force_closure = ! is_ring)
: m_geometry(g)
+ , m_force_closure(force_closure)
{}
template <typename Char, typename Traits>
@@ -482,13 +512,14 @@ public:
std::basic_ostream<Char, Traits>& os,
wkt_manipulator const& m)
{
- dispatch::devarianted_wkt<Geometry>::apply(os, m.m_geometry);
+ dispatch::devarianted_wkt<Geometry>::apply(os, m.m_geometry, m.m_force_closure);
os.flush();
return os;
}
private:
Geometry const& m_geometry;
+ bool m_force_closure;
};
/*!
diff --git a/boost/geometry/policies/compare.hpp b/boost/geometry/policies/compare.hpp
index 2e952d3e15..7f32b7ab30 100644
--- a/boost/geometry/policies/compare.hpp
+++ b/boost/geometry/policies/compare.hpp
@@ -2,6 +2,11 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// This file was modified by Oracle on 2017.
+// Modifications copyright (c) 2017, 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)
@@ -20,170 +25,56 @@ namespace boost { namespace geometry
{
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace compare
-{
-
-
-template
-<
- int Direction,
- typename Point,
- typename Strategy,
- std::size_t Dimension,
- std::size_t DimensionCount
->
-struct compare_loop
-{
- typedef typename strategy::compare::detail::select_strategy
- <
- Strategy, Direction, Point, Dimension
- >::type compare_type;
-
- typedef typename geometry::coordinate_type<Point>::type coordinate_type;
-
- static inline bool apply(Point const& left, Point const& right)
- {
- coordinate_type const& cleft = geometry::get<Dimension>(left);
- coordinate_type const& cright = geometry::get<Dimension>(right);
-
- if (geometry::math::equals(cleft, cright))
- {
- return compare_loop
- <
- Direction, Point, Strategy,
- Dimension + 1, DimensionCount
- >::apply(left, right);
- }
- else
- {
- compare_type compare;
- return compare(cleft, cright);
- }
- }
-};
-
-template
-<
- int Direction,
- typename Point,
- typename Strategy,
- std::size_t DimensionCount
->
-struct compare_loop<Direction, Point, Strategy, DimensionCount, DimensionCount>
-{
- static inline bool apply(Point const&, Point const&)
- {
- // On coming here, points are equal. Return true if
- // direction = 0 (equal), false if -1/1 (greater/less)
- return Direction == 0;
- }
-};
-
-
-template <int Direction, typename Point, typename Strategy>
-struct compare_in_all_dimensions
-{
- inline bool operator()(Point const& left, Point const& right) const
- {
- return detail::compare::compare_loop
- <
- Direction, Point, Strategy,
- 0, geometry::dimension<Point>::type::value
- >::apply(left, right);
- }
-};
-
-
-template <typename Point, typename Strategy, std::size_t Dimension>
-class compare_in_one_dimension
-{
- Strategy compare;
-
-public :
- inline bool operator()(Point const& left, Point const& right) const
- {
- typedef typename geometry::coordinate_type<Point>::type coordinate_type;
-
- coordinate_type const& cleft = get<Dimension>(left);
- coordinate_type const& cright = get<Dimension>(right);
- return compare(cleft, cright);
- }
-};
-
-}} // namespace detail::compare
-
-#endif
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-template
-<
- int Direction,
- typename Point,
- typename Strategy,
- int Dimension
->
-struct compare_geometries
- : detail::compare::compare_in_one_dimension
- <
- Point,
- typename strategy::compare::detail::select_strategy
- <
- Strategy, Direction, Point, Dimension
- >::type,
- Dimension
- >
-{};
-
-
-// Specialization with -1: compare in all dimensions
-template <int Direction, typename Point, typename Strategy>
-struct compare_geometries<Direction, Point, Strategy, -1>
- : detail::compare::compare_in_all_dimensions<Direction, Point, Strategy>
-{};
-
-
-
-} // namespace dispatch
-#endif // DOXYGEN_NO_DISPATCH
-
-
/*!
\brief Less functor, to sort points in ascending order.
\ingroup compare
\details This functor compares points and orders them on x,
then on y, then on z coordinate.
-\tparam Geometry the geometry
+\tparam Point the geometry
\tparam Dimension the dimension to sort on, defaults to -1,
indicating ALL dimensions. That's to say, first on x,
on equal x-es then on y, etc.
If a dimension is specified, only that dimension is considered
-\tparam Strategy underlying coordinate comparing functor,
- defaults to the default comparison strategies
- related to the point coordinate system. If specified, the specified
- strategy is used. This can e.g. be std::less<double>.
*/
template
<
- typename Point,
- int Dimension = -1,
- typename Strategy = strategy::compare::default_strategy
+ typename Point = void,
+ int Dimension = -1
>
struct less
- : dispatch::compare_geometries
- <
- 1, // indicates ascending
- Point,
- Strategy,
- Dimension
- >
{
typedef Point first_argument_type;
typedef Point second_argument_type;
typedef bool result_type;
+
+ inline bool operator()(Point const& left, Point const& right) const
+ {
+ typedef typename strategy::compare::services::default_strategy
+ <
+ strategy::compare::less,
+ Point, Point,
+ Dimension
+ >::type strategy_type;
+
+ return strategy_type::apply(left, right);
+ }
+};
+
+template <int Dimension>
+struct less<void, Dimension>
+{
+ template <typename Point1, typename Point2>
+ inline bool operator()(Point1 const& left, Point2 const& right) const
+ {
+ typedef typename strategy::compare::services::default_strategy
+ <
+ strategy::compare::less,
+ Point1, Point2,
+ Dimension
+ >::type strategy_type;
+
+ return strategy_type::apply(left, right);
+ }
};
@@ -195,19 +86,44 @@ struct less
*/
template
<
- typename Point,
- int Dimension = -1,
- typename Strategy = strategy::compare::default_strategy
+ typename Point = void,
+ int Dimension = -1
>
struct greater
- : dispatch::compare_geometries
- <
- -1, // indicates descending
- Point,
- Strategy,
- Dimension
- >
-{};
+{
+ typedef Point first_argument_type;
+ typedef Point second_argument_type;
+ typedef bool result_type;
+
+ bool operator()(Point const& left, Point const& right) const
+ {
+ typedef typename strategy::compare::services::default_strategy
+ <
+ strategy::compare::greater,
+ Point, Point,
+ Dimension
+ >::type strategy_type;
+
+ return strategy_type::apply(left, right);
+ }
+};
+
+template <int Dimension>
+struct greater<void, Dimension>
+{
+ template <typename Point1, typename Point2>
+ bool operator()(Point1 const& left, Point2 const& right) const
+ {
+ typedef typename strategy::compare::services::default_strategy
+ <
+ strategy::compare::greater,
+ Point1, Point2,
+ Dimension
+ >::type strategy_type;
+
+ return strategy_type::apply(left, right);
+ }
+};
/*!
@@ -217,23 +133,47 @@ struct greater
\tparam Dimension the dimension to compare on, defaults to -1,
indicating ALL dimensions.
If a dimension is specified, only that dimension is considered
-\tparam Strategy underlying coordinate comparing functor
*/
template
<
typename Point,
- int Dimension = -1,
- typename Strategy = strategy::compare::default_strategy
+ int Dimension = -1
>
struct equal_to
- : dispatch::compare_geometries
- <
- 0,
- Point,
- Strategy,
- Dimension
- >
-{};
+{
+ typedef Point first_argument_type;
+ typedef Point second_argument_type;
+ typedef bool result_type;
+
+ bool operator()(Point const& left, Point const& right) const
+ {
+ typedef typename strategy::compare::services::default_strategy
+ <
+ strategy::compare::equal_to,
+ Point, Point,
+ Dimension
+ >::type strategy_type;
+
+ return strategy_type::apply(left, right);
+ }
+};
+
+template <int Dimension>
+struct equal_to<void, Dimension>
+{
+ template <typename Point1, typename Point2>
+ bool operator()(Point1 const& left, Point2 const& right) const
+ {
+ typedef typename strategy::compare::services::default_strategy
+ <
+ strategy::compare::equal_to,
+ Point1, Point2,
+ Dimension
+ >::type strategy_type;
+
+ return strategy_type::apply(left, right);
+ }
+};
}} // namespace boost::geometry
diff --git a/boost/geometry/strategies/agnostic/buffer_distance_symmetric.hpp b/boost/geometry/strategies/agnostic/buffer_distance_symmetric.hpp
index 73bd21ac73..fe973e3f38 100644
--- a/boost/geometry/strategies/agnostic/buffer_distance_symmetric.hpp
+++ b/boost/geometry/strategies/agnostic/buffer_distance_symmetric.hpp
@@ -68,7 +68,7 @@ public :
return negative() ? -1 : 1;
}
- //! Returns true if distance is negative
+ //! Returns true if distance is negative (aka deflate)
inline bool negative() const
{
return m_distance < 0;
diff --git a/boost/geometry/strategies/agnostic/point_in_point.hpp b/boost/geometry/strategies/agnostic/point_in_point.hpp
index 1a9274149a..d4692766c5 100644
--- a/boost/geometry/strategies/agnostic/point_in_point.hpp
+++ b/boost/geometry/strategies/agnostic/point_in_point.hpp
@@ -32,7 +32,7 @@ struct point_in_point
{
static inline bool apply(Point1 const& point1, Point2 const& point2)
{
- return detail::equals::equals_point_point(point1, point2);
+ return geometry::detail::equals::equals_point_point(point1, point2);
}
};
diff --git a/boost/geometry/strategies/agnostic/point_in_poly_winding.hpp b/boost/geometry/strategies/agnostic/point_in_poly_winding.hpp
index 0a797ac0f0..774294b57e 100644
--- a/boost/geometry/strategies/agnostic/point_in_poly_winding.hpp
+++ b/boost/geometry/strategies/agnostic/point_in_poly_winding.hpp
@@ -18,14 +18,15 @@
#define BOOST_GEOMETRY_STRATEGY_AGNOSTIC_POINT_IN_POLY_WINDING_HPP
-#include <boost/core/ignore_unused.hpp>
+#include <boost/mpl/assert.hpp>
-#include <boost/geometry/util/math.hpp>
-#include <boost/geometry/util/select_calculation_type.hpp>
+#include <boost/geometry/core/cs.hpp>
+#include <boost/geometry/core/tag_cast.hpp>
+#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/strategies/cartesian/point_in_poly_winding.hpp>
#include <boost/geometry/strategies/side.hpp>
-#include <boost/geometry/strategies/covered_by.hpp>
-#include <boost/geometry/strategies/within.hpp>
+#include <boost/geometry/strategies/spherical/point_in_poly_winding.hpp>
namespace boost { namespace geometry
@@ -34,292 +35,63 @@ namespace boost { namespace geometry
namespace strategy { namespace within
{
-// 1 deg or pi/180 rad
-template <typename Point,
- typename CalculationType = typename coordinate_type<Point>::type>
-struct winding_small_angle
-{
- typedef typename coordinate_system<Point>::type cs_t;
- typedef math::detail::constants_on_spheroid
- <
- CalculationType,
- typename cs_t::units
- > constants;
-
- static inline CalculationType apply()
- {
- return constants::half_period() / CalculationType(180);
- }
-};
-
-// Fix for https://svn.boost.org/trac/boost/ticket/9628
-// For floating point coordinates, the <D> coordinate of a point is compared
-// with the segment's points using some EPS. If the coordinates are "equal"
-// the sides are calculated. Therefore we can treat a segment as a long areal
-// geometry having some width. There is a small ~triangular area somewhere
-// between the segment's effective area and a segment's line used in sides
-// calculation where the segment is on the one side of the line but on the
-// other side of a segment (due to the width).
-// Below picture assuming D = 1, if D = 0 horiz<->vert, E<->N, RIGHT<->UP.
-// For the s1 of a segment going NE the real side is RIGHT but the point may
-// be detected as LEFT, like this:
-// RIGHT
-// ___----->
-// ^ O Pt __ __
-// EPS __ __
-// v__ __ BUT DETECTED AS LEFT OF THIS LINE
-// _____7
-// _____/
-// _____/
-// In the code below actually D = 0, so segments are nearly-vertical
-// Called when the point is on the same level as one of the segment's points
-// but the point is not aligned with a vertical segment
-template <typename CSTag>
-struct winding_side_equal
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail
{
- typedef typename strategy::side::services::default_strategy
- <
- CSTag
- >::type strategy_side_type;
-
- template <typename Point, typename PointOfSegment>
- static inline int apply(Point const& point,
- PointOfSegment const& se,
- int count)
- {
- typedef typename coordinate_type<PointOfSegment>::type scoord_t;
- typedef typename coordinate_system<PointOfSegment>::type::units units_t;
- if (math::equals(get<1>(point), get<1>(se)))
- return 0;
- // Create a horizontal segment intersecting the original segment's endpoint
- // equal to the point, with the derived direction (E/W).
- PointOfSegment ss1, ss2;
- set<1>(ss1, get<1>(se));
- set<0>(ss1, get<0>(se));
- set<1>(ss2, get<1>(se));
- scoord_t ss20 = get<0>(se);
- if (count > 0)
- {
- ss20 += winding_small_angle<PointOfSegment>::apply();
- }
- else
- {
- ss20 -= winding_small_angle<PointOfSegment>::apply();
- }
- math::normalize_longitude<units_t>(ss20);
- set<0>(ss2, ss20);
-
- // Check the side using this vertical segment
- return strategy_side_type::apply(ss1, ss2, point);
- }
-};
-// The optimization for cartesian
-template <>
-struct winding_side_equal<cartesian_tag>
+template
+<
+ typename Point,
+ typename PointOfSegment,
+ typename CalculationType,
+ typename CSTag = typename tag_cast
+ <
+ typename cs_tag<Point>::type,
+ spherical_tag
+ >::type
+>
+struct winding_base_type
{
- template <typename Point, typename PointOfSegment>
- static inline int apply(Point const& point,
- PointOfSegment const& se,
- int count)
- {
- // NOTE: for D=0 the signs would be reversed
- return math::equals(get<1>(point), get<1>(se)) ?
- 0 :
- get<1>(point) < get<1>(se) ?
- // assuming count is equal to 1 or -1
- -count : // ( count > 0 ? -1 : 1) :
- count; // ( count > 0 ? 1 : -1) ;
- }
+ BOOST_MPL_ASSERT_MSG(false,
+ NOT_IMPLEMENTED_FOR_THIS_COORDINATE_SYSTEM,
+ (CSTag));
};
-
-template <typename Point,
- typename CalculationType,
- typename CSTag = typename cs_tag<Point>::type>
-struct winding_check_touch
+template <typename Point, typename PointOfSegment, typename CalculationType>
+struct winding_base_type<Point, PointOfSegment, CalculationType, cartesian_tag>
{
- typedef CalculationType calc_t;
- typedef typename coordinate_system<Point>::type::units units_t;
- typedef math::detail::constants_on_spheroid<CalculationType, units_t> constants;
-
- template <typename PointOfSegment, typename State>
- static inline int apply(Point const& point,
- PointOfSegment const& seg1,
- PointOfSegment const& seg2,
- State& state,
- bool& eq1,
- bool& eq2)
- {
- calc_t const pi = constants::half_period();
- calc_t const pi2 = pi / calc_t(2);
-
- calc_t const px = get<0>(point);
- calc_t const s1x = get<0>(seg1);
- calc_t const s2x = get<0>(seg2);
- calc_t const py = get<1>(point);
- calc_t const s1y = get<1>(seg1);
- calc_t const s2y = get<1>(seg2);
-
- // NOTE: lat in {-90, 90} and arbitrary lon
- // it doesn't matter what lon it is if it's a pole
- // so e.g. if one of the segment endpoints is a pole
- // then only the other lon matters
-
- bool eq1_strict = math::equals(s1x, px);
- bool eq2_strict = math::equals(s2x, px);
-
- eq1 = eq1_strict // lon strictly equal to s1
- || math::equals(s1y, pi2) || math::equals(s1y, -pi2); // s1 is pole
- eq2 = eq2_strict // lon strictly equal to s2
- || math::equals(s2y, pi2) || math::equals(s2y, -pi2); // s2 is pole
-
- // segment overlapping pole
- calc_t s1x_anti = s1x + constants::half_period();
- math::normalize_longitude<units_t, calc_t>(s1x_anti);
- bool antipodal = math::equals(s2x, s1x_anti);
- if (antipodal)
- {
- eq1 = eq2 = eq1 || eq2;
-
- // segment overlapping pole and point is pole
- if (math::equals(py, pi2) || math::equals(py, -pi2))
- {
- eq1 = eq2 = true;
- }
- }
-
- // Both equal p -> segment vertical
- // The only thing which has to be done is check if point is ON segment
- if (eq1 && eq2)
- {
- // segment endpoints on the same sides of the globe
- if (! antipodal
- // p's lat between segment endpoints' lats
- ? (s1y <= py && s2y >= py) || (s2y <= py && s1y >= py)
- // going through north or south pole?
- : (pi - s1y - s2y <= pi
- ? (eq1_strict && s1y <= py) || (eq2_strict && s2y <= py) // north
- || math::equals(py, pi2) // point on north pole
- : (eq1_strict && s1y >= py) || (eq2_strict && s2y >= py)) // south
- || math::equals(py, -pi2) // point on south pole
- )
- {
- state.m_touches = true;
- }
- return true;
- }
- return false;
- }
-};
-// The optimization for cartesian
-template <typename Point, typename CalculationType>
-struct winding_check_touch<Point, CalculationType, cartesian_tag>
-{
- typedef CalculationType calc_t;
-
- template <typename PointOfSegment, typename State>
- static inline bool apply(Point const& point,
- PointOfSegment const& seg1,
- PointOfSegment const& seg2,
- State& state,
- bool& eq1,
- bool& eq2)
- {
- calc_t const px = get<0>(point);
- calc_t const s1x = get<0>(seg1);
- calc_t const s2x = get<0>(seg2);
-
- eq1 = math::equals(s1x, px);
- eq2 = math::equals(s2x, px);
-
- // Both equal p -> segment vertical
- // The only thing which has to be done is check if point is ON segment
- if (eq1 && eq2)
- {
- calc_t const py = get<1>(point);
- calc_t const s1y = get<1>(seg1);
- calc_t const s2y = get<1>(seg2);
- if ((s1y <= py && s2y >= py) || (s2y <= py && s1y >= py))
- {
- state.m_touches = true;
- }
- return true;
- }
- return false;
- }
+ typedef within::cartesian_winding<Point, PointOfSegment, CalculationType> type;
};
-
-// Called if point is not aligned with a vertical segment
-template <typename Point,
- typename CalculationType,
- typename CSTag = typename cs_tag<Point>::type>
-struct winding_calculate_count
+template <typename Point, typename PointOfSegment, typename CalculationType>
+struct winding_base_type<Point, PointOfSegment, CalculationType, spherical_tag>
{
- typedef CalculationType calc_t;
- typedef typename coordinate_system<Point>::type::units units_t;
-
- static inline bool greater(calc_t const& l, calc_t const& r)
- {
- calc_t diff = l - r;
- math::normalize_longitude<units_t, calc_t>(diff);
- return diff > calc_t(0);
- }
-
- static inline int apply(calc_t const& p,
- calc_t const& s1, calc_t const& s2,
- bool eq1, bool eq2)
- {
- // Probably could be optimized by avoiding normalization for some comparisons
- // e.g. s1 > p could be calculated from p > s1
+ typedef within::detail::spherical_winding_base
+ <
+ Point,
+ PointOfSegment,
+ typename strategy::side::services::default_strategy
+ <
+ typename cs_tag<Point>::type
+ >::type,
+ CalculationType
+ > type;
+};
- // If both segment endpoints were poles below checks wouldn't be enough
- // but this means that either both are the same or that they are N/S poles
- // and therefore the segment is not valid.
- // If needed (eq1 && eq2 ? 0) could be returned
- return
- eq1 ? (greater(s2, p) ? 1 : -1) // Point on level s1, E/W depending on s2
- : eq2 ? (greater(s1, p) ? -1 : 1) // idem
- : greater(p, s1) && greater(s2, p) ? 2 // Point between s1 -> s2 --> E
- : greater(p, s2) && greater(s1, p) ? -2 // Point between s2 -> s1 --> W
- : 0;
- }
-};
-// The optimization for cartesian
-template <typename Point, typename CalculationType>
-struct winding_calculate_count<Point, CalculationType, cartesian_tag>
-{
- typedef CalculationType calc_t;
-
- static inline int apply(calc_t const& p,
- calc_t const& s1, calc_t const& s2,
- bool eq1, bool eq2)
- {
- return
- eq1 ? (s2 > p ? 1 : -1) // Point on level s1, E/W depending on s2
- : eq2 ? (s1 > p ? -1 : 1) // idem
- : s1 < p && s2 > p ? 2 // Point between s1 -> s2 --> E
- : s2 < p && s1 > p ? -2 // Point between s2 -> s1 --> W
- : 0;
- }
-};
+} // namespace detail
+#endif // DOXYGEN_NO_DETAIL
/*!
-\brief Within detection using winding rule
+\brief Within detection using winding rule. Side strategy used internally is
+ choosen based on Point's coordinate system.
\ingroup strategies
\tparam Point \tparam_point
\tparam PointOfSegment \tparam_segment_point
-\tparam SideStrategy Side strategy
\tparam CalculationType \tparam_calculation
-\author Barend Gehrels
-\note The implementation is inspired by terralib http://www.terralib.org (LGPL)
-\note but totally revised afterwards, especially for cases on segments
-\note Only dependant on "side", -> agnostic, suitable for spherical/latlong
\qbk{
[heading See also]
@@ -330,245 +102,32 @@ template
<
typename Point,
typename PointOfSegment = Point,
- typename SideStrategy = typename strategy::side::services::default_strategy
- <
- typename cs_tag<Point>::type
- >::type,
typename CalculationType = void
>
class winding
+ : public within::detail::winding_base_type
+ <
+ Point, PointOfSegment, CalculationType
+ >::type
{
- typedef typename select_calculation_type
+ typedef typename within::detail::winding_base_type
<
- Point,
- PointOfSegment,
- CalculationType
- >::type calculation_type;
-
- /*! subclass to keep state */
- class counter
- {
- int m_count;
- bool m_touches;
-
- inline int code() const
- {
- return m_touches ? 0 : m_count == 0 ? -1 : 1;
- }
-
- public :
- friend class winding;
-
- template <typename P, typename CT, typename CST>
- friend struct winding_check_touch;
-
- inline counter()
- : m_count(0)
- , m_touches(false)
- {}
-
- };
-
- static inline int check_segment(Point const& point,
- PointOfSegment const& seg1, PointOfSegment const& seg2,
- counter& state, bool& eq1, bool& eq2)
- {
- if (winding_check_touch<Point, calculation_type>
- ::apply(point, seg1, seg2, state, eq1, eq2))
- {
- return 0;
- }
-
- calculation_type const p = get<0>(point);
- calculation_type const s1 = get<0>(seg1);
- calculation_type const s2 = get<0>(seg2);
- return winding_calculate_count<Point, calculation_type>
- ::apply(p, s1, s2, eq1, eq2);
- }
-
+ Point, PointOfSegment, CalculationType
+ >::type base_t;
public:
- typedef typename SideStrategy::envelope_strategy_type envelope_strategy_type;
-
- inline envelope_strategy_type get_envelope_strategy() const
- {
- return m_side_strategy.get_envelope_strategy();
- }
+ winding() {}
- typedef typename SideStrategy::disjoint_strategy_type disjoint_strategy_type;
-
- inline disjoint_strategy_type get_disjoint_strategy() const
- {
- return m_side_strategy.get_disjoint_strategy();
- }
-
- winding()
- {}
-
- explicit winding(SideStrategy const& side_strategy)
- : m_side_strategy(side_strategy)
+ template <typename Model>
+ explicit winding(Model const& model)
+ : base_t(model)
{}
-
- // Typedefs and static methods to fulfill the concept
- typedef Point point_type;
- typedef PointOfSegment segment_point_type;
- typedef counter state_type;
-
- inline bool apply(Point const& point,
- PointOfSegment const& s1, PointOfSegment const& s2,
- counter& state) const
- {
- typedef typename cs_tag<Point>::type cs_t;
-
- bool eq1 = false;
- bool eq2 = false;
- boost::ignore_unused(eq2);
-
- int count = check_segment(point, s1, s2, state, eq1, eq2);
- if (count != 0)
- {
- int side = 0;
- if (count == 1 || count == -1)
- {
- side = winding_side_equal<cs_t>::apply(point, eq1 ? s1 : s2, count);
- }
- else // count == 2 || count == -2
- {
- // 1 left, -1 right
- side = m_side_strategy.apply(s1, s2, point);
- }
-
- if (side == 0)
- {
- // Point is lying on segment
- state.m_touches = true;
- state.m_count = 0;
- return false;
- }
-
- // Side is NEG for right, POS for left.
- // The count is -2 for down, 2 for up (or -1/1)
- // Side positive thus means UP and LEFTSIDE or DOWN and RIGHTSIDE
- // See accompagnying figure (TODO)
- if (side * count > 0)
- {
- state.m_count += count;
- }
- }
- return ! state.m_touches;
- }
-
- static inline int result(counter const& state)
- {
- return state.code();
- }
-
-private:
- SideStrategy m_side_strategy;
-};
-
-
-#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
-
-namespace services
-{
-
-template <typename PointLike, typename Geometry, typename AnyTag1, typename AnyTag2>
-struct default_strategy<PointLike, Geometry, AnyTag1, AnyTag2, pointlike_tag, polygonal_tag, cartesian_tag, cartesian_tag>
-{
- typedef winding
- <
- typename geometry::point_type<PointLike>::type,
- typename geometry::point_type<Geometry>::type
- > type;
};
-template <typename PointLike, typename Geometry, typename AnyTag1, typename AnyTag2>
-struct default_strategy<PointLike, Geometry, AnyTag1, AnyTag2, pointlike_tag, polygonal_tag, spherical_tag, spherical_tag>
-{
- typedef winding
- <
- typename geometry::point_type<PointLike>::type,
- typename geometry::point_type<Geometry>::type
- > type;
-};
-
-template <typename PointLike, typename Geometry, typename AnyTag1, typename AnyTag2>
-struct default_strategy<PointLike, Geometry, AnyTag1, AnyTag2, pointlike_tag, linear_tag, cartesian_tag, cartesian_tag>
-{
- typedef winding
- <
- typename geometry::point_type<PointLike>::type,
- typename geometry::point_type<Geometry>::type
- > type;
-};
-
-template <typename PointLike, typename Geometry, typename AnyTag1, typename AnyTag2>
-struct default_strategy<PointLike, Geometry, AnyTag1, AnyTag2, pointlike_tag, linear_tag, spherical_tag, spherical_tag>
-{
- typedef winding
- <
- typename geometry::point_type<PointLike>::type,
- typename geometry::point_type<Geometry>::type
- > type;
-};
-
-} // namespace services
-
-#endif
-
}} // namespace strategy::within
-#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
-namespace strategy { namespace covered_by { namespace services
-{
-
-template <typename PointLike, typename Geometry, typename AnyTag1, typename AnyTag2>
-struct default_strategy<PointLike, Geometry, AnyTag1, AnyTag2, pointlike_tag, polygonal_tag, cartesian_tag, cartesian_tag>
-{
- typedef within::winding
- <
- typename geometry::point_type<PointLike>::type,
- typename geometry::point_type<Geometry>::type
- > type;
-};
-
-template <typename PointLike, typename Geometry, typename AnyTag1, typename AnyTag2>
-struct default_strategy<PointLike, Geometry, AnyTag1, AnyTag2, pointlike_tag, polygonal_tag, spherical_tag, spherical_tag>
-{
- typedef within::winding
- <
- typename geometry::point_type<PointLike>::type,
- typename geometry::point_type<Geometry>::type
- > type;
-};
-
-template <typename PointLike, typename Geometry, typename AnyTag1, typename AnyTag2>
-struct default_strategy<PointLike, Geometry, AnyTag1, AnyTag2, pointlike_tag, linear_tag, cartesian_tag, cartesian_tag>
-{
- typedef within::winding
- <
- typename geometry::point_type<PointLike>::type,
- typename geometry::point_type<Geometry>::type
- > type;
-};
-
-template <typename PointLike, typename Geometry, typename AnyTag1, typename AnyTag2>
-struct default_strategy<PointLike, Geometry, AnyTag1, AnyTag2, pointlike_tag, linear_tag, spherical_tag, spherical_tag>
-{
- typedef within::winding
- <
- typename geometry::point_type<PointLike>::type,
- typename geometry::point_type<Geometry>::type
- > type;
-};
-
-}}} // namespace strategy::covered_by::services
-#endif
-
-
}} // namespace boost::geometry
diff --git a/boost/geometry/strategies/cartesian/intersection.hpp b/boost/geometry/strategies/cartesian/intersection.hpp
index 50e903885b..233bb50b64 100644
--- a/boost/geometry/strategies/cartesian/intersection.hpp
+++ b/boost/geometry/strategies/cartesian/intersection.hpp
@@ -33,10 +33,10 @@
#include <boost/geometry/util/promote_integral.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
-#include <boost/geometry/strategies/agnostic/point_in_poly_winding.hpp>
#include <boost/geometry/strategies/cartesian/area_surveyor.hpp>
#include <boost/geometry/strategies/cartesian/distance_pythagoras.hpp>
#include <boost/geometry/strategies/cartesian/envelope_segment.hpp>
+#include <boost/geometry/strategies/cartesian/point_in_poly_winding.hpp>
#include <boost/geometry/strategies/cartesian/side_by_triangle.hpp>
#include <boost/geometry/strategies/covered_by.hpp>
#include <boost/geometry/strategies/intersection.hpp>
@@ -81,11 +81,10 @@ struct cartesian_segments
template <typename Geometry1, typename Geometry2>
struct point_in_geometry_strategy
{
- typedef strategy::within::winding
+ typedef strategy::within::cartesian_winding
<
typename point_type<Geometry1>::type,
typename point_type<Geometry2>::type,
- side_strategy_type,
CalculationType
> type;
};
diff --git a/boost/geometry/strategies/cartesian/point_in_poly_winding.hpp b/boost/geometry/strategies/cartesian/point_in_poly_winding.hpp
new file mode 100644
index 0000000000..c41bc9b83d
--- /dev/null
+++ b/boost/geometry/strategies/cartesian/point_in_poly_winding.hpp
@@ -0,0 +1,296 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2013, 2014, 2016, 2017.
+// Modifications copyright (c) 2013-2017 Oracle and/or its affiliates.
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_STRATEGY_CARTESIAN_POINT_IN_POLY_WINDING_HPP
+#define BOOST_GEOMETRY_STRATEGY_CARTESIAN_POINT_IN_POLY_WINDING_HPP
+
+
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/util/math.hpp>
+#include <boost/geometry/util/select_calculation_type.hpp>
+
+#include <boost/geometry/strategies/cartesian/side_by_triangle.hpp>
+#include <boost/geometry/strategies/covered_by.hpp>
+#include <boost/geometry/strategies/within.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+namespace strategy { namespace within
+{
+
+
+/*!
+\brief Within detection using winding rule in cartesian coordinate system.
+\ingroup strategies
+\tparam Point \tparam_point
+\tparam PointOfSegment \tparam_segment_point
+\tparam CalculationType \tparam_calculation
+\author Barend Gehrels
+\note The implementation is inspired by terralib http://www.terralib.org (LGPL)
+\note but totally revised afterwards, especially for cases on segments
+
+\qbk{
+[heading See also]
+[link geometry.reference.algorithms.within.within_3_with_strategy within (with strategy)]
+}
+ */
+template
+<
+ typename Point,
+ typename PointOfSegment = Point,
+ typename CalculationType = void
+>
+class cartesian_winding
+{
+ typedef side::side_by_triangle<CalculationType> side_strategy_type;
+
+ typedef typename select_calculation_type
+ <
+ Point,
+ PointOfSegment,
+ CalculationType
+ >::type calculation_type;
+
+ /*! subclass to keep state */
+ class counter
+ {
+ int m_count;
+ bool m_touches;
+
+ inline int code() const
+ {
+ return m_touches ? 0 : m_count == 0 ? -1 : 1;
+ }
+
+ public :
+ friend class cartesian_winding;
+
+ inline counter()
+ : m_count(0)
+ , m_touches(false)
+ {}
+
+ };
+
+public:
+ typedef typename side_strategy_type::envelope_strategy_type envelope_strategy_type;
+
+ static inline envelope_strategy_type get_envelope_strategy()
+ {
+ return side_strategy_type::get_envelope_strategy();
+ }
+
+ typedef typename side_strategy_type::disjoint_strategy_type disjoint_strategy_type;
+
+ static inline disjoint_strategy_type get_disjoint_strategy()
+ {
+ return side_strategy_type::get_disjoint_strategy();
+ }
+
+ // Typedefs and static methods to fulfill the concept
+ typedef Point point_type;
+ typedef PointOfSegment segment_point_type;
+ typedef counter state_type;
+
+ static inline bool apply(Point const& point,
+ PointOfSegment const& s1, PointOfSegment const& s2,
+ counter& state)
+ {
+ bool eq1 = false;
+ bool eq2 = false;
+
+ int count = check_segment(point, s1, s2, state, eq1, eq2);
+ if (count != 0)
+ {
+ int side = 0;
+ if (count == 1 || count == -1)
+ {
+ side = side_equal(point, eq1 ? s1 : s2, count);
+ }
+ else // count == 2 || count == -2
+ {
+ // 1 left, -1 right
+ side = side_strategy_type::apply(s1, s2, point);
+ }
+
+ if (side == 0)
+ {
+ // Point is lying on segment
+ state.m_touches = true;
+ state.m_count = 0;
+ return false;
+ }
+
+ // Side is NEG for right, POS for left.
+ // The count is -2 for left, 2 for right (or -1/1)
+ // Side positive thus means RIGHT and LEFTSIDE or LEFT and RIGHTSIDE
+ // See accompagnying figure (TODO)
+ if (side * count > 0)
+ {
+ state.m_count += count;
+ }
+ }
+ return ! state.m_touches;
+ }
+
+ static inline int result(counter const& state)
+ {
+ return state.code();
+ }
+
+private:
+ static inline int check_segment(Point const& point,
+ PointOfSegment const& seg1,
+ PointOfSegment const& seg2,
+ counter& state,
+ bool& eq1, bool& eq2)
+ {
+ if (check_touch(point, seg1, seg2, state, eq1, eq2))
+ {
+ return 0;
+ }
+
+ return calculate_count(point, seg1, seg2, eq1, eq2);
+ }
+
+ static inline bool check_touch(Point const& point,
+ PointOfSegment const& seg1,
+ PointOfSegment const& seg2,
+ counter& state,
+ bool& eq1, bool& eq2)
+ {
+ calculation_type const px = get<0>(point);
+ calculation_type const s1x = get<0>(seg1);
+ calculation_type const s2x = get<0>(seg2);
+
+ eq1 = math::equals(s1x, px);
+ eq2 = math::equals(s2x, px);
+
+ // Both equal p -> segment vertical
+ // The only thing which has to be done is check if point is ON segment
+ if (eq1 && eq2)
+ {
+ calculation_type const py = get<1>(point);
+ calculation_type const s1y = get<1>(seg1);
+ calculation_type const s2y = get<1>(seg2);
+ if ((s1y <= py && s2y >= py) || (s2y <= py && s1y >= py))
+ {
+ state.m_touches = true;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ static inline int calculate_count(Point const& point,
+ PointOfSegment const& seg1,
+ PointOfSegment const& seg2,
+ bool eq1, bool eq2)
+ {
+ calculation_type const p = get<0>(point);
+ calculation_type const s1 = get<0>(seg1);
+ calculation_type const s2 = get<0>(seg2);
+
+ return eq1 ? (s2 > p ? 1 : -1) // Point on level s1, E/W depending on s2
+ : eq2 ? (s1 > p ? -1 : 1) // idem
+ : s1 < p && s2 > p ? 2 // Point between s1 -> s2 --> E
+ : s2 < p && s1 > p ? -2 // Point between s2 -> s1 --> W
+ : 0;
+ }
+
+ static inline int side_equal(Point const& point,
+ PointOfSegment const& se,
+ int count)
+ {
+ // NOTE: for D=0 the signs would be reversed
+ return math::equals(get<1>(point), get<1>(se)) ?
+ 0 :
+ get<1>(point) < get<1>(se) ?
+ // assuming count is equal to 1 or -1
+ -count : // ( count > 0 ? -1 : 1) :
+ count; // ( count > 0 ? 1 : -1) ;
+ }
+};
+
+
+#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
+
+namespace services
+{
+
+template <typename PointLike, typename Geometry, typename AnyTag1, typename AnyTag2>
+struct default_strategy<PointLike, Geometry, AnyTag1, AnyTag2, pointlike_tag, polygonal_tag, cartesian_tag, cartesian_tag>
+{
+ typedef cartesian_winding
+ <
+ typename geometry::point_type<PointLike>::type,
+ typename geometry::point_type<Geometry>::type
+ > type;
+};
+
+template <typename PointLike, typename Geometry, typename AnyTag1, typename AnyTag2>
+struct default_strategy<PointLike, Geometry, AnyTag1, AnyTag2, pointlike_tag, linear_tag, cartesian_tag, cartesian_tag>
+{
+ typedef cartesian_winding
+ <
+ typename geometry::point_type<PointLike>::type,
+ typename geometry::point_type<Geometry>::type
+ > type;
+};
+
+} // namespace services
+
+#endif
+
+
+}} // namespace strategy::within
+
+
+#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
+namespace strategy { namespace covered_by { namespace services
+{
+
+template <typename PointLike, typename Geometry, typename AnyTag1, typename AnyTag2>
+struct default_strategy<PointLike, Geometry, AnyTag1, AnyTag2, pointlike_tag, polygonal_tag, cartesian_tag, cartesian_tag>
+{
+ typedef within::cartesian_winding
+ <
+ typename geometry::point_type<PointLike>::type,
+ typename geometry::point_type<Geometry>::type
+ > type;
+};
+
+template <typename PointLike, typename Geometry, typename AnyTag1, typename AnyTag2>
+struct default_strategy<PointLike, Geometry, AnyTag1, AnyTag2, pointlike_tag, linear_tag, cartesian_tag, cartesian_tag>
+{
+ typedef within::cartesian_winding
+ <
+ typename geometry::point_type<PointLike>::type,
+ typename geometry::point_type<Geometry>::type
+ > type;
+};
+
+}}} // namespace strategy::covered_by::services
+#endif
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_STRATEGY_CARTESIAN_POINT_IN_POLY_WINDING_HPP
diff --git a/boost/geometry/strategies/cartesian/side_by_triangle.hpp b/boost/geometry/strategies/cartesian/side_by_triangle.hpp
index 4d1d97520f..91bbee7bb2 100644
--- a/boost/geometry/strategies/cartesian/side_by_triangle.hpp
+++ b/boost/geometry/strategies/cartesian/side_by_triangle.hpp
@@ -4,10 +4,11 @@
// 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.
+// This file was modified by Oracle on 2015, 2017.
+// Modifications copyright (c) 2015-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -29,9 +30,9 @@
#include <boost/geometry/strategies/cartesian/disjoint_segment_box.hpp>
#include <boost/geometry/strategies/cartesian/envelope_segment.hpp>
+#include <boost/geometry/strategies/compare.hpp>
#include <boost/geometry/strategies/side.hpp>
-#include <boost/geometry/algorithms/detail/relate/less.hpp>
#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
@@ -182,10 +183,11 @@ public :
// arguments, we cyclically permute them so that the first
// argument is always the lexicographically smallest point.
- geometry::detail::relate::less less;
- if (less(p, p1))
+ typedef compare::cartesian<compare::less> less;
+
+ if (less::apply(p, p1))
{
- if (less(p, p2))
+ if (less::apply(p, p2))
{
// p is the lexicographically smallest
return side_value<CoordinateType, PromotedType>(p, p1, p2, epsp);
@@ -197,7 +199,7 @@ public :
}
}
- if (less(p1, p2))
+ if (less::apply(p1, p2))
{
// p1 is the lexicographically smallest
return side_value<CoordinateType, PromotedType>(p1, p2, p, epsp);
diff --git a/boost/geometry/strategies/compare.hpp b/boost/geometry/strategies/compare.hpp
index 2958319229..b196b75ec2 100644
--- a/boost/geometry/strategies/compare.hpp
+++ b/boost/geometry/strategies/compare.hpp
@@ -4,6 +4,11 @@
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// This file was modified by Oracle on 2017.
+// Modifications copyright (c) 2017, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -15,155 +20,204 @@
#ifndef BOOST_GEOMETRY_STRATEGIES_COMPARE_HPP
#define BOOST_GEOMETRY_STRATEGIES_COMPARE_HPP
+
#include <cstddef>
#include <functional>
-#include <boost/mpl/if.hpp>
+#include <boost/mpl/assert.hpp>
+#include <boost/mpl/min.hpp>
+#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
+#include <boost/geometry/core/coordinate_dimension.hpp>
-#include <boost/geometry/strategies/tags.hpp>
+#include <boost/geometry/util/math.hpp>
namespace boost { namespace geometry
{
-/*!
- \brief Traits class binding a comparing strategy to a coordinate system
- \ingroup util
- \tparam Tag tag of coordinate system of point-type
- \tparam Direction direction to compare on: 1 for less (-> ascending order)
- and -1 for greater (-> descending order)
- \tparam Point point-type
- \tparam CoordinateSystem coordinate sytem of point
- \tparam Dimension: the dimension to compare on
-*/
-template
-<
- typename Tag,
- int Direction,
- typename Point,
- typename CoordinateSystem,
- std::size_t Dimension
->
-struct strategy_compare
+namespace strategy { namespace compare
{
- typedef strategy::not_implemented type;
+
+
+struct less
+{
+ template <typename T1, typename T2>
+ static inline bool apply(T1 const& l, T2 const& r)
+ {
+ return l < r;
+ }
};
+struct greater
+{
+ template <typename T1, typename T2>
+ static inline bool apply(T1 const& l, T2 const& r)
+ {
+ return l > r;
+ }
+};
+
+struct equal_to
+{
+ template <typename T1, typename T2>
+ static inline bool apply(T1 const& , T2 const& )
+ {
+ return false;
+ }
+};
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail
+{
-#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
-// For compare we add defaults specializations,
-// because they defaultly redirect to std::less / greater / equal_to
template
<
- typename Tag,
- typename Point,
- typename CoordinateSystem,
- std::size_t Dimension
+ typename ComparePolicy,
+ std::size_t Dimension,
+ std::size_t DimensionCount
>
-struct strategy_compare<Tag, 1, Point, CoordinateSystem, Dimension>
+struct compare_loop
{
- typedef std::less<typename coordinate_type<Point>::type> type;
+ template <typename Point1, typename Point2>
+ static inline bool apply(Point1 const& left, Point2 const& right)
+ {
+ typename geometry::coordinate_type<Point1>::type const&
+ cleft = geometry::get<Dimension>(left);
+ typename geometry::coordinate_type<Point2>::type const&
+ cright = geometry::get<Dimension>(right);
+
+ if (math::equals(cleft, cright))
+ {
+ return compare_loop
+ <
+ ComparePolicy,
+ Dimension + 1, DimensionCount
+ >::apply(left, right);
+ }
+ else
+ {
+ return ComparePolicy::apply(cleft, cright);
+ }
+ }
};
-
template
<
- typename Tag,
- typename Point,
- typename CoordinateSystem,
- std::size_t Dimension
+ typename ComparePolicy,
+ std::size_t DimensionCount
>
-struct strategy_compare<Tag, -1, Point, CoordinateSystem, Dimension>
+struct compare_loop<ComparePolicy, DimensionCount, DimensionCount>
{
- typedef std::greater<typename coordinate_type<Point>::type> type;
+ template <typename Point1, typename Point2>
+ static inline bool apply(Point1 const& , Point2 const& )
+ {
+ // On coming here, points are equal.
+ // Return false for less/greater.
+ return false;
+ }
};
-
template
<
- typename Tag,
- typename Point,
- typename CoordinateSystem,
- std::size_t Dimension
+ std::size_t DimensionCount
>
-struct strategy_compare<Tag, 0, Point, CoordinateSystem, Dimension>
+struct compare_loop<strategy::compare::equal_to, DimensionCount, DimensionCount>
{
- typedef std::equal_to<typename coordinate_type<Point>::type> type;
+ template <typename Point1, typename Point2>
+ static inline bool apply(Point1 const& , Point2 const& )
+ {
+ // On coming here, points are equal.
+ // Return true for equal_to.
+ return true;
+ }
};
-
-#endif
+} // namespace detail
+#endif // DOXYGEN_NO_DETAIL
-namespace strategy { namespace compare
+template
+<
+ typename ComparePolicy,
+ int Dimension = -1
+>
+struct cartesian
{
+ template <typename Point1, typename Point2>
+ static inline bool apply(Point1 const& left, Point2 const& right)
+ {
+ return compare::detail::compare_loop
+ <
+ ComparePolicy, Dimension, Dimension + 1
+ >::apply(left, right);
+ }
+};
-
-/*!
- \brief Default strategy, indicates the default strategy for comparisons
- \details The default strategy for comparisons defer in most cases
- to std::less (for ascending) and std::greater (for descending).
- However, if a spherical coordinate system is used, and comparison
- is done on longitude, it will take another strategy handling circular
-*/
-struct default_strategy {};
-
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail
+#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
+template
+<
+ typename ComparePolicy
+>
+struct cartesian<ComparePolicy, -1>
{
+ template <typename Point1, typename Point2>
+ static inline bool apply(Point1 const& left, Point2 const& right)
+ {
+ return compare::detail::compare_loop
+ <
+ ComparePolicy,
+ 0,
+ boost::mpl::min
+ <
+ geometry::dimension<Point1>,
+ geometry::dimension<Point2>
+ >::type::value
+ >::apply(left, right);
+ }
+};
+#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
-template <typename Type>
-struct is_default : boost::false_type
-{};
-
-
-template <>
-struct is_default<default_strategy> : boost::true_type
-{};
+namespace services
+{
-/*!
- \brief Meta-function to select strategy
- \details If "default_strategy" is specified, it will take the
- traits-registered class for the specified coordinate system.
- If another strategy is explicitly specified, it takes that one.
-*/
template
<
- typename Strategy,
- int Direction,
- typename Point,
- std::size_t Dimension
+ typename ComparePolicy,
+ typename Point1,
+ typename Point2 = Point1,
+ int Dimension = -1,
+ typename CSTag1 = typename cs_tag<Point1>::type,
+ typename CSTag2 = typename cs_tag<Point2>::type
>
-struct select_strategy
+struct default_strategy
{
- typedef typename
- boost::mpl::if_
- <
- is_default<Strategy>,
- typename strategy_compare
- <
- typename cs_tag<Point>::type,
- Direction,
- Point,
- typename coordinate_system<Point>::type,
- Dimension
- >::type,
- Strategy
- >::type type;
+ BOOST_MPL_ASSERT_MSG
+ (
+ false,
+ NOT_IMPLEMENTED_FOR_THESE_TYPES,
+ (types<CSTag1, CSTag2>)
+ );
};
-} // namespace detail
-#endif // DOXYGEN_NO_DETAIL
+
+template <typename ComparePolicy, typename Point1, typename Point2, int Dimension>
+struct default_strategy<ComparePolicy, Point1, Point2, Dimension, cartesian_tag, cartesian_tag>
+{
+ typedef compare::cartesian<ComparePolicy, Dimension> type;
+};
+
+
+} // namespace services
-}} // namespace strategy::compare
+}} // namespace strategy compare
}} // namespace boost::geometry
diff --git a/boost/geometry/strategies/geographic/area.hpp b/boost/geometry/strategies/geographic/area.hpp
index 44dc2e6945..40d6c8243e 100644
--- a/boost/geometry/strategies/geographic/area.hpp
+++ b/boost/geometry/strategies/geographic/area.hpp
@@ -15,12 +15,11 @@
#include <boost/geometry/core/srs.hpp>
#include <boost/geometry/formulas/area_formulas.hpp>
-#include <boost/geometry/formulas/flattening.hpp>
+#include <boost/geometry/formulas/authalic_radius_sqr.hpp>
+#include <boost/geometry/formulas/eccentricity_sqr.hpp>
#include <boost/geometry/strategies/geographic/parameters.hpp>
-#include <boost/math/special_functions/atanh.hpp>
-
namespace boost { namespace geometry
{
@@ -88,31 +87,16 @@ protected :
inline spheroid_constants(Spheroid const& spheroid)
: m_spheroid(spheroid)
, m_a2(math::sqr(get_radius<0>(spheroid)))
- , m_e2(formula::flattening<CT>(spheroid)
- * (CT(2.0) - CT(formula::flattening<CT>(spheroid))))
+ , m_e2(formula::eccentricity_sqr<CT>(spheroid))
, m_ep2(m_e2 / (CT(1.0) - m_e2))
, m_ep(math::sqrt(m_ep2))
- , m_c2(authalic_radius(spheroid, m_a2, m_e2))
+ , m_c2(formula_dispatch::authalic_radius_sqr
+ <
+ CT, Spheroid, srs_spheroid_tag
+ >::apply(m_a2, m_e2))
{}
};
- static inline CT authalic_radius(Spheroid const& sph, CT const& a2, CT const& e2)
- {
- CT const c0 = 0;
-
- if (math::equals(e2, c0))
- {
- return a2;
- }
-
- CT const sqrt_e2 = math::sqrt(e2);
- CT const c2 = 2;
-
- return (a2 / c2) +
- ((math::sqr(get_radius<2>(sph)) * boost::math::atanh(sqrt_e2))
- / (c2 * sqrt_e2));
- }
-
struct area_sums
{
CT m_excess_sum;
@@ -190,8 +174,10 @@ public :
state.m_correction_sum += result.ellipsoidal_term;
// Keep track whenever a segment crosses the prime meridian
- geometry::formula::area_formulas<CT>
- ::crosses_prime_meridian(p1, p2, state);
+ if (area_formulas::crosses_prime_meridian(p1, p2))
+ {
+ state.m_crosses_prime_meridian++;
+ }
}
}
diff --git a/boost/geometry/strategies/geographic/distance.hpp b/boost/geometry/strategies/geographic/distance.hpp
index d3656f449c..98ee46a369 100644
--- a/boost/geometry/strategies/geographic/distance.hpp
+++ b/boost/geometry/strategies/geographic/distance.hpp
@@ -5,6 +5,7 @@
// This file was modified by Oracle on 2014-2017.
// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates.
+// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
@@ -22,12 +23,14 @@
#include <boost/geometry/core/srs.hpp>
#include <boost/geometry/formulas/andoyer_inverse.hpp>
+#include <boost/geometry/formulas/elliptic_arc_length.hpp>
#include <boost/geometry/formulas/flattening.hpp>
#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/strategies/geographic/parameters.hpp>
#include <boost/geometry/util/math.hpp>
+#include <boost/geometry/util/normalize_spheroidal_coordinates.hpp>
#include <boost/geometry/util/promote_floating_point.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
@@ -70,17 +73,41 @@ public :
: m_spheroid(spheroid)
{}
+ template <typename CT>
+ static inline CT apply(CT lon1, CT lat1, CT lon2, CT lat2,
+ Spheroid const& spheroid)
+ {
+ typedef typename formula::elliptic_arc_length
+ <
+ CT, strategy::default_order<FormulaPolicy>::value
+ > elliptic_arc_length;
+
+ typename elliptic_arc_length::result res =
+ elliptic_arc_length::apply(lon1, lat1, lon2, lat2, spheroid);
+
+ if (res.meridian)
+ {
+ return res.distance;
+ }
+
+ return FormulaPolicy::template inverse
+ <
+ CT, true, false, false, false, false
+ >::apply(lon1, lat1, lon2, lat2, spheroid).distance;
+ }
+
template <typename Point1, typename Point2>
inline typename calculation_type<Point1, Point2>::type
apply(Point1 const& point1, Point2 const& point2) const
{
- return FormulaPolicy::template inverse
- <
- typename calculation_type<Point1, Point2>::type,
- true, false, false, false, false
- >::apply(get_as_radian<0>(point1), get_as_radian<1>(point1),
- get_as_radian<0>(point2), get_as_radian<1>(point2),
- m_spheroid).distance;
+ typedef typename calculation_type<Point1, Point2>::type CT;
+
+ CT lon1 = get_as_radian<0>(point1);
+ CT lat1 = get_as_radian<1>(point1);
+ CT lon2 = get_as_radian<0>(point2);
+ CT lat2 = get_as_radian<1>(point2);
+
+ return apply(lon1, lat1, lon2, lat2, m_spheroid);
}
inline Spheroid const& model() const
diff --git a/boost/geometry/strategies/geographic/distance_cross_track.hpp b/boost/geometry/strategies/geographic/distance_cross_track.hpp
new file mode 100644
index 0000000000..799208a96d
--- /dev/null
+++ b/boost/geometry/strategies/geographic/distance_cross_track.hpp
@@ -0,0 +1,641 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2016-2017, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Vissarion Fysikopoulos, 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_STRATEGIES_GEOGRAPHIC_DISTANCE_CROSS_TRACK_HPP
+#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_DISTANCE_CROSS_TRACK_HPP
+
+#include <algorithm>
+
+#include <boost/config.hpp>
+#include <boost/concept_check.hpp>
+#include <boost/mpl/if.hpp>
+#include <boost/type_traits/is_void.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/strategies/distance.hpp>
+#include <boost/geometry/strategies/concepts/distance_concept.hpp>
+#include <boost/geometry/strategies/spherical/distance_haversine.hpp>
+#include <boost/geometry/strategies/geographic/azimuth.hpp>
+#include <boost/geometry/strategies/geographic/parameters.hpp>
+
+#include <boost/geometry/formulas/vincenty_direct.hpp>
+
+#include <boost/geometry/util/math.hpp>
+#include <boost/geometry/util/promote_floating_point.hpp>
+#include <boost/geometry/util/select_calculation_type.hpp>
+#include <boost/geometry/util/normalize_spheroidal_coordinates.hpp>
+
+#include <boost/geometry/formulas/result_direct.hpp>
+#include <boost/geometry/formulas/mean_radius.hpp>
+
+#ifdef BOOST_GEOMETRY_DEBUG_GEOGRAPHIC_CROSS_TRACK
+# include <boost/geometry/io/dsv/write.hpp>
+#endif
+
+#ifndef BOOST_GEOMETRY_DETAIL_POINT_SEGMENT_DISTANCE_MAX_STEPS
+#define BOOST_GEOMETRY_DETAIL_POINT_SEGMENT_DISTANCE_MAX_STEPS 100
+#endif
+
+#ifdef BOOST_GEOMETRY_DEBUG_GEOGRAPHIC_CROSS_TRACK
+#include <iostream>
+#endif
+
+namespace boost { namespace geometry
+{
+
+namespace strategy { namespace distance
+{
+
+/*!
+\brief Strategy functor for distance point to segment calculation on ellipsoid
+ Algorithm uses direct and inverse geodesic problems as subroutines.
+ The algorithm approximates the distance by an iterative Newton method.
+\ingroup strategies
+\details Class which calculates the distance of a point to a segment, for points
+on the ellipsoid
+\see C.F.F.Karney - Geodesics on an ellipsoid of revolution,
+ https://arxiv.org/abs/1102.1215
+\tparam FormulaPolicy underlying point-point distance strategy
+\tparam Spheroid is the spheroidal model used
+\tparam CalculationType \tparam_calculation
+\tparam EnableClosestPoint computes the closest point on segment if true
+*/
+template
+<
+ typename FormulaPolicy = strategy::andoyer,
+ typename Spheroid = srs::spheroid<double>,
+ typename CalculationType = void,
+ bool EnableClosestPoint = false
+>
+class geographic_cross_track
+{
+public :
+ template <typename Point, typename PointOfSegment>
+ struct return_type
+ : promote_floating_point
+ <
+ typename select_calculation_type
+ <
+ Point,
+ PointOfSegment,
+ CalculationType
+ >::type
+ >
+ {};
+
+ struct distance_strategy
+ {
+ typedef geographic<FormulaPolicy, Spheroid, CalculationType> type;
+ };
+
+ inline typename distance_strategy::type get_distance_strategy() const
+ {
+ typedef typename distance_strategy::type distance_type;
+ return distance_type(m_spheroid);
+ }
+
+ explicit geographic_cross_track(Spheroid const& spheroid = Spheroid())
+ : m_spheroid(spheroid)
+ {}
+
+ template <typename Point, typename PointOfSegment>
+ inline typename return_type<Point, PointOfSegment>::type
+ apply(Point const& p, PointOfSegment const& sp1, PointOfSegment const& sp2) const
+ {
+ typedef typename coordinate_system<Point>::type::units units_type;
+
+ return (apply<units_type>(get<0>(sp1), get<1>(sp1),
+ get<0>(sp2), get<1>(sp2),
+ get<0>(p), get<1>(p),
+ m_spheroid)).distance;
+ }
+
+private :
+
+ template <typename CT>
+ struct result_distance_point_segment
+ {
+ result_distance_point_segment()
+ : distance(0)
+ , closest_point_lon(0)
+ , closest_point_lat(0)
+ {}
+
+ CT distance;
+ CT closest_point_lon;
+ CT closest_point_lat;
+ };
+
+ template <typename CT>
+ result_distance_point_segment<CT>
+ static inline non_iterative_case(CT lon, CT lat, CT distance)
+ {
+ result_distance_point_segment<CT> result;
+ result.distance = distance;
+
+ if (EnableClosestPoint)
+ {
+ result.closest_point_lon = lon;
+ result.closest_point_lat = lat;
+ }
+ return result;
+ }
+
+ template <typename CT>
+ result_distance_point_segment<CT>
+ static inline non_iterative_case(CT lon1, CT lat1, //p1
+ CT lon2, CT lat2, //p2
+ Spheroid const& spheroid)
+ {
+ CT distance = geometry::strategy::distance::geographic<FormulaPolicy, Spheroid, CT>
+ ::apply(lon1, lat1, lon2, lat2, spheroid);
+
+ return non_iterative_case(lon1, lat1, distance);
+ }
+
+ template <typename CT>
+ CT static inline normalize(CT g4)
+ {
+ CT const pi = math::pi<CT>();
+ if (g4 < 0 && g4 < -pi)//close to -270
+ {
+ return g4 + 1.5 * pi;
+ }
+ else if (g4 > 0 && g4 > pi)//close to 270
+ {
+ return - g4 + 1.5 * pi;
+ }
+ else if (g4 < 0 && g4 > -pi)//close to -90
+ {
+ return -g4 - pi/2;
+ }
+ return g4 - pi/2;
+ }
+
+ template <typename Units, typename CT>
+ result_distance_point_segment<CT>
+ static inline apply(CT lon1, CT lat1, //p1
+ CT lon2, CT lat2, //p2
+ CT lon3, CT lat3, //query point p3
+ Spheroid const& spheroid)
+ {
+ typedef typename FormulaPolicy::template inverse<CT, true, false, false, true, true>
+ inverse_distance_quantities_type;
+ typedef typename FormulaPolicy::template inverse<CT, false, true, false, false, false>
+ inverse_azimuth_type;
+ typedef typename FormulaPolicy::template inverse<CT, false, true, true, false, false>
+ inverse_azimuth_reverse_type;
+ typedef typename FormulaPolicy::template direct<CT, true, false, false, false>
+ direct_distance_type;
+
+ CT const earth_radius = geometry::formula::mean_radius<CT>(spheroid);
+
+ result_distance_point_segment<CT> result;
+
+ // Constants
+ CT const f = geometry::formula::flattening<CT>(spheroid);
+ CT const pi = math::pi<CT>();
+ CT const half_pi = pi / CT(2);
+ CT const c0 = CT(0);
+
+ // Convert to radians
+ lon1 = math::as_radian<Units>(lon1);
+ lat1 = math::as_radian<Units>(lat1);
+ lon2 = math::as_radian<Units>(lon2);
+ lat2 = math::as_radian<Units>(lat2);
+ lon3 = math::as_radian<Units>(lon3);
+ lat3 = math::as_radian<Units>(lat3);
+
+ if (lon1 > lon2)
+ {
+ std::swap(lon1, lon2);
+ std::swap(lat1, lat2);
+ }
+
+ //segment on equator
+ //Note: antipodal points on equator does not define segment on equator
+ //but pass by the pole
+ CT diff = geometry::math::longitude_distance_signed<geometry::radian>(lon1, lon2);
+ if (math::equals(lat1, c0) && math::equals(lat2, c0)
+ && !math::equals(math::abs(diff), pi))
+ {
+#ifdef BOOST_GEOMETRY_DEBUG_GEOGRAPHIC_CROSS_TRACK
+ std::cout << "Equatorial segment" << std::endl;
+#endif
+ if (lon3 <= lon1)
+ {
+ return non_iterative_case(lon1, lat1, lon3, lat3, spheroid);
+ }
+ if (lon3 >= lon2)
+ {
+ return non_iterative_case(lon2, lat2, lon3, lat3, spheroid);
+ }
+ return non_iterative_case(lon3, lat1, lon3, lat3, spheroid);
+ }
+
+ if (math::equals(math::abs(diff), pi))
+ {
+#ifdef BOOST_GEOMETRY_DEBUG_GEOGRAPHIC_CROSS_TRACK
+ std::cout << "Meridian segment" << std::endl;
+#endif
+ result_distance_point_segment<CT> d1 = apply<geometry::radian>(lon1, lat1, lon1, half_pi, lon3, lat3, spheroid);
+ result_distance_point_segment<CT> d2 = apply<geometry::radian>(lon2, lat2, lon2, half_pi, lon3, lat3, spheroid);
+ if (d1.distance < d2.distance)
+ {
+ return d1;
+ }
+ else
+ {
+ return d2;
+ }
+ }
+
+ CT d1 = geometry::strategy::distance::geographic<FormulaPolicy, Spheroid, CT>
+ ::apply(lon1, lat1, lon3, lat3, spheroid);
+
+ CT d3 = geometry::strategy::distance::geographic<FormulaPolicy, Spheroid, CT>
+ ::apply(lon1, lat1, lon2, lat2, spheroid);
+
+ if (geometry::math::equals(d3, c0))
+ {
+#ifdef BOOST_GEOMETRY_DEBUG_GEOGRAPHIC_CROSS_TRACK
+ std::cout << "Degenerate segment" << std::endl;
+ std::cout << "distance between points=" << d1 << std::endl;
+#endif
+ return non_iterative_case(lon1, lat2, d1);
+ }
+
+ CT d2 = geometry::strategy::distance::geographic<FormulaPolicy, Spheroid, CT>
+ ::apply(lon2, lat2, lon3, lat3, spheroid);
+
+ // Compute a12 (GEO)
+ geometry::formula::result_inverse<CT> res12 =
+ inverse_azimuth_reverse_type::apply(lon1, lat1, lon2, lat2, spheroid);
+ CT a12 = res12.azimuth;
+ CT a13 = inverse_azimuth_type::apply(lon1, lat1, lon3, lat3, spheroid).azimuth;
+
+ CT a312 = a13 - a12;
+
+ if (geometry::math::equals(a312, c0))
+ {
+#ifdef BOOST_GEOMETRY_DEBUG_GEOGRAPHIC_CROSS_TRACK
+ std::cout << "point on segment" << std::endl;
+#endif
+ return non_iterative_case(lon3, lat3, c0);
+ }
+
+ CT projection1 = cos( a312 ) * d1 / d3;
+
+#ifdef BOOST_GEOMETRY_DEBUG_GEOGRAPHIC_CROSS_TRACK
+ std::cout << "segment=(" << lon1 * math::r2d<CT>();
+ std::cout << "," << lat1 * math::r2d<CT>();
+ std::cout << "),(" << lon2 * math::r2d<CT>();
+ std::cout << "," << lat2 * math::r2d<CT>();
+ std::cout << ")\np=(" << lon3 * math::r2d<CT>();
+ std::cout << "," << lat3 * math::r2d<CT>();
+ std::cout << ")\na1=" << a12 * math::r2d<CT>() << std::endl;
+ std::cout << "a13=" << a13 * math::r2d<CT>() << std::endl;
+ std::cout << "a312=" << a312 * math::r2d<CT>() << std::endl;
+ std::cout << "cos(a312)=" << cos(a312) << std::endl;
+#endif
+ if (projection1 < 0.0)
+ {
+#ifdef BOOST_GEOMETRY_DEBUG_GEOGRAPHIC_CROSS_TRACK
+ std::cout << "projection closer to p1" << std::endl;
+#endif
+ // projection of p3 on geodesic spanned by segment (p1,p2) fall
+ // outside of segment on the side of p1
+ return non_iterative_case(lon1, lat1, lon3, lat3, spheroid);
+ }
+
+ CT a21 = res12.reverse_azimuth - pi;
+ CT a23 = inverse_azimuth_type::apply(lon2, lat2, lon3, lat3, spheroid).azimuth;
+
+ CT a321 = a23 - a21;
+
+#ifdef BOOST_GEOMETRY_DEBUG_GEOGRAPHIC_CROSS_TRACK
+ std::cout << "a21=" << a21 * math::r2d<CT>() << std::endl;
+ std::cout << "a23=" << a23 * math::r2d<CT>() << std::endl;
+ std::cout << "a321=" << a321 * math::r2d<CT>() << std::endl;
+ std::cout << "cos(a321)=" << cos(a321) << std::endl;
+#endif
+ CT projection2 = cos( a321 ) * d2 / d3;
+
+ if (projection2 < 0.0)
+ {
+#ifdef BOOST_GEOMETRY_DEBUG_GEOGRAPHIC_CROSS_TRACK
+ std::cout << "projection closer to p2" << std::endl;
+#endif
+ // projection of p3 on geodesic spanned by segment (p1,p2) fall
+ // outside of segment on the side of p2
+ return non_iterative_case(lon2, lat2, lon3, lat3, spheroid);
+ }
+
+ // Guess s14 (SPHERICAL)
+ typedef geometry::model::point
+ <
+ CT, 2,
+ geometry::cs::spherical_equatorial<geometry::radian>
+ > point;
+
+ CT bet1 = atan((1 - f) * tan(lon1));
+ CT bet2 = atan((1 - f) * tan(lon2));
+ CT bet3 = atan((1 - f) * tan(lon3));
+ point p1 = point(bet1, lat1);
+ point p2 = point(bet2, lat2);
+ point p3 = point(bet3, lat3);
+
+ geometry::strategy::distance::cross_track<CT> cross_track(earth_radius);
+ CT s34 = cross_track.apply(p3, p1, p2);
+
+ geometry::strategy::distance::haversine<CT> str(earth_radius);
+ CT s13 = str.apply(p1, p3);
+ CT s14 = acos( cos(s13/earth_radius) / cos(s34/earth_radius) ) * earth_radius;
+
+#ifdef BOOST_GEOMETRY_DEBUG_GEOGRAPHIC_CROSS_TRACK
+ std::cout << "s34=" << s34 << std::endl;
+ std::cout << "s13=" << s13 << std::endl;
+ std::cout << "s14=" << s14 << std::endl;
+ std::cout << "===============" << std::endl;
+#endif
+
+ // Update s14 (using Newton method)
+ CT prev_distance = 0;
+ geometry::formula::result_direct<CT> res14;
+ geometry::formula::result_inverse<CT> res34;
+
+ int counter = 0; // robustness
+ CT g4;
+ CT delta_g4;
+
+ do{
+ prev_distance = res34.distance;
+
+ // Solve the direct problem to find p4 (GEO)
+ res14 = direct_distance_type::apply(lon1, lat1, s14, a12, spheroid);
+
+ // Solve an inverse problem to find g4
+ // g4 is the angle between segment (p1,p2) and segment (p3,p4) that meet on p4 (GEO)
+
+ CT a4 = inverse_azimuth_type::apply(res14.lon2, res14.lat2,
+ lon2, lat2, spheroid).azimuth;
+ res34 = inverse_distance_quantities_type::apply(res14.lon2, res14.lat2,
+ lon3, lat3, spheroid);
+ g4 = res34.azimuth - a4;
+
+ delta_g4 = normalize(g4);
+
+ CT M43 = res34.geodesic_scale; // cos(s14/earth_radius) is the spherical limit
+ CT m34 = res34.reduced_length;
+ CT der = (M43 / m34) * sin(g4);
+ s14 = s14 - delta_g4 / der;
+
+#ifdef BOOST_GEOMETRY_DEBUG_GEOGRAPHIC_CROSS_TRACK
+ std::cout << "p4=" << res14.lon2 * math::r2d<CT>() <<
+ "," << res14.lat2 * math::r2d<CT>() << std::endl;
+ std::cout << "delta_g4=" << delta_g4 << std::endl;
+ std::cout << "g4=" << g4 * math::r2d<CT>() << std::endl;
+ std::cout << "der=" << der << std::endl;
+ std::cout << "M43=" << M43 << std::endl;
+ std::cout << "spherical limit=" << cos(s14/earth_radius) << std::endl;
+ std::cout << "m34=" << m34 << std::endl;
+ std::cout << "new_s14=" << s14 << std::endl;
+ std::cout << std::setprecision(16) << "dist =" << res34.distance << std::endl;
+ std::cout << "---------end of step " << counter << std::endl<< std::endl;
+#endif
+ result.distance = prev_distance;
+
+#ifdef BOOST_GEOMETRY_DEBUG_GEOGRAPHIC_CROSS_TRACK
+ if (g4 == half_pi)
+ {
+ std::cout << "Stop msg: g4 == half_pi" << std::endl;
+ }
+ if (res34.distance >= prev_distance && prev_distance != 0)
+ {
+ std::cout << "Stop msg: res34.distance >= prev_distance" << std::endl;
+ }
+ if (delta_g4 == 0)
+ {
+ std::cout << "Stop msg: delta_g4 == 0" << std::endl;
+ }
+ if (counter == 19)
+ {
+ std::cout << "Stop msg: counter" << std::endl;
+ }
+#endif
+
+ } while (g4 != half_pi
+ && (prev_distance > res34.distance || prev_distance == 0)
+ && delta_g4 != 0
+ && ++counter < BOOST_GEOMETRY_DETAIL_POINT_SEGMENT_DISTANCE_MAX_STEPS ) ;
+
+#ifdef BOOST_GEOMETRY_DEBUG_GEOGRAPHIC_CROSS_TRACK
+ std::cout << "distance=" << res34.distance << std::endl;
+
+ point p4(res14.lon2, res14.lat2);
+ CT s34_sph = str.apply(p4, p3);
+
+ std::cout << "s34(sph) =" << s34_sph << std::endl;
+ std::cout << "s34(geo) ="
+ << inverse_distance_quantities_type::apply(get<0>(p4), get<1>(p4), lon3, lat3, spheroid).distance
+ << ", p4=(" << get<0>(p4) * math::r2d<double>() << ","
+ << get<1>(p4) * math::r2d<double>() << ")"
+ << std::endl;
+
+ CT s31 = inverse_distance_quantities_type::apply(lon3, lat3, lon1, lat1, spheroid).distance;
+ CT s32 = inverse_distance_quantities_type::apply(lon3, lat3, lon2, lat2, spheroid).distance;
+
+ CT a4 = inverse_azimuth_type::apply(get<0>(p4), get<1>(p4), lon2, lat2, spheroid).azimuth;
+ geometry::formula::result_direct<CT> res4 = direct_distance_type::apply(get<0>(p4), get<1>(p4), .04, a4, spheroid);
+ CT p4_plus = inverse_distance_quantities_type::apply(res4.lon2, res4.lat2, lon3, lat3, spheroid).distance;
+
+ geometry::formula::result_direct<CT> res1 = direct_distance_type::apply(lon1, lat1, s14-.04, a12, spheroid);
+ CT p4_minus = inverse_distance_quantities_type::apply(res1.lon2, res1.lat2, lon3, lat3, spheroid).distance;
+
+ std::cout << "s31=" << s31 << "\ns32=" << s32
+ << "\np4_plus=" << p4_plus << ", p4=(" << res4.lon2 * math::r2d<double>() << "," << res4.lat2 * math::r2d<double>() << ")"
+ << "\np4_minus=" << p4_minus << ", p4=(" << res1.lon2 * math::r2d<double>() << "," << res1.lat2 * math::r2d<double>() << ")"
+ << std::endl;
+
+ if (res34.distance <= p4_plus && res34.distance <= p4_minus)
+ {
+ std::cout << "Closest point computed" << std::endl;
+ }
+ else
+ {
+ std::cout << "There is a closer point nearby" << std::endl;
+ }
+#endif
+
+ return result;
+ }
+
+ Spheroid m_spheroid;
+};
+
+
+
+#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
+namespace services
+{
+
+//tags
+template <typename FormulaPolicy>
+struct tag<geographic_cross_track<FormulaPolicy> >
+{
+ typedef strategy_tag_distance_point_segment type;
+};
+
+template
+<
+ typename FormulaPolicy,
+ typename Spheroid
+>
+struct tag<geographic_cross_track<FormulaPolicy, Spheroid> >
+{
+ typedef strategy_tag_distance_point_segment type;
+};
+
+template
+<
+ typename FormulaPolicy,
+ typename Spheroid,
+ typename CalculationType
+>
+struct tag<geographic_cross_track<FormulaPolicy, Spheroid, CalculationType> >
+{
+ typedef strategy_tag_distance_point_segment type;
+};
+
+
+//return types
+template <typename FormulaPolicy, typename P, typename PS>
+struct return_type<geographic_cross_track<FormulaPolicy>, P, PS>
+ : geographic_cross_track<FormulaPolicy>::template return_type<P, PS>
+{};
+
+template
+<
+ typename FormulaPolicy,
+ typename Spheroid,
+ typename P,
+ typename PS
+>
+struct return_type<geographic_cross_track<FormulaPolicy, Spheroid>, P, PS>
+ : geographic_cross_track<FormulaPolicy, Spheroid>::template return_type<P, PS>
+{};
+
+template
+<
+ typename FormulaPolicy,
+ typename Spheroid,
+ typename CalculationType,
+ typename P,
+ typename PS
+>
+struct return_type<geographic_cross_track<FormulaPolicy, Spheroid, CalculationType>, P, PS>
+ : geographic_cross_track<FormulaPolicy, Spheroid, CalculationType>::template return_type<P, PS>
+{};
+
+//comparable types
+template
+<
+ typename FormulaPolicy,
+ typename Spheroid,
+ typename CalculationType
+>
+struct comparable_type<geographic_cross_track<FormulaPolicy, Spheroid, CalculationType> >
+{
+ typedef geographic_cross_track
+ <
+ FormulaPolicy, Spheroid, CalculationType
+ > type;
+};
+
+template
+<
+ typename FormulaPolicy,
+ typename Spheroid,
+ typename CalculationType
+>
+struct get_comparable<geographic_cross_track<FormulaPolicy, Spheroid, CalculationType> >
+{
+ typedef typename comparable_type
+ <
+ geographic_cross_track<FormulaPolicy, Spheroid, CalculationType>
+ >::type comparable_type;
+public :
+ static inline comparable_type
+ apply(geographic_cross_track<FormulaPolicy, Spheroid, CalculationType> const& )
+ {
+ return comparable_type();
+ }
+};
+
+
+template
+<
+ typename FormulaPolicy,
+ typename P,
+ typename PS
+>
+struct result_from_distance<geographic_cross_track<FormulaPolicy>, P, PS>
+{
+private :
+ typedef typename geographic_cross_track
+ <
+ FormulaPolicy
+ >::template return_type<P, PS>::type return_type;
+public :
+ template <typename T>
+ static inline return_type
+ apply(geographic_cross_track<FormulaPolicy> const& , T const& distance)
+ {
+ return distance;
+ }
+};
+
+
+template <typename Point, typename PointOfSegment>
+struct default_strategy
+ <
+ point_tag, segment_tag, Point, PointOfSegment,
+ geographic_tag, geographic_tag
+ >
+{
+ typedef geographic_cross_track<> type;
+};
+
+
+template <typename PointOfSegment, typename Point>
+struct default_strategy
+ <
+ segment_tag, point_tag, PointOfSegment, Point,
+ geographic_tag, geographic_tag
+ >
+{
+ typedef typename default_strategy
+ <
+ point_tag, segment_tag, Point, PointOfSegment,
+ geographic_tag, geographic_tag
+ >::type type;
+};
+
+} // namespace services
+#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
+
+}} // namespace strategy::distance
+
+}} // namespace boost::geometry
+#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_DISTANCE_CROSS_TRACK_HPP
diff --git a/boost/geometry/strategies/geographic/intersection.hpp b/boost/geometry/strategies/geographic/intersection.hpp
index 59a40f281d..e91659d40e 100644
--- a/boost/geometry/strategies/geographic/intersection.hpp
+++ b/boost/geometry/strategies/geographic/intersection.hpp
@@ -26,6 +26,7 @@
#include <boost/geometry/formulas/andoyer_inverse.hpp>
#include <boost/geometry/formulas/sjoberg_intersection.hpp>
#include <boost/geometry/formulas/spherical.hpp>
+#include <boost/geometry/formulas/unit_spheroid.hpp>
#include <boost/geometry/geometries/concepts/point_concept.hpp>
#include <boost/geometry/geometries/concepts/segment_concept.hpp>
@@ -36,6 +37,7 @@
#include <boost/geometry/strategies/geographic/distance.hpp>
#include <boost/geometry/strategies/geographic/envelope_segment.hpp>
#include <boost/geometry/strategies/geographic/parameters.hpp>
+#include <boost/geometry/strategies/geographic/point_in_poly_winding.hpp>
#include <boost/geometry/strategies/geographic/side.hpp>
#include <boost/geometry/strategies/intersection.hpp>
#include <boost/geometry/strategies/intersection_result.hpp>
@@ -78,11 +80,12 @@ struct geographic_segments
template <typename Geometry1, typename Geometry2>
struct point_in_geometry_strategy
{
- typedef strategy::within::winding
+ typedef strategy::within::geographic_winding
<
typename point_type<Geometry1>::type,
typename point_type<Geometry2>::type,
- side_strategy_type,
+ FormulaPolicy,
+ Spheroid,
CalculationType
> type;
};
@@ -95,7 +98,7 @@ struct geographic_segments
<
Geometry1, Geometry2
>::type strategy_type;
- return strategy_type(get_side_strategy());
+ return strategy_type(m_spheroid);
}
template <typename Geometry>
@@ -289,10 +292,12 @@ private:
typedef typename select_calculation_type
<Segment1, Segment2, CalculationType>::type calc_t;
+ typedef srs::spheroid<calc_t> spheroid_type;
+
static const calc_t c0 = 0;
// normalized spheroid
- srs::spheroid<calc_t> spheroid = normalized_spheroid<calc_t>(m_spheroid);
+ spheroid_type spheroid = formula::unit_spheroid<spheroid_type>(m_spheroid);
// TODO: check only 2 first coordinates here?
using geometry::detail::equals::equals_point_point;
@@ -958,14 +963,6 @@ private:
ip_flag;
}
- template <typename CalcT, typename SpheroidT>
- static inline srs::spheroid<CalcT> normalized_spheroid(SpheroidT const& spheroid)
- {
- return srs::spheroid<CalcT>(CalcT(1),
- CalcT(get_radius<2>(spheroid)) // b/a
- / CalcT(get_radius<0>(spheroid)));
- }
-
private:
Spheroid m_spheroid;
};
diff --git a/boost/geometry/strategies/geographic/parameters.hpp b/boost/geometry/strategies/geographic/parameters.hpp
index 5638db50fa..4896e42e8d 100644
--- a/boost/geometry/strategies/geographic/parameters.hpp
+++ b/boost/geometry/strategies/geographic/parameters.hpp
@@ -12,7 +12,9 @@
#include <boost/geometry/formulas/andoyer_inverse.hpp>
+#include <boost/geometry/formulas/thomas_direct.hpp>
#include <boost/geometry/formulas/thomas_inverse.hpp>
+#include <boost/geometry/formulas/vincenty_direct.hpp>
#include <boost/geometry/formulas/vincenty_inverse.hpp>
#include <boost/mpl/assert.hpp>
@@ -24,6 +26,23 @@ namespace boost { namespace geometry { namespace strategy
struct andoyer
{
+ //TODO: this should be replaced by an andoyer direct formula
+ template
+ <
+ typename CT,
+ bool EnableCoordinates = true,
+ bool EnableReverseAzimuth = false,
+ bool EnableReducedLength = false,
+ bool EnableGeodesicScale = false
+ >
+ struct direct
+ : formula::thomas_direct
+ <
+ CT, EnableCoordinates, EnableReverseAzimuth,
+ EnableReducedLength, EnableGeodesicScale
+ >
+ {};
+
template
<
typename CT,
@@ -48,6 +67,22 @@ struct thomas
template
<
typename CT,
+ bool EnableCoordinates = true,
+ bool EnableReverseAzimuth = false,
+ bool EnableReducedLength = false,
+ bool EnableGeodesicScale = false
+ >
+ struct direct
+ : formula::thomas_direct
+ <
+ CT, EnableCoordinates, EnableReverseAzimuth,
+ EnableReducedLength, EnableGeodesicScale
+ >
+ {};
+
+ template
+ <
+ typename CT,
bool EnableDistance,
bool EnableAzimuth,
bool EnableReverseAzimuth = false,
@@ -69,6 +104,22 @@ struct vincenty
template
<
typename CT,
+ bool EnableCoordinates = true,
+ bool EnableReverseAzimuth = false,
+ bool EnableReducedLength = false,
+ bool EnableGeodesicScale = false
+ >
+ struct direct
+ : formula::vincenty_direct
+ <
+ CT, EnableCoordinates, EnableReverseAzimuth,
+ EnableReducedLength, EnableGeodesicScale
+ >
+ {};
+
+ template
+ <
+ typename CT,
bool EnableDistance,
bool EnableAzimuth,
bool EnableReverseAzimuth = false,
diff --git a/boost/geometry/strategies/geographic/point_in_poly_winding.hpp b/boost/geometry/strategies/geographic/point_in_poly_winding.hpp
new file mode 100644
index 0000000000..95a1961474
--- /dev/null
+++ b/boost/geometry/strategies/geographic/point_in_poly_winding.hpp
@@ -0,0 +1,80 @@
+// Boost.Geometry
+
+// Copyright (c) 2017 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_STRATEGY_GEOGRAPHIC_POINT_IN_POLY_WINDING_HPP
+#define BOOST_GEOMETRY_STRATEGY_GEOGRAPHIC_POINT_IN_POLY_WINDING_HPP
+
+
+#include <boost/geometry/strategies/geographic/side.hpp>
+#include <boost/geometry/strategies/spherical/point_in_poly_winding.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+namespace strategy { namespace within
+{
+
+
+/*!
+\brief Within detection using winding rule in geographic coordinate system.
+\ingroup strategies
+\tparam Point \tparam_point
+\tparam PointOfSegment \tparam_segment_point
+\tparam FormulaPolicy Geodesic formula policy
+\tparam Spheroid Spheroid model
+\tparam CalculationType \tparam_calculation
+
+\qbk{
+[heading See also]
+[link geometry.reference.algorithms.within.within_3_with_strategy within (with strategy)]
+}
+ */
+template
+<
+ typename Point,
+ typename PointOfSegment = Point,
+ typename FormulaPolicy = strategy::andoyer,
+ typename Spheroid = srs::spheroid<double>,
+ typename CalculationType = void
+>
+class geographic_winding
+ : public within::detail::spherical_winding_base
+ <
+ Point,
+ PointOfSegment,
+ side::geographic<FormulaPolicy, Spheroid, CalculationType>,
+ CalculationType
+ >
+{
+ typedef within::detail::spherical_winding_base
+ <
+ Point,
+ PointOfSegment,
+ side::geographic<FormulaPolicy, Spheroid, CalculationType>,
+ CalculationType
+ > base_t;
+
+public:
+ geographic_winding()
+ {}
+
+ explicit geographic_winding(Spheroid const& model)
+ : base_t(model)
+ {}
+};
+
+
+}} // namespace strategy::within
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_STRATEGY_GEOGRAPHIC_POINT_IN_POLY_WINDING_HPP
diff --git a/boost/geometry/strategies/spherical/area.hpp b/boost/geometry/strategies/spherical/area.hpp
index 206b734548..1ab61b644f 100644
--- a/boost/geometry/strategies/spherical/area.hpp
+++ b/boost/geometry/strategies/spherical/area.hpp
@@ -127,14 +127,15 @@ public :
{
if (! geometry::math::equals(get<0>(p1), get<0>(p2)))
{
+ typedef geometry::formula::area_formulas<CT> area_formulas;
- state.m_sum += geometry::formula::area_formulas
- <CT>::template spherical<LongSegment>(p1, p2);
+ state.m_sum += area_formulas::template spherical<LongSegment>(p1, p2);
// Keep track whenever a segment crosses the prime meridian
- geometry::formula::area_formulas
- <CT>::crosses_prime_meridian(p1, p2, state);
-
+ if (area_formulas::crosses_prime_meridian(p1, p2))
+ {
+ state.m_crosses_prime_meridian++;
+ }
}
}
diff --git a/boost/geometry/strategies/spherical/compare.hpp b/boost/geometry/strategies/spherical/compare.hpp
new file mode 100644
index 0000000000..26163f7406
--- /dev/null
+++ b/boost/geometry/strategies/spherical/compare.hpp
@@ -0,0 +1,321 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// This file was modified by Oracle on 2017.
+// Modifications copyright (c) 2017, 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_STRATEGIES_SPHERICAL_COMPARE_HPP
+#define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_COMPARE_HPP
+
+
+#include <boost/mpl/if.hpp>
+#include <boost/mpl/min.hpp>
+
+#include <boost/type_traits/is_same.hpp>
+
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/coordinate_dimension.hpp>
+#include <boost/geometry/core/coordinate_system.hpp>
+#include <boost/geometry/core/coordinate_type.hpp>
+#include <boost/geometry/core/cs.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/strategies/compare.hpp>
+
+#include <boost/geometry/util/math.hpp>
+#include <boost/geometry/util/normalize_spheroidal_coordinates.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+namespace strategy { namespace compare
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail
+{
+
+template <std::size_t I, typename P>
+static inline typename geometry::coordinate_type<P>::type
+get(P const& p, boost::true_type /*same units*/)
+{
+ return geometry::get<I>(p);
+}
+
+template <std::size_t I, typename P>
+static inline typename geometry::coordinate_type<P>::type
+get(P const& p, boost::false_type /*different units*/)
+{
+ return geometry::get_as_radian<I>(p);
+}
+
+template
+<
+ typename ComparePolicy,
+ typename Point1,
+ typename Point2,
+ std::size_t DimensionCount
+>
+struct spherical_latitude
+{
+ typedef typename geometry::coordinate_type<Point1>::type coordinate1_type;
+ typedef typename geometry::coordinate_system<Point1>::type::units units1_type;
+ typedef typename geometry::coordinate_type<Point2>::type coordinate2_type;
+ typedef typename geometry::coordinate_system<Point2>::type::units units2_type;
+ typedef typename boost::is_same<units1_type, units2_type>::type same_units_type;
+
+ template <typename T1, typename T2>
+ static inline bool apply(Point1 const& left, Point2 const& right,
+ T1 const& l1, T2 const& r1)
+ {
+ // latitudes equal
+ if (math::equals(l1, r1))
+ {
+ return compare::detail::compare_loop
+ <
+ ComparePolicy, 2, DimensionCount
+ >::apply(left, right);
+ }
+ else
+ {
+ return ComparePolicy::apply(l1, r1);
+ }
+ }
+
+ static inline bool apply(Point1 const& left, Point2 const& right)
+ {
+ coordinate1_type const& l1 = compare::detail::get<1>(left, same_units_type());
+ coordinate2_type const& r1 = compare::detail::get<1>(right, same_units_type());
+
+ return apply(left, right, l1, r1);
+ }
+};
+
+template
+<
+ typename ComparePolicy,
+ typename Point1,
+ typename Point2
+>
+struct spherical_latitude<ComparePolicy, Point1, Point2, 1>
+{
+ template <typename T1, typename T2>
+ static inline bool apply(Point1 const& left, Point2 const& right,
+ T1 const& , T2 const& )
+ {
+ return apply(left, right);
+ }
+
+ static inline bool apply(Point1 const& left, Point2 const& right)
+ {
+ return compare::detail::compare_loop
+ <
+ ComparePolicy, 1, 1
+ >::apply(left, right);
+ }
+};
+
+template
+<
+ typename ComparePolicy,
+ typename Point1,
+ typename Point2,
+ std::size_t DimensionCount
+>
+struct spherical_longitude
+{
+ typedef typename geometry::coordinate_type<Point1>::type coordinate1_type;
+ typedef typename geometry::coordinate_system<Point1>::type::units units1_type;
+ typedef typename geometry::coordinate_type<Point2>::type coordinate2_type;
+ typedef typename geometry::coordinate_system<Point2>::type::units units2_type;
+ typedef typename boost::is_same<units1_type, units2_type>::type same_units_type;
+ typedef typename boost::mpl::if_<same_units_type, units1_type, geometry::radian>::type units_type;
+
+ static const bool is_equatorial = ! boost::is_same
+ <
+ typename geometry::cs_tag<Point1>::type,
+ geometry::spherical_polar_tag
+ >::value;
+
+ static inline bool are_both_at_antimeridian(coordinate1_type const& l0,
+ coordinate2_type const& r0,
+ bool & is_left_at,
+ bool & is_right_at)
+ {
+ is_left_at = math::is_longitude_antimeridian<units_type>(l0);
+ is_right_at = math::is_longitude_antimeridian<units_type>(r0);
+ return is_left_at && is_right_at;
+ }
+
+ static inline bool apply(Point1 const& left, Point2 const& right)
+ {
+ // if units are different the coordinates are in radians
+ coordinate1_type const& l0 = compare::detail::get<0>(left, same_units_type());
+ coordinate2_type const& r0 = compare::detail::get<0>(right, same_units_type());
+ coordinate1_type const& l1 = compare::detail::get<1>(left, same_units_type());
+ coordinate2_type const& r1 = compare::detail::get<1>(right, same_units_type());
+
+ bool is_left_at_antimeridian = false;
+ bool is_right_at_antimeridian = false;
+
+ // longitudes equal
+ if (math::equals(l0, r0)
+ // both at antimeridian
+ || are_both_at_antimeridian(l0, r0, is_left_at_antimeridian, is_right_at_antimeridian)
+ // both at pole
+ || (math::equals(l1, r1)
+ && math::is_latitude_pole<units_type, is_equatorial>(l1)))
+ {
+ return spherical_latitude
+ <
+ ComparePolicy, Point1, Point2, DimensionCount
+ >::apply(left, right, l1, r1);
+ }
+ // if left is at antimeridian and right is not at antimeridian
+ // then left is greater than right
+ else if (is_left_at_antimeridian)
+ {
+ // less/equal_to -> false, greater -> true
+ return ComparePolicy::apply(1, 0);
+ }
+ // if right is at antimeridian and left is not at antimeridian
+ // then left is lesser than right
+ else if (is_right_at_antimeridian)
+ {
+ // less -> true, equal_to/greater -> false
+ return ComparePolicy::apply(0, 1);
+ }
+ else
+ {
+ return ComparePolicy::apply(l0, r0);
+ }
+ }
+};
+
+
+} // namespace detail
+#endif // DOXYGEN_NO_DETAIL
+
+
+/*!
+\brief Compare strategy for spherical coordinates
+\ingroup strategies
+\tparam Point point-type
+\tparam Dimension dimension
+*/
+template
+<
+ typename ComparePolicy,
+ int Dimension = -1
+>
+struct spherical
+ : cartesian<ComparePolicy, Dimension>
+{};
+
+#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
+// all dimensions starting from longitude
+template <typename ComparePolicy>
+struct spherical<ComparePolicy, -1>
+{
+ template <typename Point1, typename Point2>
+ static inline bool apply(Point1 const& left, Point2 const& right)
+ {
+ return compare::detail::spherical_longitude
+ <
+ ComparePolicy,
+ Point1,
+ Point2,
+ boost::mpl::min
+ <
+ geometry::dimension<Point1>,
+ geometry::dimension<Point2>
+ >::type::value
+ >::apply(left, right);
+ }
+};
+
+// only longitudes (and latitudes to check poles)
+template <typename ComparePolicy>
+struct spherical<ComparePolicy, 0>
+{
+ template <typename Point1, typename Point2>
+ static inline bool apply(Point1 const& left, Point2 const& right)
+ {
+ return compare::detail::spherical_longitude
+ <
+ ComparePolicy, Point1, Point2, 1
+ >::apply(left, right);
+ }
+};
+
+// only latitudes
+template <typename ComparePolicy>
+struct spherical<ComparePolicy, 1>
+{
+ template <typename Point1, typename Point2>
+ static inline bool apply(Point1 const& left, Point2 const& right)
+ {
+ return compare::detail::spherical_latitude
+ <
+ ComparePolicy, Point1, Point2, 2
+ >::apply(left, right);
+ }
+};
+
+#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
+
+
+namespace services
+{
+
+
+template <typename ComparePolicy, typename Point1, typename Point2, int Dimension>
+struct default_strategy
+ <
+ ComparePolicy, Point1, Point2, Dimension,
+ spherical_polar_tag, spherical_polar_tag
+ >
+{
+ typedef compare::spherical<ComparePolicy, Dimension> type;
+};
+
+template <typename ComparePolicy, typename Point1, typename Point2, int Dimension>
+struct default_strategy
+ <
+ ComparePolicy, Point1, Point2, Dimension,
+ spherical_equatorial_tag, spherical_equatorial_tag
+ >
+{
+ typedef compare::spherical<ComparePolicy, Dimension> type;
+};
+
+template <typename ComparePolicy, typename Point1, typename Point2, int Dimension>
+struct default_strategy
+ <
+ ComparePolicy, Point1, Point2, Dimension,
+ geographic_tag, geographic_tag
+ >
+{
+ typedef compare::spherical<ComparePolicy, Dimension> type;
+};
+
+
+} // namespace services
+
+
+}} // namespace strategy::compare
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_COMPARE_HPP
diff --git a/boost/geometry/strategies/spherical/compare_circular.hpp b/boost/geometry/strategies/spherical/compare_circular.hpp
deleted file mode 100644
index 2f890dfd87..0000000000
--- a/boost/geometry/strategies/spherical/compare_circular.hpp
+++ /dev/null
@@ -1,152 +0,0 @@
-// Boost.Geometry (aka GGL, Generic Geometry Library)
-
-// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
-
-// Use, modification and distribution is subject to the Boost Software License,
-// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
-// http://www.boost.org/LICENSE_1_0.txt)
-
-#ifndef BOOST_GEOMETRY_STRATEGIES_SPHERICAL_COMPARE_SPHERICAL_HPP
-#define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_COMPARE_SPHERICAL_HPP
-
-#include <boost/math/constants/constants.hpp>
-
-#include <boost/geometry/core/cs.hpp>
-#include <boost/geometry/core/tags.hpp>
-#include <boost/geometry/strategies/compare.hpp>
-#include <boost/geometry/util/math.hpp>
-
-
-namespace boost { namespace geometry
-{
-
-
-namespace strategy { namespace compare
-{
-
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail
-{
-
-template <typename Units>
-struct shift
-{
-};
-
-template <>
-struct shift<degree>
-{
- static inline double full() { return 360.0; }
- static inline double half() { return 180.0; }
-};
-
-template <>
-struct shift<radian>
-{
- static inline double full() { return 2.0 * boost::math::constants::pi<double>(); }
- static inline double half() { return boost::math::constants::pi<double>(); }
-};
-
-} // namespace detail
-#endif
-
-/*!
-\brief Compare (in one direction) strategy for spherical coordinates
-\ingroup strategies
-\tparam Point point-type
-\tparam Dimension dimension
-*/
-template <typename CoordinateType, typename Units, typename Compare>
-struct circular_comparator
-{
- static inline CoordinateType put_in_range(CoordinateType const& c,
- double min_border, double max_border)
- {
- CoordinateType value = c;
- while (value < min_border)
- {
- value += detail::shift<Units>::full();
- }
- while (value > max_border)
- {
- value -= detail::shift<Units>::full();
- }
- return value;
- }
-
- inline bool operator()(CoordinateType const& c1, CoordinateType const& c2) const
- {
- Compare compare;
-
- // Check situation that one of them is e.g. std::numeric_limits.
- static const double full = detail::shift<Units>::full();
- double mx = 10.0 * full;
- if (c1 < -mx || c1 > mx || c2 < -mx || c2 > mx)
- {
- // do normal comparison, using circular is not useful
- return compare(c1, c2);
- }
-
- static const double half = full / 2.0;
- CoordinateType v1 = put_in_range(c1, -half, half);
- CoordinateType v2 = put_in_range(c2, -half, half);
-
- // Two coordinates on a circle are
- // at max <= half a circle away from each other.
- // So if it is more, shift origin.
- CoordinateType diff = geometry::math::abs(v1 - v2);
- if (diff > half)
- {
- v1 = put_in_range(v1, 0, full);
- v2 = put_in_range(v2, 0, full);
- }
-
- return compare(v1, v2);
- }
-};
-
-}} // namespace strategy::compare
-
-#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
-
-// Specialize for the longitude (dim 0)
-template
-<
- typename Point,
- template<typename> class CoordinateSystem,
- typename Units
->
-struct strategy_compare<spherical_polar_tag, 1, Point, CoordinateSystem<Units>, 0>
-{
- typedef typename coordinate_type<Point>::type coordinate_type;
- typedef strategy::compare::circular_comparator
- <
- coordinate_type,
- Units,
- std::less<coordinate_type>
- > type;
-};
-
-template
-<
- typename Point,
- template<typename> class CoordinateSystem,
- typename Units
->
-struct strategy_compare<spherical_polar_tag, -1, Point, CoordinateSystem<Units>, 0>
-{
- typedef typename coordinate_type<Point>::type coordinate_type;
- typedef strategy::compare::circular_comparator
- <
- coordinate_type,
- Units,
- std::greater<coordinate_type>
- > type;
-};
-
-#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
-
-}} // namespace boost::geometry
-
-#endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_COMPARE_SPHERICAL_HPP
diff --git a/boost/geometry/strategies/spherical/distance_cross_track.hpp b/boost/geometry/strategies/spherical/distance_cross_track.hpp
index 7daafa4a16..82a2fb3d6f 100644
--- a/boost/geometry/strategies/spherical/distance_cross_track.hpp
+++ b/boost/geometry/strategies/spherical/distance_cross_track.hpp
@@ -2,9 +2,10 @@
// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
-// This file was modified by Oracle on 2014.
-// Modifications copyright (c) 2014, Oracle and/or its affiliates.
+// This file was modified by Oracle on 2014-2017.
+// Modifications copyright (c) 2014-2017, Oracle and/or its affiliates.
+// Contributed and/or modified by Vissarion Fysikopoulos, 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,
@@ -26,8 +27,6 @@
#include <boost/geometry/core/radian_access.hpp>
#include <boost/geometry/core/tags.hpp>
-#include <boost/geometry/algorithms/detail/course.hpp>
-
#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/strategies/concepts/distance_concept.hpp>
#include <boost/geometry/strategies/spherical/distance_haversine.hpp>
@@ -373,19 +372,6 @@ public :
typedef typename return_type<Point, PointOfSegment>::type return_type;
-#ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK
- std::cout << "Course " << dsv(sp1) << " to " << dsv(p) << " "
- << crs_AD * geometry::math::r2d<return_type>() << std::endl;
- std::cout << "Course " << dsv(sp1) << " to " << dsv(sp2) << " "
- << crs_AB * geometry::math::r2d<return_type>() << std::endl;
- std::cout << "Course " << dsv(sp2) << " to " << dsv(p) << " "
- << crs_BD * geometry::math::r2d << std::endl;
- std::cout << "Projection AD-AB " << projection1 << " : "
- << d_crs1 * geometry::math::r2d<return_type>() << std::endl;
- std::cout << "Projection BD-BA " << projection2 << " : "
- << d_crs2 * geometry::math::r2d<return_type>() << std::endl;
-#endif
-
// http://williams.best.vwh.net/avform.htm#XTE
return_type d1 = m_strategy.apply(sp1, p);
return_type d3 = m_strategy.apply(sp1, sp2);
@@ -398,10 +384,25 @@ public :
return_type d2 = m_strategy.apply(sp2, p);
- return_type crs_AD = geometry::detail::course<return_type>(sp1, p);
- return_type crs_AB = geometry::detail::course<return_type>(sp1, sp2);
- return_type crs_BA = crs_AB - geometry::math::pi<return_type>();
- return_type crs_BD = geometry::detail::course<return_type>(sp2, p);
+ return_type lon1 = geometry::get_as_radian<0>(sp1);
+ return_type lat1 = geometry::get_as_radian<1>(sp1);
+ return_type lon2 = geometry::get_as_radian<0>(sp2);
+ return_type lat2 = geometry::get_as_radian<1>(sp2);
+ return_type lon = geometry::get_as_radian<0>(p);
+ return_type lat = geometry::get_as_radian<1>(p);
+
+ return_type crs_AD = geometry::formula::spherical_azimuth<return_type, false>
+ (lon1, lat1, lon, lat).azimuth;
+
+ geometry::formula::result_spherical<return_type> result =
+ geometry::formula::spherical_azimuth<return_type, true>
+ (lon1, lat1, lon2, lat2);
+ return_type crs_AB = result.azimuth;
+ return_type crs_BA = result.reverse_azimuth - geometry::math::pi<return_type>();
+
+ return_type crs_BD = geometry::formula::spherical_azimuth<return_type, false>
+ (lon2, lat2, lon, lat).azimuth;
+
return_type d_crs1 = crs_AD - crs_AB;
return_type d_crs2 = crs_BD - crs_BA;
@@ -409,6 +410,24 @@ public :
return_type projection1 = cos( d_crs1 ) * d1 / d3;
return_type projection2 = cos( d_crs2 ) * d2 / d3;
+#ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK
+ std::cout << "Course " << dsv(sp1) << " to " << dsv(p) << " "
+ << crs_AD * geometry::math::r2d<return_type>() << std::endl;
+ std::cout << "Course " << dsv(sp1) << " to " << dsv(sp2) << " "
+ << crs_AB * geometry::math::r2d<return_type>() << std::endl;
+ std::cout << "Course " << dsv(sp2) << " to " << dsv(sp1) << " "
+ << crs_BA * geometry::math::r2d<return_type>() << std::endl;
+ std::cout << "Course " << dsv(sp2) << " to " << dsv(p) << " "
+ << crs_BD * geometry::math::r2d<return_type>() << std::endl;
+ std::cout << "Projection AD-AB " << projection1 << " : "
+ << d_crs1 * geometry::math::r2d<return_type>() << std::endl;
+ std::cout << "Projection BD-BA " << projection2 << " : "
+ << d_crs2 * geometry::math::r2d<return_type>() << std::endl;
+ std::cout << " d1: " << (d1 )
+ << " d2: " << (d2 )
+ << std::endl;
+#endif
+
if (projection1 > 0.0 && projection2 > 0.0)
{
#ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK
diff --git a/boost/geometry/strategies/spherical/intersection.hpp b/boost/geometry/strategies/spherical/intersection.hpp
index 44b1cc62bf..b5ae878b85 100644
--- a/boost/geometry/strategies/spherical/intersection.hpp
+++ b/boost/geometry/strategies/spherical/intersection.hpp
@@ -33,7 +33,6 @@
#include <boost/geometry/policies/robustness/segment_ratio.hpp>
-#include <boost/geometry/strategies/agnostic/point_in_poly_winding.hpp>
#include <boost/geometry/strategies/covered_by.hpp>
#include <boost/geometry/strategies/intersection.hpp>
#include <boost/geometry/strategies/intersection_result.hpp>
@@ -42,6 +41,7 @@
#include <boost/geometry/strategies/spherical/area.hpp>
#include <boost/geometry/strategies/spherical/distance_haversine.hpp>
#include <boost/geometry/strategies/spherical/envelope_segment.hpp>
+#include <boost/geometry/strategies/spherical/point_in_poly_winding.hpp>
#include <boost/geometry/strategies/spherical/ssf.hpp>
#include <boost/geometry/strategies/within.hpp>
@@ -94,11 +94,10 @@ struct ecef_segments
template <typename Geometry1, typename Geometry2>
struct point_in_geometry_strategy
{
- typedef strategy::within::winding
+ typedef strategy::within::spherical_winding
<
typename point_type<Geometry1>::type,
typename point_type<Geometry2>::type,
- side_strategy_type,
CalculationType
> type;
};
diff --git a/boost/geometry/strategies/spherical/point_in_poly_winding.hpp b/boost/geometry/strategies/spherical/point_in_poly_winding.hpp
new file mode 100644
index 0000000000..0f1a901d13
--- /dev/null
+++ b/boost/geometry/strategies/spherical/point_in_poly_winding.hpp
@@ -0,0 +1,581 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2013, 2014, 2016, 2017.
+// Modifications copyright (c) 2013-2017 Oracle and/or its affiliates.
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_STRATEGY_SPHERICAL_POINT_IN_POLY_WINDING_HPP
+#define BOOST_GEOMETRY_STRATEGY_SPHERICAL_POINT_IN_POLY_WINDING_HPP
+
+
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/coordinate_system.hpp>
+#include <boost/geometry/core/cs.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/util/math.hpp>
+#include <boost/geometry/util/select_calculation_type.hpp>
+#include <boost/geometry/util/normalize_spheroidal_coordinates.hpp>
+
+#include <boost/geometry/strategies/covered_by.hpp>
+#include <boost/geometry/strategies/side.hpp>
+#include <boost/geometry/strategies/spherical/ssf.hpp>
+#include <boost/geometry/strategies/within.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+namespace strategy { namespace within
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail
+{
+
+template
+<
+ typename Point,
+ typename PointOfSegment = Point,
+ typename SideStrategy = typename strategy::side::services::default_strategy
+ <
+ typename cs_tag<Point>::type
+ >::type,
+ typename CalculationType = void
+>
+class spherical_winding_base
+{
+ typedef typename select_calculation_type
+ <
+ Point,
+ PointOfSegment,
+ CalculationType
+ >::type calculation_type;
+
+ typedef typename coordinate_system<Point>::type::units units_t;
+ typedef math::detail::constants_on_spheroid<calculation_type, units_t> constants;
+
+ /*! subclass to keep state */
+ class counter
+ {
+ int m_count;
+ //int m_count_n;
+ int m_count_s;
+ int m_raw_count;
+ int m_raw_count_anti;
+ bool m_touches;
+
+ inline int code() const
+ {
+ if (m_touches)
+ {
+ return 0;
+ }
+
+ if (m_raw_count != 0 && m_raw_count_anti != 0)
+ {
+ if (m_raw_count > 0) // right, wrap around south pole
+ {
+ return (m_count + m_count_s) == 0 ? -1 : 1;
+ }
+ else // left, wrap around north pole
+ {
+ //return (m_count + m_count_n) == 0 ? -1 : 1;
+ // m_count_n is 0
+ return m_count == 0 ? -1 : 1;
+ }
+ }
+
+ return m_count == 0 ? -1 : 1;
+ }
+
+ public :
+ friend class spherical_winding_base;
+
+ inline counter()
+ : m_count(0)
+ //, m_count_n(0)
+ , m_count_s(0)
+ , m_raw_count(0)
+ , m_raw_count_anti(0)
+ , m_touches(false)
+ {}
+
+ };
+
+ struct count_info
+ {
+ explicit count_info(int c = 0, bool ia = false)
+ : count(c)
+ , is_anti(ia)
+ {}
+
+ int count;
+ bool is_anti;
+ };
+
+public:
+ typedef typename SideStrategy::envelope_strategy_type envelope_strategy_type;
+
+ inline envelope_strategy_type get_envelope_strategy() const
+ {
+ return m_side_strategy.get_envelope_strategy();
+ }
+
+ typedef typename SideStrategy::disjoint_strategy_type disjoint_strategy_type;
+
+ inline disjoint_strategy_type get_disjoint_strategy() const
+ {
+ return m_side_strategy.get_disjoint_strategy();
+ }
+
+ spherical_winding_base()
+ {}
+
+ template <typename Model>
+ explicit spherical_winding_base(Model const& model)
+ : m_side_strategy(model)
+ {}
+
+ // Typedefs and static methods to fulfill the concept
+ typedef Point point_type;
+ typedef PointOfSegment segment_point_type;
+ typedef counter state_type;
+
+ inline bool apply(Point const& point,
+ PointOfSegment const& s1, PointOfSegment const& s2,
+ counter& state) const
+ {
+ bool eq1 = false;
+ bool eq2 = false;
+ bool s_antipodal = false;
+
+ count_info ci = check_segment(point, s1, s2, state, eq1, eq2, s_antipodal);
+ if (ci.count != 0)
+ {
+ if (! ci.is_anti)
+ {
+ int side = 0;
+ if (ci.count == 1 || ci.count == -1)
+ {
+ side = side_equal(point, eq1 ? s1 : s2, ci, s1, s2);
+ }
+ else // count == 2 || count == -2
+ {
+ if (! s_antipodal)
+ {
+ // 1 left, -1 right
+ side = m_side_strategy.apply(s1, s2, point);
+ }
+ else
+ {
+ calculation_type const pi = constants::half_period();
+ calculation_type const s1_lat = get<1>(s1);
+ calculation_type const s2_lat = get<1>(s2);
+
+ side = math::sign(ci.count)
+ * (pi - s1_lat - s2_lat <= pi // segment goes through north pole
+ ? -1 // going right all points will be on right side
+ : 1); // going right all points will be on left side
+ }
+ }
+
+ if (side == 0)
+ {
+ // Point is lying on segment
+ state.m_touches = true;
+ state.m_count = 0;
+ return false;
+ }
+
+ // Side is NEG for right, POS for left.
+ // The count is -2 for left, 2 for right (or -1/1)
+ // Side positive thus means RIGHT and LEFTSIDE or LEFT and RIGHTSIDE
+ // See accompagnying figure (TODO)
+ if (side * ci.count > 0)
+ {
+ state.m_count += ci.count;
+ }
+
+ state.m_raw_count += ci.count;
+ }
+ else
+ {
+ // Count negated because the segment is on the other side of the globe
+ // so it is reversed to match this side of the globe
+
+ // Assuming geometry wraps around north pole, for segments on the other side of the globe
+ // the point will always be RIGHT+RIGHTSIDE or LEFT+LEFTSIDE, so side*-count always < 0
+ //state.m_count_n -= 0;
+
+ // Assuming geometry wraps around south pole, for segments on the other side of the globe
+ // the point will always be RIGHT+LEFTSIDE or LEFT+RIGHTSIDE, so side*-count always > 0
+ state.m_count_s -= ci.count;
+
+ state.m_raw_count_anti -= ci.count;
+ }
+ }
+ return ! state.m_touches;
+ }
+
+ static inline int result(counter const& state)
+ {
+ return state.code();
+ }
+
+private:
+
+ static inline count_info check_segment(Point const& point,
+ PointOfSegment const& seg1,
+ PointOfSegment const& seg2,
+ counter& state,
+ bool& eq1, bool& eq2, bool& s_antipodal)
+ {
+ if (check_touch(point, seg1, seg2, state, eq1, eq2, s_antipodal))
+ {
+ return count_info(0, false);
+ }
+
+ return calculate_count(point, seg1, seg2, eq1, eq2, s_antipodal);
+ }
+
+ static inline int check_touch(Point const& point,
+ PointOfSegment const& seg1,
+ PointOfSegment const& seg2,
+ counter& state,
+ bool& eq1,
+ bool& eq2,
+ bool& s_antipodal)
+ {
+ calculation_type const c0 = 0;
+ calculation_type const c2 = 2;
+ calculation_type const pi = constants::half_period();
+ calculation_type const half_pi = pi / c2;
+
+ calculation_type const p_lon = get<0>(point);
+ calculation_type const s1_lon = get<0>(seg1);
+ calculation_type const s2_lon = get<0>(seg2);
+ calculation_type const p_lat = get<1>(point);
+ calculation_type const s1_lat = get<1>(seg1);
+ calculation_type const s2_lat = get<1>(seg2);
+
+ // NOTE: lat in {-90, 90} and arbitrary lon
+ // it doesn't matter what lon it is if it's a pole
+ // so e.g. if one of the segment endpoints is a pole
+ // then only the other lon matters
+
+ bool eq1_strict = longitudes_equal(s1_lon, p_lon);
+ bool eq2_strict = longitudes_equal(s2_lon, p_lon);
+ bool eq1_anti = false;
+ bool eq2_anti = false;
+
+ calculation_type const anti_p_lon = p_lon + (p_lon <= c0 ? pi : -pi);
+
+ eq1 = eq1_strict // lon strictly equal to s1
+ || (eq1_anti = longitudes_equal(s1_lon, anti_p_lon)) // anti-lon strictly equal to s1
+ || math::equals(math::abs(s1_lat), half_pi); // s1 is pole
+ eq2 = eq2_strict // lon strictly equal to s2
+ || (eq2_anti = longitudes_equal(s2_lon, anti_p_lon)) // anti-lon strictly equal to s2
+ || math::equals(math::abs(s2_lat), half_pi); // s2 is pole
+
+ // segment overlapping pole
+ calculation_type const s_lon_diff = math::longitude_distance_signed<units_t>(s1_lon, s2_lon);
+ s_antipodal = math::equals(s_lon_diff, pi);
+ if (s_antipodal)
+ {
+ eq1 = eq2 = eq1 || eq2;
+
+ // segment overlapping pole and point is pole
+ if (math::equals(math::abs(p_lat), half_pi))
+ {
+ eq1 = eq2 = true;
+ }
+ }
+
+ // Both equal p -> segment vertical
+ // The only thing which has to be done is check if point is ON segment
+ if (eq1 && eq2)
+ {
+ // segment endpoints on the same sides of the globe
+ if (! s_antipodal)
+ {
+ // p's lat between segment endpoints' lats
+ if ( (s1_lat <= p_lat && s2_lat >= p_lat) || (s2_lat <= p_lat && s1_lat >= p_lat) )
+ {
+ if (!eq1_anti || !eq2_anti)
+ {
+ state.m_touches = true;
+ }
+ }
+ }
+ else
+ {
+ // going through north or south pole?
+ if (pi - s1_lat - s2_lat <= pi)
+ {
+ if ( (eq1_strict && s1_lat <= p_lat) || (eq2_strict && s2_lat <= p_lat) // north
+ || math::equals(p_lat, half_pi) ) // point on north pole
+ {
+ state.m_touches = true;
+ }
+ else if (! eq1_strict && ! eq2_strict && math::equals(p_lat, -half_pi) ) // point on south pole
+ {
+ return false;
+ }
+ }
+ else // south pole
+ {
+ if ( (eq1_strict && s1_lat >= p_lat) || (eq2_strict && s2_lat >= p_lat) // south
+ || math::equals(p_lat, -half_pi) ) // point on south pole
+ {
+ state.m_touches = true;
+ }
+ else if (! eq1_strict && ! eq2_strict && math::equals(p_lat, half_pi) ) // point on north pole
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ // Called if point is not aligned with a vertical segment
+ static inline count_info calculate_count(Point const& point,
+ PointOfSegment const& seg1,
+ PointOfSegment const& seg2,
+ bool eq1, bool eq2, bool s_antipodal)
+ {
+ // If both segment endpoints were poles below checks wouldn't be enough
+ // but this means that either both are the same or that they are N/S poles
+ // and therefore the segment is not valid.
+ // If needed (eq1 && eq2 ? 0) could be returned
+
+ calculation_type const c0 = 0;
+ calculation_type const pi = constants::half_period();
+
+ calculation_type const p = get<0>(point);
+ calculation_type const s1 = get<0>(seg1);
+ calculation_type const s2 = get<0>(seg2);
+
+ calculation_type const s1_p = math::longitude_distance_signed<units_t>(s1, p);
+
+ if (s_antipodal)
+ {
+ return count_info(s1_p < c0 ? -2 : 2, false); // choose W/E
+ }
+
+ calculation_type const s1_s2 = math::longitude_distance_signed<units_t>(s1, s2);
+
+ if (eq1 || eq2) // Point on level s1 or s2
+ {
+ return count_info(s1_s2 < c0 ? -1 : 1, // choose W/E
+ longitudes_equal(p + pi, (eq1 ? s1 : s2)));
+ }
+
+ // Point between s1 and s2
+ if ( math::sign(s1_p) == math::sign(s1_s2)
+ && math::abs(s1_p) < math::abs(s1_s2) )
+ {
+ return count_info(s1_s2 < c0 ? -2 : 2, false); // choose W/E
+ }
+
+ calculation_type const s1_p_anti = math::longitude_distance_signed<units_t>(s1, p + pi);
+
+ // Anti-Point between s1 and s2
+ if ( math::sign(s1_p_anti) == math::sign(s1_s2)
+ && math::abs(s1_p_anti) < math::abs(s1_s2) )
+ {
+ return count_info(s1_s2 < c0 ? -2 : 2, true); // choose W/E
+ }
+
+ return count_info(0, false);
+ }
+
+
+ // Fix for https://svn.boost.org/trac/boost/ticket/9628
+ // For floating point coordinates, the <D> coordinate of a point is compared
+ // with the segment's points using some EPS. If the coordinates are "equal"
+ // the sides are calculated. Therefore we can treat a segment as a long areal
+ // geometry having some width. There is a small ~triangular area somewhere
+ // between the segment's effective area and a segment's line used in sides
+ // calculation where the segment is on the one side of the line but on the
+ // other side of a segment (due to the width).
+ // Below picture assuming D = 1, if D = 0 horiz<->vert, E<->N, RIGHT<->UP.
+ // For the s1 of a segment going NE the real side is RIGHT but the point may
+ // be detected as LEFT, like this:
+ // RIGHT
+ // ___----->
+ // ^ O Pt __ __
+ // EPS __ __
+ // v__ __ BUT DETECTED AS LEFT OF THIS LINE
+ // _____7
+ // _____/
+ // _____/
+ // In the code below actually D = 0, so segments are nearly-vertical
+ // Called when the point is on the same level as one of the segment's points
+ // but the point is not aligned with a vertical segment
+ inline int side_equal(Point const& point,
+ PointOfSegment const& se,
+ count_info const& ci,
+ PointOfSegment const& s1, PointOfSegment const& s2) const
+ {
+ typedef typename coordinate_type<PointOfSegment>::type scoord_t;
+ typedef typename coordinate_system<PointOfSegment>::type::units units_t;
+
+ if (math::equals(get<1>(point), get<1>(se)))
+ {
+ return 0;
+ }
+
+ // Create a horizontal segment intersecting the original segment's endpoint
+ // equal to the point, with the derived direction (E/W).
+ PointOfSegment ss1, ss2;
+ set<1>(ss1, get<1>(se));
+ set<0>(ss1, get<0>(se));
+ set<1>(ss2, get<1>(se));
+ scoord_t ss20 = get<0>(se);
+ if (ci.count > 0)
+ {
+ ss20 += small_angle();
+ }
+ else
+ {
+ ss20 -= small_angle();
+ }
+ math::normalize_longitude<units_t>(ss20);
+ set<0>(ss2, ss20);
+
+ // Check the side using this vertical segment
+ return m_side_strategy.apply(ss1, ss2, point);
+ }
+
+ // 1 deg or pi/180 rad
+ static inline calculation_type small_angle()
+ {
+ return constants::half_period() / calculation_type(180);
+ };
+
+ static inline bool longitudes_equal(calculation_type const& lon1, calculation_type const& lon2)
+ {
+ return math::equals(
+ math::longitude_distance_signed<units_t>(lon1, lon2),
+ calculation_type(0));
+ }
+
+ SideStrategy m_side_strategy;
+};
+
+
+} // namespace detail
+#endif // DOXYGEN_NO_DETAIL
+
+
+/*!
+\brief Within detection using winding rule in spherical coordinate system.
+\ingroup strategies
+\tparam Point \tparam_point
+\tparam PointOfSegment \tparam_segment_point
+\tparam CalculationType \tparam_calculation
+
+\qbk{
+[heading See also]
+[link geometry.reference.algorithms.within.within_3_with_strategy within (with strategy)]
+}
+ */
+template
+<
+ typename Point,
+ typename PointOfSegment = Point,
+ typename CalculationType = void
+>
+class spherical_winding
+ : public within::detail::spherical_winding_base
+ <
+ Point,
+ PointOfSegment,
+ side::spherical_side_formula<CalculationType>,
+ CalculationType
+ >
+{};
+
+
+#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
+
+namespace services
+{
+
+template <typename PointLike, typename Geometry, typename AnyTag1, typename AnyTag2>
+struct default_strategy<PointLike, Geometry, AnyTag1, AnyTag2, pointlike_tag, polygonal_tag, spherical_tag, spherical_tag>
+{
+ typedef within::detail::spherical_winding_base
+ <
+ typename geometry::point_type<PointLike>::type,
+ typename geometry::point_type<Geometry>::type
+ > type;
+};
+
+template <typename PointLike, typename Geometry, typename AnyTag1, typename AnyTag2>
+struct default_strategy<PointLike, Geometry, AnyTag1, AnyTag2, pointlike_tag, linear_tag, spherical_tag, spherical_tag>
+{
+ typedef within::detail::spherical_winding_base
+ <
+ typename geometry::point_type<PointLike>::type,
+ typename geometry::point_type<Geometry>::type
+ > type;
+};
+
+} // namespace services
+
+#endif
+
+
+}} // namespace strategy::within
+
+
+#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
+namespace strategy { namespace covered_by { namespace services
+{
+
+template <typename PointLike, typename Geometry, typename AnyTag1, typename AnyTag2>
+struct default_strategy<PointLike, Geometry, AnyTag1, AnyTag2, pointlike_tag, polygonal_tag, spherical_tag, spherical_tag>
+{
+ typedef within::detail::spherical_winding_base
+ <
+ typename geometry::point_type<PointLike>::type,
+ typename geometry::point_type<Geometry>::type
+ > type;
+};
+
+template <typename PointLike, typename Geometry, typename AnyTag1, typename AnyTag2>
+struct default_strategy<PointLike, Geometry, AnyTag1, AnyTag2, pointlike_tag, linear_tag, spherical_tag, spherical_tag>
+{
+ typedef within::detail::spherical_winding_base
+ <
+ typename geometry::point_type<PointLike>::type,
+ typename geometry::point_type<Geometry>::type
+ > type;
+};
+
+}}} // namespace strategy::covered_by::services
+#endif
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_STRATEGY_SPHERICAL_POINT_IN_POLY_WINDING_HPP
diff --git a/boost/geometry/strategies/spherical/side_by_cross_track.hpp b/boost/geometry/strategies/spherical/side_by_cross_track.hpp
index 3f7be05557..2b195e96f0 100644
--- a/boost/geometry/strategies/spherical/side_by_cross_track.hpp
+++ b/boost/geometry/strategies/spherical/side_by_cross_track.hpp
@@ -2,9 +2,10 @@
// 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.
+// This file was modified by Oracle on 2014-2017.
+// Modifications copyright (c) 2014-2017, Oracle and/or its affiliates.
+// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
@@ -18,7 +19,7 @@
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/radian_access.hpp>
-#include <boost/geometry/algorithms/detail/course.hpp>
+#include <boost/geometry/formulas/spherical.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/promote_floating_point.hpp>
@@ -59,8 +60,20 @@ public :
>::type calc_t;
calc_t d1 = 0.001; // m_strategy.apply(sp1, p);
- calc_t crs_AD = geometry::detail::course<calc_t>(p1, p);
- calc_t crs_AB = geometry::detail::course<calc_t>(p1, p2);
+
+ calc_t lon1 = geometry::get_as_radian<0>(p1);
+ calc_t lat1 = geometry::get_as_radian<1>(p1);
+ calc_t lon2 = geometry::get_as_radian<0>(p2);
+ calc_t lat2 = geometry::get_as_radian<1>(p2);
+ calc_t lon = geometry::get_as_radian<0>(p);
+ calc_t lat = geometry::get_as_radian<1>(p);
+
+ calc_t crs_AD = geometry::formula::spherical_azimuth<calc_t, false>
+ (lon1, lat1, lon, lat).azimuth;
+
+ calc_t crs_AB = geometry::formula::spherical_azimuth<calc_t, false>
+ (lon1, lat1, lon2, lat2).azimuth;
+
calc_t XTD = asin(sin(d1) * sin(crs_AD - crs_AB));
return math::equals(XTD, 0) ? 0 : XTD < 0 ? 1 : -1;
diff --git a/boost/geometry/strategies/strategies.hpp b/boost/geometry/strategies/strategies.hpp
index 27a025c7c4..e7f3604abf 100644
--- a/boost/geometry/strategies/strategies.hpp
+++ b/boost/geometry/strategies/strategies.hpp
@@ -65,6 +65,7 @@
#include <boost/geometry/strategies/cartesian/point_in_box.hpp>
#include <boost/geometry/strategies/cartesian/point_in_poly_franklin.hpp>
#include <boost/geometry/strategies/cartesian/point_in_poly_crossings_multiply.hpp>
+#include <boost/geometry/strategies/cartesian/point_in_poly_winding.hpp>
#include <boost/geometry/strategies/cartesian/side_by_triangle.hpp>
#include <boost/geometry/strategies/spherical/area.hpp>
@@ -73,9 +74,10 @@
#include <boost/geometry/strategies/spherical/distance_haversine.hpp>
#include <boost/geometry/strategies/spherical/distance_cross_track.hpp>
#include <boost/geometry/strategies/spherical/distance_cross_track_point_box.hpp>
-#include <boost/geometry/strategies/spherical/compare_circular.hpp>
+#include <boost/geometry/strategies/spherical/compare.hpp>
#include <boost/geometry/strategies/spherical/envelope_segment.hpp>
#include <boost/geometry/strategies/spherical/intersection.hpp>
+#include <boost/geometry/strategies/spherical/point_in_poly_winding.hpp>
#include <boost/geometry/strategies/spherical/ssf.hpp>
#include <boost/geometry/strategies/geographic/area.hpp>
@@ -83,11 +85,13 @@
#include <boost/geometry/strategies/geographic/disjoint_segment_box.hpp>
#include <boost/geometry/strategies/geographic/distance.hpp>
#include <boost/geometry/strategies/geographic/distance_andoyer.hpp>
+#include <boost/geometry/strategies/geographic/distance_cross_track.hpp>
#include <boost/geometry/strategies/geographic/distance_thomas.hpp>
#include <boost/geometry/strategies/geographic/distance_vincenty.hpp>
#include <boost/geometry/strategies/geographic/envelope_segment.hpp>
#include <boost/geometry/strategies/geographic/intersection.hpp>
//#include <boost/geometry/strategies/geographic/intersection_elliptic.hpp>
+#include <boost/geometry/strategies/geographic/point_in_poly_winding.hpp>
#include <boost/geometry/strategies/geographic/side.hpp>
#include <boost/geometry/strategies/geographic/side_andoyer.hpp>
#include <boost/geometry/strategies/geographic/side_thomas.hpp>
diff --git a/boost/geometry/util/normalize_spheroidal_box_coordinates.hpp b/boost/geometry/util/normalize_spheroidal_box_coordinates.hpp
index eb947bb092..288dab20dd 100644
--- a/boost/geometry/util/normalize_spheroidal_box_coordinates.hpp
+++ b/boost/geometry/util/normalize_spheroidal_box_coordinates.hpp
@@ -1,8 +1,9 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2015, Oracle and/or its affiliates.
+// Copyright (c) 2015-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
@@ -26,7 +27,7 @@ namespace detail
{
-template <typename Units, typename CoordinateType>
+template <typename Units, typename CoordinateType, bool IsEquatorial = true>
class normalize_spheroidal_box_coordinates
{
private:
@@ -50,6 +51,9 @@ public:
normalize::apply(longitude1, latitude1, false);
normalize::apply(longitude2, latitude2, false);
+ latitude_convert_if_polar<Units, IsEquatorial>::apply(latitude1);
+ latitude_convert_if_polar<Units, IsEquatorial>::apply(latitude2);
+
if (math::equals(latitude1, constants::min_latitude())
&& math::equals(latitude2, constants::min_latitude()))
{
@@ -76,6 +80,9 @@ public:
longitude2 += constants::period();
}
+ latitude_convert_if_polar<Units, IsEquatorial>::apply(latitude1);
+ latitude_convert_if_polar<Units, IsEquatorial>::apply(latitude2);
+
#ifdef BOOST_GEOMETRY_NORMALIZE_LATITUDE
BOOST_GEOMETRY_ASSERT(! math::larger(latitude1, latitude2));
BOOST_GEOMETRY_ASSERT(! math::smaller(latitude1, constants::min_latitude()));
@@ -126,6 +133,18 @@ inline void normalize_spheroidal_box_coordinates(CoordinateType& longitude1,
>::apply(longitude1, latitude1, longitude2, latitude2);
}
+template <typename Units, bool IsEquatorial, typename CoordinateType>
+inline void normalize_spheroidal_box_coordinates(CoordinateType& longitude1,
+ CoordinateType& latitude1,
+ CoordinateType& longitude2,
+ CoordinateType& latitude2)
+{
+ detail::normalize_spheroidal_box_coordinates
+ <
+ Units, CoordinateType, IsEquatorial
+ >::apply(longitude1, latitude1, longitude2, latitude2);
+}
+
/*!
\brief Short utility to normalize the coordinates of a box on a spheroid
\tparam Units The units of the coordindate system in the spheroid
@@ -151,6 +170,19 @@ inline void normalize_spheroidal_box_coordinates(CoordinateType& longitude1,
>::apply(longitude1, latitude1, longitude2, latitude2, band);
}
+template <typename Units, bool IsEquatorial, typename CoordinateType>
+inline void normalize_spheroidal_box_coordinates(CoordinateType& longitude1,
+ CoordinateType& latitude1,
+ CoordinateType& longitude2,
+ CoordinateType& latitude2,
+ bool band)
+{
+ detail::normalize_spheroidal_box_coordinates
+ <
+ Units, CoordinateType, IsEquatorial
+ >::apply(longitude1, latitude1, longitude2, latitude2, band);
+}
+
} // namespace math
diff --git a/boost/geometry/util/normalize_spheroidal_coordinates.hpp b/boost/geometry/util/normalize_spheroidal_coordinates.hpp
index 19d4d33d28..eaa686ed10 100644
--- a/boost/geometry/util/normalize_spheroidal_coordinates.hpp
+++ b/boost/geometry/util/normalize_spheroidal_coordinates.hpp
@@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2015-2016, Oracle and/or its affiliates.
+// Copyright (c) 2015-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -26,8 +26,8 @@ namespace math
namespace detail
{
-
-template <typename CoordinateType, typename Units>
+// CoordinateType, radian, true
+template <typename CoordinateType, typename Units, bool IsEquatorial = true>
struct constants_on_spheroid
{
static inline CoordinateType period()
@@ -40,6 +40,13 @@ struct constants_on_spheroid
return math::pi<CoordinateType>();
}
+ static inline CoordinateType quarter_period()
+ {
+ static CoordinateType const
+ pi_half = math::pi<CoordinateType>() / CoordinateType(2);
+ return pi_half;
+ }
+
static inline CoordinateType min_longitude()
{
static CoordinateType const minus_pi = -math::pi<CoordinateType>();
@@ -65,7 +72,22 @@ struct constants_on_spheroid
};
template <typename CoordinateType>
-struct constants_on_spheroid<CoordinateType, degree>
+struct constants_on_spheroid<CoordinateType, radian, false>
+ : constants_on_spheroid<CoordinateType, radian, true>
+{
+ static inline CoordinateType min_latitude()
+ {
+ return CoordinateType(0);
+ }
+
+ static inline CoordinateType max_latitude()
+ {
+ return math::pi<CoordinateType>();
+ }
+};
+
+template <typename CoordinateType>
+struct constants_on_spheroid<CoordinateType, degree, true>
{
static inline CoordinateType period()
{
@@ -77,6 +99,11 @@ struct constants_on_spheroid<CoordinateType, degree>
return CoordinateType(180.0);
}
+ static inline CoordinateType quarter_period()
+ {
+ return CoordinateType(90.0);
+ }
+
static inline CoordinateType min_longitude()
{
return CoordinateType(-180.0);
@@ -98,8 +125,94 @@ struct constants_on_spheroid<CoordinateType, degree>
}
};
+template <typename CoordinateType>
+struct constants_on_spheroid<CoordinateType, degree, false>
+ : constants_on_spheroid<CoordinateType, degree, true>
+{
+ static inline CoordinateType min_latitude()
+ {
+ return CoordinateType(0);
+ }
+
+ static inline CoordinateType max_latitude()
+ {
+ return CoordinateType(180.0);
+ }
+};
+
+
+} // namespace detail
+#endif // DOXYGEN_NO_DETAIL
+
template <typename Units, typename CoordinateType>
+inline CoordinateType latitude_convert_ep(CoordinateType const& lat)
+{
+ typedef math::detail::constants_on_spheroid
+ <
+ CoordinateType,
+ Units
+ > constants;
+
+ return constants::quarter_period() - lat;
+}
+
+
+template <typename Units, bool IsEquatorial, typename T>
+static bool is_latitude_pole(T const& lat)
+{
+ typedef math::detail::constants_on_spheroid
+ <
+ T,
+ Units
+ > constants;
+
+ return math::equals(math::abs(IsEquatorial
+ ? lat
+ : math::latitude_convert_ep<Units>(lat)),
+ constants::quarter_period());
+
+}
+
+
+template <typename Units, typename T>
+static bool is_longitude_antimeridian(T const& lon)
+{
+ typedef math::detail::constants_on_spheroid
+ <
+ T,
+ Units
+ > constants;
+
+ return math::equals(math::abs(lon), constants::half_period());
+
+}
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail
+{
+
+
+template <typename Units, bool IsEquatorial>
+struct latitude_convert_if_polar
+{
+ template <typename T>
+ static inline void apply(T & lat) {}
+};
+
+template <typename Units>
+struct latitude_convert_if_polar<Units, false>
+{
+ template <typename T>
+ static inline void apply(T & lat)
+ {
+ lat = latitude_convert_ep<Units>(lat);
+ }
+};
+
+
+template <typename Units, typename CoordinateType, bool IsEquatorial = true>
class normalize_spheroidal_coordinates
{
typedef constants_on_spheroid<CoordinateType, Units> constants;
@@ -145,6 +258,8 @@ public:
CoordinateType& latitude,
bool normalize_poles = true)
{
+ latitude_convert_if_polar<Units, IsEquatorial>::apply(latitude);
+
#ifdef BOOST_GEOMETRY_NORMALIZE_LATITUDE
// normalize latitude
if (math::larger(latitude, constants::half_period()))
@@ -183,6 +298,8 @@ public:
}
}
+ latitude_convert_if_polar<Units, IsEquatorial>::apply(latitude);
+
#ifdef BOOST_GEOMETRY_NORMALIZE_LATITUDE
BOOST_GEOMETRY_ASSERT(! math::larger(constants::min_latitude(), latitude));
BOOST_GEOMETRY_ASSERT(! math::larger(latitude, constants::max_latitude()));
@@ -216,6 +333,15 @@ inline void normalize_spheroidal_coordinates(CoordinateType& longitude,
>::apply(longitude, latitude);
}
+template <typename Units, bool IsEquatorial, typename CoordinateType>
+inline void normalize_spheroidal_coordinates(CoordinateType& longitude,
+ CoordinateType& latitude)
+{
+ detail::normalize_spheroidal_coordinates
+ <
+ Units, CoordinateType, IsEquatorial
+ >::apply(longitude, latitude);
+}
/*!
\brief Short utility to normalize the longitude on a spheroid.
@@ -316,6 +442,7 @@ inline CoordinateType longitude_interval_distance_signed(CoordinateType const& l
: c0;
}
+
} // namespace math