diff --git a/doc/quickref.xml b/doc/quickref.xml
index 6bca7566c..0d6de52ca 100644
--- a/doc/quickref.xml
+++ b/doc/quickref.xml
@@ -614,6 +614,8 @@
strategy::simplify::douglas_peucker
+
+
Transform
@@ -625,9 +627,7 @@
strategy::transform::rotate_transformer
-
-
-
+
Within
strategy::winding
diff --git a/doc/release_notes.qbk b/doc/release_notes.qbk
index 9d859a22e..8d98af080 100644
--- a/doc/release_notes.qbk
+++ b/doc/release_notes.qbk
@@ -19,6 +19,25 @@
[section:release_notes Release Notes]
+[/=================]
+[heading Boost 1.71]
+[/=================]
+
+[*Improvements]
+
+* [@https://github.com/boostorg/geometry/pull/568 568] Add a constructor that takes matrix_type to matrix_transformer.
+* [@https://github.com/boostorg/geometry/pull/605 605] Improvement of handling of coordinate systems in various algorithms.
+* Various improvements related to robustness of set and relational operation.
+
+[*Solved issues]
+
+* [@https://github.com/boostorg/geometry/issues/596 596] boost::geometry::buffer generates (multi)polygon with spike.
+
+[*Bugfixes]
+
+* [@https://github.com/boostorg/geometry/pull/595 595] Fix inaccuracy in geographic point-segment distance computation.
+* Fix various compiler warnings.
+
[/=================]
[heading Boost 1.70]
[/=================]
diff --git a/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp b/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp
index a969b21cf..c79abcc7a 100644
--- a/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp
+++ b/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp
@@ -31,14 +31,16 @@
#include
#include
+#include
#include
#include
-#include
#include
#include
#include
+#include
+
#include
@@ -175,6 +177,16 @@ struct buffer_range
}
}
+ static inline bool similar_direction(output_point_type const& p0,
+ output_point_type const& p1,
+ output_point_type const& p2)
+ {
+ typedef model::infinite_line line_type;
+ line_type const p = detail::make::make_infinite_line(p0, p1);
+ line_type const q = detail::make::make_infinite_line(p1, p2);
+ return arithmetic::similar_direction(p, q);
+ }
+
template
static inline geometry::strategy::buffer::join_selector get_join_type(
output_point_type const& p0,
@@ -185,13 +197,8 @@ struct buffer_range
int const side = strategy.apply(p0, p1, p2);
return side == -1 ? geometry::strategy::buffer::join_convex
: side == 1 ? geometry::strategy::buffer::join_concave
- : parallel_continue
- (
- get<0>(p2) - get<0>(p1),
- get<1>(p2) - get<1>(p1),
- get<0>(p1) - get<0>(p0),
- get<1>(p1) - get<1>(p0)
- ) ? geometry::strategy::buffer::join_continue
+ : similar_direction(p0, p1, p2)
+ ? geometry::strategy::buffer::join_continue
: geometry::strategy::buffer::join_spike;
}
diff --git a/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp b/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp
index 8a4618da4..de3f3c2b4 100644
--- a/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp
+++ b/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp
@@ -179,23 +179,22 @@ struct buffered_piece_collection
typename IntersectionStrategy::cs_tag
>::type rescale_policy_type;
- typedef typename geometry::segment_ratio_type
+ typedef geometry::segment_ratio
<
- point_type,
- RobustPolicy
- >::type segment_ratio_type;
+ typename geometry::coordinate_type::type
+ > ratio_type;
typedef buffer_turn_info
<
point_type,
robust_point_type,
- segment_ratio_type
+ ratio_type
> buffer_turn_info_type;
typedef buffer_turn_operation
<
point_type,
- segment_ratio_type
+ ratio_type
> buffer_turn_operation_type;
typedef std::vector turn_vector_type;
@@ -206,7 +205,7 @@ struct buffered_piece_collection
int operation_index;
robust_point_type point;
segment_identifier seg_id;
- segment_ratio_type fraction;
+ ratio_type fraction;
};
struct piece
@@ -484,25 +483,25 @@ struct buffered_piece_collection
// intersection-point -> outgoing)
// for all (co-located) points still present in the map
- for (iterator_type it = boost::begin(m_turns);
- it != boost::end(m_turns);
- ++it)
+ for (iterator_type tit = boost::begin(m_turns);
+ tit != boost::end(m_turns);
+ ++tit)
{
typename occupation_map_type::iterator mit =
- occupation_map.find(it->get_robust_point());
+ occupation_map.find(tit->get_robust_point());
if (mit != occupation_map.end())
{
buffer_occupation_info& info = mit->second;
for (int i = 0; i < 2; i++)
{
- add_incoming_and_outgoing_angles(it->get_robust_point(), *it,
+ add_incoming_and_outgoing_angles(tit->get_robust_point(), *tit,
m_pieces,
- i, it->operations[i].seg_id,
+ i, tit->operations[i].seg_id,
info);
}
- it->count_on_multi++;
+ tit->count_on_multi++;
}
}
@@ -526,10 +525,10 @@ struct buffered_piece_collection
#endif
// Get left turns from all clusters
- for (typename occupation_map_type::iterator it = occupation_map.begin();
- it != occupation_map.end(); ++it)
+ for (typename occupation_map_type::iterator mit = occupation_map.begin();
+ mit != occupation_map.end(); ++mit)
{
- it->second.get_left_turns(it->first, m_turns, m_side_strategy);
+ mit->second.get_left_turns(mit->first, m_turns, m_side_strategy);
}
}
diff --git a/include/boost/geometry/algorithms/detail/buffer/line_line_intersection.hpp b/include/boost/geometry/algorithms/detail/buffer/line_line_intersection.hpp
index 11f1c689a..ec50d91a8 100644
--- a/include/boost/geometry/algorithms/detail/buffer/line_line_intersection.hpp
+++ b/include/boost/geometry/algorithms/detail/buffer/line_line_intersection.hpp
@@ -10,9 +10,9 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_LINE_LINE_INTERSECTION_HPP
-#include
+#include
+#include
#include
-#include
namespace boost { namespace geometry
{
@@ -22,55 +22,33 @@ namespace boost { namespace geometry
namespace detail { namespace buffer
{
-
-// TODO: once change this to proper strategy
-// It is different from current segment intersection because these are not segments but lines
-// If we have the Line concept, we can create a strategy
-// Assumes a convex corner
+// TODO: it might once be changed this to proper strategy
struct line_line_intersection
{
-
template
- static inline strategy::buffer::join_selector apply(Point const& pi, Point const& pj,
- Point const& qi, Point const& qj, Point& ip)
+ static inline strategy::buffer::join_selector
+ apply(Point const& pi, Point const& pj,
+ Point const& qi, Point const& qj,
+ Point& ip)
{
typedef typename coordinate_type::type ct;
+ typedef model::infinite_line line_type;
- // Construct lines in general form (ax + by + c = 0),
- // (will be replaced by a general_form structure in a next PR)
- ct const pa = get<1>(pi) - get<1>(pj);
- ct const pb = get<0>(pj) - get<0>(pi);
- ct const pc = -pa * get<0>(pi) - pb * get<1>(pi);
+ line_type const p = detail::make::make_infinite_line(pi, pj);
+ line_type const q = detail::make::make_infinite_line(qi, qj);
- ct const qa = get<1>(qi) - get<1>(qj);
- ct const qb = get<0>(qj) - get<0>(qi);
- ct const qc = -qa * get<0>(qi) - qb * get<1>(qi);
-
- ct const denominator = pb * qa - pa * qb;
-
- // Even if the corner was checked before (so it is convex now), that
- // was done on the original geometry. This function runs on the buffered
- // geometries, where sides are generated and might be slightly off. In
- // Floating Point, that slightly might just exceed the limit and we have
- // to check it again.
-
- // For round joins, it will not be used at all.
- // For miter joins, there is a miter limit
- // If segments are parallel/collinear we must be distinguish two cases:
- // they continue each other, or they form a spike
- ct const zero = ct();
- if (math::equals(denominator, zero))
+ if (arithmetic::intersection_point(p, q, ip))
{
- return parallel_continue(qb, -qa, pb, -pa)
- ? strategy::buffer::join_continue
- : strategy::buffer::join_spike
- ;
+ return strategy::buffer::join_convex;
}
- set<0>(ip, (pc * qb - pb * qc) / denominator);
- set<1>(ip, (pa * qc - pc * qa) / denominator);
-
- return strategy::buffer::join_convex;
+ // The lines do not intersect.
+ // Distinguish between continuing lines (having a similar direction)
+ // and spikes (having the opposite direction).
+ return arithmetic::similar_direction(p, q)
+ ? strategy::buffer::join_continue
+ : strategy::buffer::join_spike
+ ;
}
};
diff --git a/include/boost/geometry/algorithms/detail/buffer/parallel_continue.hpp b/include/boost/geometry/algorithms/detail/buffer/parallel_continue.hpp
deleted file mode 100644
index 119d64de7..000000000
--- a/include/boost/geometry/algorithms/detail/buffer/parallel_continue.hpp
+++ /dev/null
@@ -1,33 +0,0 @@
-// Boost.Geometry (aka GGL, Generic Geometry Library)
-
-// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
-
-// Use, modification and distribution is subject to the Boost Software License,
-// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
-// http://www.boost.org/LICENSE_1_0.txt)
-
-#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_PARALLEL_CONTINUE_HPP
-#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_PARALLEL_CONTINUE_HPP
-
-
-namespace boost { namespace geometry
-{
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace buffer
-{
-
-template
-inline bool parallel_continue(T dx1, T dy1, T dx2, T dy2)
-{
- T const dot = dx1 * dx2 + dy1 * dy2;
- return dot > 0;
-}
-
-}} // namespace detail::buffer
-#endif // DOXYGEN_NO_DETAIL
-
-
-}} // namespace boost::geometry
-
-#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_PARALLEL_CONTINUE_HPP
diff --git a/include/boost/geometry/algorithms/detail/calculate_point_order.hpp b/include/boost/geometry/algorithms/detail/calculate_point_order.hpp
new file mode 100644
index 000000000..a3024076e
--- /dev/null
+++ b/include/boost/geometry/algorithms/detail/calculate_point_order.hpp
@@ -0,0 +1,370 @@
+// Boost.Geometry
+
+// Copyright (c) 2019, Oracle and/or its affiliates.
+
+// 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
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_CALCULATE_POINT_ORDER_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CALCULATE_POINT_ORDER_HPP
+
+
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+namespace boost { namespace geometry
+{
+
+namespace detail
+{
+
+template
+struct clean_point
+{
+ explicit clean_point(Iter const& iter)
+ : m_iter(iter), m_azi(0), m_razi(0), m_azi_diff(0)
+ , m_is_azi_valid(false), m_is_azi_diff_valid(false)
+ {}
+
+ typename boost::iterators::iterator_reference::type ref() const
+ {
+ return *m_iter;
+ }
+
+ CalcT const& azimuth() const
+ {
+ return m_azi;
+ }
+
+ CalcT const& reverse_azimuth() const
+ {
+ return m_razi;
+ }
+
+ CalcT const& azimuth_difference() const
+ {
+ return m_azi_diff;
+ }
+
+ void set_azimuths(CalcT const& azi, CalcT const& razi)
+ {
+ m_azi = azi;
+ m_razi = razi;
+ m_is_azi_valid = true;
+ }
+
+ void set_azimuth_invalid()
+ {
+ m_is_azi_valid = false;
+ }
+
+ bool is_azimuth_valid() const
+ {
+ return m_is_azi_valid;
+ }
+
+ void set_azimuth_difference(CalcT const& diff)
+ {
+ m_azi_diff = diff;
+ m_is_azi_diff_valid = true;
+ }
+
+ void set_azimuth_difference_invalid()
+ {
+ m_is_azi_diff_valid = false;
+ }
+
+ bool is_azimuth_difference_valid() const
+ {
+ return m_is_azi_diff_valid;
+ }
+
+private:
+ Iter m_iter;
+ CalcT m_azi;
+ CalcT m_razi;
+ CalcT m_azi_diff;
+ // NOTE: these flags could be removed and replaced with some magic number
+ // assigned to the above variables, e.g. CalcT(1000).
+ bool m_is_azi_valid;
+ bool m_is_azi_diff_valid;
+};
+
+struct calculate_point_order_by_azimuth
+{
+ template
+ static geometry::order_selector apply(Ring const& ring, Strategy const& strategy)
+ {
+ typedef typename boost::range_iterator::type iter_t;
+ typedef typename Strategy::template result_type::type calc_t;
+ typedef clean_point clean_point_t;
+ typedef std::vector cleaned_container_t;
+ typedef typename cleaned_container_t::iterator cleaned_iter_t;
+
+ calc_t const zero = 0;
+ calc_t const pi = math::pi();
+
+ std::size_t const count = boost::size(ring);
+ if (count < 3)
+ {
+ return geometry::order_undetermined;
+ }
+
+ // non-duplicated, non-spike points
+ cleaned_container_t cleaned;
+ cleaned.reserve(count);
+
+ for (iter_t it = boost::begin(ring); it != boost::end(ring); ++it)
+ {
+ // Add point
+ cleaned.push_back(clean_point_t(it));
+
+ while (cleaned.size() >= 3)
+ {
+ cleaned_iter_t it0 = cleaned.end() - 3;
+ cleaned_iter_t it1 = cleaned.end() - 2;
+ cleaned_iter_t it2 = cleaned.end() - 1;
+
+ calc_t diff;
+ if (get_or_calculate_azimuths_difference(*it0, *it1, *it2, diff, strategy)
+ && ! math::equals(math::abs(diff), pi))
+ {
+ // neither duplicate nor a spike - difference already stored
+ break;
+ }
+ else
+ {
+ // spike detected
+ // TODO: angles have to be invalidated only if spike is detected
+ // for duplicates it'd be ok to leave them
+ it0->set_azimuth_invalid();
+ it0->set_azimuth_difference_invalid();
+ it2->set_azimuth_difference_invalid();
+ cleaned.erase(it1);
+ }
+ }
+ }
+
+ // filter-out duplicates and spikes at the front and back of cleaned
+ cleaned_iter_t cleaned_b = cleaned.begin();
+ cleaned_iter_t cleaned_e = cleaned.end();
+ std::size_t cleaned_count = cleaned.size();
+ bool found = false;
+ do
+ {
+ found = false;
+ while(cleaned_count >= 3)
+ {
+ cleaned_iter_t it0 = cleaned_e - 2;
+ cleaned_iter_t it1 = cleaned_e - 1;
+ cleaned_iter_t it2 = cleaned_b;
+ cleaned_iter_t it3 = cleaned_b + 1;
+
+ calc_t diff = 0;
+ if (! get_or_calculate_azimuths_difference(*it0, *it1, *it2, diff, strategy)
+ || math::equals(math::abs(diff), pi))
+ {
+ // spike at the back
+ // TODO: angles have to be invalidated only if spike is detected
+ // for duplicates it'd be ok to leave them
+ it0->set_azimuth_invalid();
+ it0->set_azimuth_difference_invalid();
+ it2->set_azimuth_difference_invalid();
+ --cleaned_e;
+ --cleaned_count;
+ found = true;
+ }
+ else if (! get_or_calculate_azimuths_difference(*it1, *it2, *it3, diff, strategy)
+ || math::equals(math::abs(diff), pi))
+ {
+ // spike at the front
+ // TODO: angles have to be invalidated only if spike is detected
+ // for duplicates it'd be ok to leave them
+ it1->set_azimuth_invalid();
+ it1->set_azimuth_difference_invalid();
+ it3->set_azimuth_difference_invalid();
+ ++cleaned_b;
+ --cleaned_count;
+ found = true;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ while (found);
+
+ if (cleaned_count < 3)
+ {
+ return geometry::order_undetermined;
+ }
+
+ // calculate the sum of external angles
+ calc_t angles_sum = zero;
+ for (cleaned_iter_t it = cleaned_b; it != cleaned_e; ++it)
+ {
+ cleaned_iter_t it0 = (it == cleaned_b ? cleaned_e - 1 : it - 1);
+ cleaned_iter_t it2 = (it == cleaned_e - 1 ? cleaned_b : it + 1);
+
+ calc_t diff = 0;
+ get_or_calculate_azimuths_difference(*it0, *it, *it2, diff, strategy);
+
+ angles_sum += diff;
+ }
+
+#ifdef BOOST_GEOMETRY_DEBUG_POINT_ORDER
+ std::cout << angles_sum << " for " << geometry::wkt(ring) << std::endl;
+#endif
+
+ return angles_sum == zero ? geometry::order_undetermined
+ : angles_sum > zero ? geometry::clockwise
+ : geometry::counterclockwise;
+ }
+
+private:
+ template
+ static bool get_or_calculate_azimuths_difference(clean_point & p0,
+ clean_point & p1,
+ clean_point const& p2,
+ T & diff,
+ Strategy const& strategy)
+ {
+ if (p1.is_azimuth_difference_valid())
+ {
+ diff = p1.azimuth_difference();
+ return true;
+ }
+
+ T azi1, razi1, azi2, razi2;
+ if (get_or_calculate_azimuths(p0, p1, azi1, razi1, strategy)
+ && get_or_calculate_azimuths(p1, p2, azi2, razi2, strategy))
+ {
+ diff = strategy.apply(p0.ref(), p1.ref(), p2.ref(), razi1, azi2);
+ p1.set_azimuth_difference(diff);
+ return true;
+ }
+ return false;
+ }
+
+ template
+ static bool get_or_calculate_azimuths(clean_point & p0,
+ clean_point const& p1,
+ T & azi, T & razi,
+ Strategy const& strategy)
+ {
+ if (p0.is_azimuth_valid())
+ {
+ azi = p0.azimuth();
+ razi = p0.reverse_azimuth();
+ return true;
+ }
+
+ if (strategy.apply(p0.ref(), p1.ref(), azi, razi))
+ {
+ p0.set_azimuths(azi, razi);
+ return true;
+ }
+
+ return false;
+ }
+};
+
+struct calculate_point_order_by_area
+{
+ template
+ static geometry::order_selector apply(Ring const& ring, Strategy const& strategy)
+ {
+ typedef detail::area::ring_area
+ <
+ geometry::order_as_direction::value>::value,
+ geometry::closure::value
+ > ring_area_type;
+
+ typedef typename area_result
+ <
+ Ring, Strategy
+ >::type result_type;
+
+ result_type const result = ring_area_type::apply(ring, strategy);
+
+ result_type const zero = 0;
+ return result == zero ? geometry::order_undetermined
+ : result > zero ? geometry::clockwise
+ : geometry::counterclockwise;
+ }
+};
+
+} // namespace detail
+
+namespace dispatch
+{
+
+template
+<
+ typename Strategy,
+ typename VersionTag = typename Strategy::version_tag
+>
+struct calculate_point_order
+{
+ BOOST_MPL_ASSERT_MSG
+ (
+ false, NOT_IMPLEMENTED_FOR_THIS_TAG, (types)
+ );
+};
+
+template
+struct calculate_point_order
+ : geometry::detail::calculate_point_order_by_area
+{};
+
+template
+struct calculate_point_order
+ : geometry::detail::calculate_point_order_by_azimuth
+{};
+
+
+} // namespace dispatch
+
+namespace detail
+{
+
+template
+inline geometry::order_selector calculate_point_order(Ring const& ring, Strategy const& strategy)
+{
+ concepts::check();
+
+ return dispatch::calculate_point_order::apply(ring, strategy);
+}
+
+template
+inline geometry::order_selector calculate_point_order(Ring const& ring)
+{
+ typedef typename strategy::point_order::services::default_strategy
+ <
+ typename geometry::cs_tag::type
+ >::type strategy_type;
+
+ concepts::check();
+
+ return dispatch::calculate_point_order::apply(ring, strategy_type());
+}
+
+
+} // namespace detail
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CALCULATE_POINT_ORDER_HPP
diff --git a/include/boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp b/include/boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp
index df6789013..e5e8c6c25 100644
--- a/include/boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp
+++ b/include/boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp
@@ -71,8 +71,11 @@ protected:
// check if other segments are closer
for (++prev, ++it; it != last; ++prev, ++it)
{
- Distance dist = strategy.apply(point, *prev, *it);
- if (geometry::math::equals(dist, zero))
+ Distance const dist = strategy.apply(point, *prev, *it);
+
+ // Stop only if we find exactly zero distance
+ // otherwise it may stop at some very small value and miss the min
+ if (dist == zero)
{
dist_min = zero;
it_min1 = prev;
diff --git a/include/boost/geometry/algorithms/detail/direction_code.hpp b/include/boost/geometry/algorithms/detail/direction_code.hpp
index ab3b1e0a2..38c65afa2 100644
--- a/include/boost/geometry/algorithms/detail/direction_code.hpp
+++ b/include/boost/geometry/algorithms/detail/direction_code.hpp
@@ -12,11 +12,13 @@
// 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_DIRECITON_CODE_HPP
-#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DIRECITON_CODE_HPP
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DIRECTION_CODE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DIRECTION_CODE_HPP
#include
+#include
+#include
#include
#include
#include
@@ -32,20 +34,6 @@ namespace boost { namespace geometry
namespace detail
{
-
-// TODO: remove
-template
-inline int sign_of_difference(Point1 const& point1, Point2 const& point2)
-{
- return
- math::equals(geometry::get(point1), geometry::get(point2))
- ?
- 0
- :
- (geometry::get(point1) > geometry::get(point2) ? 1 : -1);
-}
-
-
template
struct direction_code_impl
{
@@ -57,42 +45,30 @@ struct direction_code_impl
{
template
static inline int apply(Point1 const& segment_a, Point1 const& segment_b,
- Point2 const& p)
+ Point2 const& point)
{
typedef typename geometry::select_coordinate_type
<
Point1, Point2
>::type calc_t;
- if ( (math::equals(geometry::get<0>(segment_b), geometry::get<0>(segment_a))
- && math::equals(geometry::get<1>(segment_b), geometry::get<1>(segment_a)))
- || (math::equals(geometry::get<0>(segment_b), geometry::get<0>(p))
- && math::equals(geometry::get<1>(segment_b), geometry::get<1>(p))) )
+ typedef model::infinite_line line_type;
+
+ // point b is often equal to the specified point, check that first
+ line_type const q = detail::make::make_infinite_line(segment_b, point);
+ if (arithmetic::is_degenerate(q))
{
return 0;
}
- calc_t x1 = geometry::get<0>(segment_b) - geometry::get<0>(segment_a);
- calc_t y1 = geometry::get<1>(segment_b) - geometry::get<1>(segment_a);
- calc_t x2 = geometry::get<0>(segment_b) - geometry::get<0>(p);
- calc_t y2 = geometry::get<1>(segment_b) - geometry::get<1>(p);
-
- calc_t ax = (std::min)(math::abs(x1), math::abs(x2));
- calc_t ay = (std::min)(math::abs(y1), math::abs(y2));
-
- int s1 = 0, s2 = 0;
- if (ax >= ay)
+ line_type const p = detail::make::make_infinite_line(segment_a, segment_b);
+ if (arithmetic::is_degenerate(p))
{
- s1 = x1 > 0 ? 1 : -1;
- s2 = x2 > 0 ? 1 : -1;
- }
- else
- {
- s1 = y1 > 0 ? 1 : -1;
- s2 = y2 > 0 ? 1 : -1;
+ return 0;
}
- return s1 == s2 ? -1 : 1;
+ // p extends a-b if direction is similar
+ return arithmetic::similar_direction(p, q) ? 1 : -1;
}
};
@@ -277,4 +253,4 @@ inline int direction_code(Point1 const& segment_a, Point1 const& segment_b,
}} // namespace boost::geometry
-#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DIRECITON_CODE_HPP
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DIRECTION_CODE_HPP
diff --git a/include/boost/geometry/algorithms/detail/disjoint/linear_linear.hpp b/include/boost/geometry/algorithms/detail/disjoint/linear_linear.hpp
index 7b830f7d1..cefa5e9f8 100644
--- a/include/boost/geometry/algorithms/detail/disjoint/linear_linear.hpp
+++ b/include/boost/geometry/algorithms/detail/disjoint/linear_linear.hpp
@@ -34,10 +34,10 @@
#include
#include
#include
+#include
#include
#include
-#include
#include
@@ -59,28 +59,17 @@ struct disjoint_segment
{
typedef typename point_type::type point_type;
- // We don't need to rescale to detect disjointness
- typedef no_rescale_policy rescale_policy_type;
- rescale_policy_type robust_policy;
-
- typedef segment_intersection_points
- <
- point_type,
- typename segment_ratio_type
- <
- point_type,
- rescale_policy_type
- >::type
- > intersection_return_type;
+ typedef segment_intersection_points intersection_return_type;
typedef policies::relate::segments_intersection_points
<
intersection_return_type
> intersection_policy;
- intersection_return_type is = strategy.apply(segment1, segment2,
- intersection_policy(),
- robust_policy);
+ detail::segment_as_subrange sub_range1(segment1);
+ detail::segment_as_subrange sub_range2(segment2);
+ intersection_return_type is = strategy.apply(sub_range1, sub_range2,
+ intersection_policy());
return is.count == 0;
}
@@ -105,18 +94,17 @@ struct disjoint_linear
Strategy const& strategy)
{
typedef typename geometry::point_type::type point_type;
- typedef detail::no_rescale_policy rescale_policy_type;
- typedef typename geometry::segment_ratio_type
+ typedef geometry::segment_ratio
<
- point_type, rescale_policy_type
- >::type segment_ratio_type;
+ typename coordinate_type::type
+ > ratio_type;
typedef overlay::turn_info
<
point_type,
- segment_ratio_type,
+ ratio_type,
typename detail::get_turns::turn_operation_type
<
- Geometry1, Geometry2, segment_ratio_type
+ Geometry1, Geometry2, ratio_type
>::type
> turn_info_type;
@@ -139,7 +127,7 @@ struct disjoint_linear
Geometry1, Geometry2, assign_disjoint_policy
>
>::apply(0, geometry1, 1, geometry2,
- strategy, rescale_policy_type(), turns, interrupt_policy);
+ strategy, detail::no_rescale_policy(), turns, interrupt_policy);
return !interrupt_policy.has_intersections;
}
diff --git a/include/boost/geometry/algorithms/detail/equals/implementation.hpp b/include/boost/geometry/algorithms/detail/equals/implementation.hpp
index f39ae0b8b..4088478d5 100644
--- a/include/boost/geometry/algorithms/detail/equals/implementation.hpp
+++ b/include/boost/geometry/algorithms/detail/equals/implementation.hpp
@@ -5,8 +5,8 @@
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// Copyright (c) 2014-2015 Adam Wulkiewicz, Lodz, Poland.
-// This file was modified by Oracle on 2014, 2015, 2016, 2017, 2018.
-// Modifications copyright (c) 2014-2018 Oracle and/or its affiliates.
+// This file was modified by Oracle on 2014, 2015, 2016, 2017, 2018, 2019.
+// Modifications copyright (c) 2014-2019 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
@@ -275,6 +275,15 @@ private:
}
};
+struct equals_always_false
+{
+ template
+ static inline bool apply(Geometry1 const& , Geometry2 const& , Strategy const& )
+ {
+ return false;
+ }
+};
+
}} // namespace detail::equals
#endif // DOXYGEN_NO_DETAIL
@@ -285,81 +294,92 @@ namespace dispatch
{
template
-struct equals
+struct equals
: detail::equals::point_point<0, DimensionCount>
{};
template
-struct equals
+struct equals
: detail::equals::equals_by_relate
{};
template
-struct equals
+struct equals
: detail::equals::equals_by_relate
{};
template
-struct equals
+struct equals
: detail::equals::box_box<0, DimensionCount>
{};
template
-struct equals
+struct equals
: detail::equals::equals_by_collection_or_relate
{};
template
-struct equals
+struct equals
: detail::equals::equals_by_collection_or_relate
{};
template
-struct equals
+struct equals
: detail::equals::equals_by_collection_or_relate
{};
template
-struct equals
+struct equals
: detail::equals::equals_by_collection
{};
template
-struct equals
+struct equals
: detail::equals::equals_by_collection
{};
template
-struct equals
+struct equals
: detail::equals::segment_segment
{};
template
-struct equals
+struct equals
: detail::equals::equals_by_relate
{};
template
-struct equals
+struct equals
: detail::equals::equals_by_relate
{};
template
-struct equals
+struct equals
: detail::equals::equals_by_relate
{};
+template
+struct equals
+ : detail::equals::equals_by_relate
+{};
+
+template
+struct equals
+ : detail::equals::equals_by_relate
+{};
+
template
struct equals
<
MultiPolygon1, MultiPolygon2,
multi_polygon_tag, multi_polygon_tag,
+ areal_tag, areal_tag,
2,
Reverse
>
@@ -372,6 +392,7 @@ struct equals
<
Polygon, MultiPolygon,
polygon_tag, multi_polygon_tag,
+ areal_tag, areal_tag,
2,
Reverse
>
@@ -383,6 +404,7 @@ struct equals
<
MultiPolygon, Ring,
multi_polygon_tag, ring_tag,
+ areal_tag, areal_tag,
2,
Reverse
>
@@ -390,6 +412,42 @@ struct equals
{};
+// NOTE: degenerated linear geometries, e.g. segment or linestring containing
+// 2 equal points, are considered to be invalid. Though theoretically
+// degenerated segments and linestrings could be treated as points and
+// multi-linestrings as multi-points.
+// This reasoning could also be applied to boxes.
+
+template
+struct equals
+ : detail::equals::equals_always_false
+{};
+
+template
+struct equals
+ : detail::equals::equals_always_false
+{};
+
+template
+struct equals
+ : detail::equals::equals_always_false
+{};
+
+template
+struct equals
+ : detail::equals::equals_always_false
+{};
+
+template
+struct equals
+ : detail::equals::equals_always_false
+{};
+
+template
+struct equals
+ : detail::equals::equals_always_false
+{};
+
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
diff --git a/include/boost/geometry/algorithms/detail/equals/interface.hpp b/include/boost/geometry/algorithms/detail/equals/interface.hpp
index eacf95e9f..1e4918836 100644
--- a/include/boost/geometry/algorithms/detail/equals/interface.hpp
+++ b/include/boost/geometry/algorithms/detail/equals/interface.hpp
@@ -5,8 +5,8 @@
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// Copyright (c) 2014-2015 Adam Wulkiewicz, Lodz, Poland.
-// This file was modified by Oracle on 2014, 2015, 2016, 2017.
-// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates.
+// This file was modified by Oracle on 2014, 2015, 2016, 2017, 2019.
+// Modifications copyright (c) 2014-2019 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
@@ -52,6 +52,8 @@ template
typename Geometry2,
typename Tag1 = typename tag::type,
typename Tag2 = typename tag::type,
+ typename CastedTag1 = typename tag_cast::type,
+ typename CastedTag2 = typename tag_cast::type,
std::size_t DimensionCount = dimension::type::value,
bool Reverse = reverse_dispatch::type::value
>
@@ -64,10 +66,11 @@ template
<
typename Geometry1, typename Geometry2,
typename Tag1, typename Tag2,
+ typename CastedTag1, typename CastedTag2,
std::size_t DimensionCount
>
-struct equals
- : equals
+struct equals
+ : equals
{
template
static inline bool apply(Geometry1 const& g1, Geometry2 const& g2, Strategy const& strategy)
@@ -76,6 +79,7 @@ struct equals
<
Geometry2, Geometry1,
Tag2, Tag1,
+ CastedTag2, CastedTag1,
DimensionCount,
false
>::apply(g2, g1, strategy);
diff --git a/include/boost/geometry/algorithms/detail/get_left_turns.hpp b/include/boost/geometry/algorithms/detail/get_left_turns.hpp
index 1fec47a01..2e0275a9b 100644
--- a/include/boost/geometry/algorithms/detail/get_left_turns.hpp
+++ b/include/boost/geometry/algorithms/detail/get_left_turns.hpp
@@ -247,17 +247,11 @@ inline void block_turns(AngleCollection& sorted, std::size_t cluster_size)
for (typename boost::range_iterator::type it = sorted.begin();
it != sorted.end(); ++it)
{
- signed_size_type cluster_index = static_cast(it->cluster_index);
- signed_size_type previous_index = cluster_index - 1;
- if (previous_index < 0)
- {
- previous_index = cluster_size - 1;
- }
- signed_size_type next_index = cluster_index + 1;
- if (next_index >= static_cast(cluster_size))
- {
- next_index = 0;
- }
+ std::size_t const cluster_index = it->cluster_index;
+ std::size_t const previous_index
+ = cluster_index == 0 ? cluster_size - 1 : cluster_index - 1;
+ std::size_t const next_index
+ = cluster_index + 1 >= cluster_size ? 0 : cluster_index + 1;
if (directions[cluster_index].first
&& directions[cluster_index].second)
diff --git a/include/boost/geometry/algorithms/detail/intersects/implementation.hpp b/include/boost/geometry/algorithms/detail/intersects/implementation.hpp
index f9b5402d0..cbb442ce4 100644
--- a/include/boost/geometry/algorithms/detail/intersects/implementation.hpp
+++ b/include/boost/geometry/algorithms/detail/intersects/implementation.hpp
@@ -29,7 +29,6 @@
#include
#include
#include
-#include
#include
@@ -53,13 +52,8 @@ struct self_intersects
<
Geometry, Geometry
>::type strategy_type;
- typedef detail::no_rescale_policy rescale_policy_type;
- typedef detail::overlay::turn_info
- <
- point_type,
- typename segment_ratio_type::type
- > turn_info;
+ typedef detail::overlay::turn_info turn_info;
std::deque turns;
@@ -69,14 +63,13 @@ struct self_intersects
> turn_policy;
strategy_type strategy;
- 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, true);
+ >::apply(geometry, strategy, detail::no_rescale_policy(), turns, policy, 0, true);
return policy.has_intersections;
}
};
diff --git a/include/boost/geometry/algorithms/detail/is_simple/linear.hpp b/include/boost/geometry/algorithms/detail/is_simple/linear.hpp
index 57bc295e5..a9a3aaf31 100644
--- a/include/boost/geometry/algorithms/detail/is_simple/linear.hpp
+++ b/include/boost/geometry/algorithms/detail/is_simple/linear.hpp
@@ -206,14 +206,7 @@ inline bool has_self_intersections(Linear const& linear, Strategy const& strateg
typedef typename point_type::type point_type;
// compute self turns
- typedef detail::overlay::turn_info
- <
- point_type,
- geometry::segment_ratio
- <
- typename geometry::coordinate_type::type
- >
- > turn_info;
+ typedef detail::overlay::turn_info turn_info;
std::deque turns;
diff --git a/include/boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp b/include/boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp
index 1978e8309..e99e41133 100644
--- a/include/boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp
+++ b/include/boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp
@@ -63,7 +63,7 @@ public:
typedef detail::overlay::turn_info
<
point_type,
- typename geometry::segment_ratio_type
+ typename segment_ratio_type
<
point_type,
rescale_policy_type
@@ -87,11 +87,13 @@ public:
is_acceptable_turn
> interrupt_policy;
+ // Calculate self-turns, skipping adjacent segments
detail::self_get_turn_points::self_turns(geometry,
strategy,
robust_policy,
turns,
- interrupt_policy);
+ interrupt_policy,
+ 0, true);
if (interrupt_policy.has_intersections)
{
diff --git a/include/boost/geometry/algorithms/detail/make/make.hpp b/include/boost/geometry/algorithms/detail/make/make.hpp
new file mode 100644
index 000000000..87631992a
--- /dev/null
+++ b/include/boost/geometry/algorithms/detail/make/make.hpp
@@ -0,0 +1,60 @@
+// Boost.Geometry
+
+// Copyright (c) 2019 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_MAKE_MAKE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_MAKE_MAKE_HPP
+
+#include
+#include
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace make
+{
+
+template
+inline
+model::infinite_line make_infinite_line(Coordinate const& x1,
+ Coordinate const& y1, Coordinate const& x2, Coordinate const& y2)
+{
+ model::infinite_line result;
+ result.a = y1 - y2;
+ result.b = x2 - x1;
+ result.c = -result.a * x1 - result.b * y1;
+ return result;
+}
+
+template
+inline
+model::infinite_line make_infinite_line(Point const& a, Point const& b)
+{
+ return make_infinite_line(geometry::get<0>(a), geometry::get<1>(a),
+ geometry::get<0>(b), geometry::get<1>(b));
+}
+
+template
+inline
+model::infinite_line make_infinite_line(Segment const& segment)
+{
+ return make_infinite_line(geometry::get<0, 0>(segment),
+ geometry::get<0, 1>(segment),
+ geometry::get<1, 0>(segment),
+ geometry::get<1, 1>(segment));
+}
+
+
+
+}} // namespace detail::make
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_MAKE_MAKE_HPP
diff --git a/include/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp b/include/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp
index d82c34cc7..fbb126bbc 100644
--- a/include/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp
+++ b/include/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp
@@ -426,12 +426,6 @@ inline void enrich_intersection_points(Turns& turns,
std::vector
> mapped_vector_type;
- // As long as turn indexes are not used yet, turns might be erased from
- // the vector
- // For now start turns are disabled.
- // TODO: remove code or fix inconsistencies within validity and relations
- // detail::overlay::erase_colocated_start_turns(turns, geometry1, geometry2);
-
// From here on, turn indexes are used (in clusters, next_index, etc)
// and may only be flagged as discarded
diff --git a/include/boost/geometry/algorithms/detail/overlay/get_distance_measure.hpp b/include/boost/geometry/algorithms/detail/overlay/get_distance_measure.hpp
index a306cb442..a4de22b27 100644
--- a/include/boost/geometry/algorithms/detail/overlay/get_distance_measure.hpp
+++ b/include/boost/geometry/algorithms/detail/overlay/get_distance_measure.hpp
@@ -12,6 +12,8 @@
#include
#include
#include
+#include
+#include
#include
#include
@@ -100,26 +102,14 @@ struct get_distance_measure
static result_type apply(SegmentPoint const& p1, SegmentPoint const& p2,
Point const& p)
{
- typedef CalculationType ct;
+ // Get the distance measure / side value
+ // It is not a real distance and purpose is
+ // to detect small differences in collinearity
- // Construct a line in general form (ax + by + c = 0),
- // (will be replaced by a general_form structure in next PR)
- ct const x1 = geometry::get<0>(p1);
- ct const y1 = geometry::get<1>(p1);
- ct const x2 = geometry::get<0>(p2);
- ct const y2 = geometry::get<1>(p2);
- ct const a = y1 - y2;
- ct const b = x2 - x1;
- ct const c = -a * x1 - b * y1;
-
- // Returns a distance measure
- // https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line#Line_defined_by_an_equation
- // dividing by sqrt(a*a+b*b) is not necessary for this distance measure,
- // it is not a real distance and purpose is to detect small differences
- // in collinearity
+ typedef model::infinite_line line_type;
+ line_type const line = detail::make::make_infinite_line(p1, p2);
result_type result;
- result.measure = a * geometry::get<0>(p) + b * geometry::get<1>(p) + c;
-
+ result.measure = arithmetic::side_value(line, p);
return result;
}
};
diff --git a/include/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp b/include/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp
index 5a3360375..4b0e9ed79 100644
--- a/include/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp
+++ b/include/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp
@@ -22,11 +22,10 @@
#include
#include
+#include
#include
-#include
-
namespace boost { namespace geometry
{
@@ -56,45 +55,25 @@ struct get_turn_without_info
UniqueSubRange2 const& range_q,
TurnInfo const& ,
Strategy const& strategy,
- RobustPolicy const& robust_policy,
+ RobustPolicy const& ,
OutputIterator out)
{
+ // Make sure this is only called with no rescaling
+ BOOST_STATIC_ASSERT((boost::is_same
+ <
+ no_rescale_policy_tag,
+ typename rescale_policy_type::type
+ >::value));
+
typedef typename TurnInfo::point_type turn_point_type;
typedef policies::relate::segments_intersection_points
<
- segment_intersection_points
- <
- turn_point_type,
- typename geometry::segment_ratio_type
- <
- turn_point_type, RobustPolicy
- >::type
- >
+ segment_intersection_points
> policy_type;
- typedef model::referring_segment segment_type1;
- typedef model::referring_segment segment_type2;
- Point1 const& pi = range_p.at(0);
- Point1 const& pj = range_p.at(1);
- Point2 const& qi = range_q.at(0);
- Point2 const& qj = range_q.at(1);
- segment_type1 p1(pi, pj);
- segment_type2 q1(qi, qj);
-
- typedef typename geometry::robust_point_type
- <
- Point1, RobustPolicy
- >::type robust_point_type;
-
- robust_point_type pi_rob, pj_rob, qi_rob, qj_rob;
- geometry::recalculate(pi_rob, pi, robust_policy);
- geometry::recalculate(pj_rob, pj, robust_policy);
- geometry::recalculate(qi_rob, qi, robust_policy);
- geometry::recalculate(qj_rob, qj, robust_policy);
- typename policy_type::return_type result
- = strategy.apply(p1, q1, policy_type(), robust_policy,
- pi_rob, pj_rob, qi_rob, qj_rob);
+ typename policy_type::return_type const result
+ = strategy.apply(range_p, range_q, policy_type());
for (std::size_t i = 0; i < result.count; i++)
{
diff --git a/include/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp b/include/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp
index f726fc1a0..7404dabb4 100644
--- a/include/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp
+++ b/include/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp
@@ -153,12 +153,14 @@ struct base_turn_handler
typename UmbrellaStrategy,
typename TurnInfo
>
- static inline void both_collinear(UniqueSubRange1 const& range_p,
+ static inline void both_collinear(
+ UniqueSubRange1 const& range_p,
UniqueSubRange2 const& range_q,
- UmbrellaStrategy const& umbrella_strategy,
+ UmbrellaStrategy const&,
std::size_t index_p, std::size_t index_q,
TurnInfo& ti)
{
+ boost::ignore_unused(range_p, range_q);
BOOST_GEOMETRY_ASSERT(IndexP + IndexQ == 1);
BOOST_GEOMETRY_ASSERT(index_p > 0 && index_p <= 2);
BOOST_GEOMETRY_ASSERT(index_q > 0 && index_q <= 2);
@@ -617,133 +619,6 @@ struct equal : public base_turn_handler
}
};
-
-template
-<
- typename TurnInfo
->
-struct start : public base_turn_handler
-{
- template
- <
- typename UniqueSubRange1,
- typename UniqueSubRange2,
- typename IntersectionInfo,
- typename DirInfo,
- typename SideCalculator,
- typename UmbrellaStrategy
- >
- static inline bool apply(UniqueSubRange1 const& range_p,
- UniqueSubRange2 const& range_q,
- TurnInfo& ti,
- IntersectionInfo const& info,
- DirInfo const& dir_info,
- SideCalculator const& side,
- UmbrellaStrategy const& )
- {
- // For now disabled. TODO: remove all code or fix inconsistencies
- // within validity and relations
- return false;
-
- if (dir_info.opposite)
- {
- // They should not be collinear
- return false;
- }
-
- int const side_pj_q1 = side.pj_wrt_q1();
- int const side_qj_p1 = side.qj_wrt_p1();
-
- // Get side values at starting point
- typedef detail::distance_measure
- <
- typename select_coordinate_type
- <
- typename UniqueSubRange1::point_type,
- typename UniqueSubRange2::point_type
- >::type
- > dm_type;
-
- typedef typename UmbrellaStrategy::cs_tag cs_tag;
- dm_type const dm_pi_q1 = get_distance_measure(range_q.at(0), range_q.at(1), range_p.at(0));
- dm_type const dm_qi_p1 = get_distance_measure(range_p.at(0), range_p.at(1), range_q.at(0));
-
- if (dir_info.how_a == -1 && dir_info.how_b == -1)
- {
- // Both p and q leave
- if (dm_pi_q1.is_zero() && dm_qi_p1.is_zero())
- {
- // Exactly collinear, not necessary to handle it
- return false;
- }
-
- if (! (dm_pi_q1.is_small() && dm_qi_p1.is_small()))
- {
- // Not nearly collinear
- return false;
- }
-
- if (side_qj_p1 == 0)
- {
- // Collinear is not handled
- return false;
- }
-
- ui_else_iu(side_qj_p1 == -1, ti);
- }
- else if (dir_info.how_b == -1)
- {
- // p --------------->
- // |
- // | q q leaves
- // v
- //
-
- if (dm_qi_p1.is_zero() || ! dm_qi_p1.is_small())
- {
- // Exactly collinear
- return false;
- }
-
- if (side_qj_p1 == 0)
- {
- // Collinear is not handled
- return false;
- }
-
- ui_else_iu(side_qj_p1 == -1, ti);
- }
- else if (dir_info.how_a == -1)
- {
- if (dm_pi_q1.is_zero() || ! dm_pi_q1.is_small())
- {
- // It starts exactly, not necessary to handle it
- return false;
- }
-
- // p leaves
- if (side_pj_q1 == 0)
- {
- // Collinear is not handled
- return false;
- }
-
- ui_else_iu(side_pj_q1 == 1, ti);
- }
- else
- {
- // Not supported
- return false;
- }
-
- // Copy intersection point
- assign_point(ti, method_start, info, 0);
- return true;
- }
-
-};
-
-
template
<
typename TurnInfo,
@@ -1167,6 +1042,8 @@ struct get_turn_info
switch(method)
{
case 'a' : // "angle"
+ case 'f' : // "from"
+ case 's' : // "start"
do_only_convert = true;
break;
@@ -1208,20 +1085,6 @@ struct get_turn_info
*out++ = tp;
}
break;
- case 'f' :
- case 's' :
- {
- // "from" or "start" without rescaling, it is in some cases necessary to handle
- if (start::apply(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides(), umbrella_strategy))
- {
- *out++ = tp;
- }
- else
- {
- do_only_convert = true;
- }
- }
- break;
case 'e':
{
if ( ! inters.d_info().opposite )
diff --git a/include/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp b/include/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp
index 478811860..734b3051b 100644
--- a/include/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp
+++ b/include/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp
@@ -22,7 +22,7 @@
#include
#include
#include
-#include
+#include
#include
namespace boost { namespace geometry {
@@ -153,18 +153,20 @@ template
typename UniqueSubRange1, typename UniqueSubRange2,
typename RobustPolicy
>
-struct robust_points
+struct robust_point_calculator
{
typedef typename geometry::robust_point_type
<
typename UniqueSubRange1::point_type, RobustPolicy
>::type robust_point1_type;
+ typedef typename geometry::robust_point_type
+ <
+ typename UniqueSubRange2::point_type, RobustPolicy
+ >::type robust_point2_type;
- typedef robust_point1_type robust_point2_type;
-
- inline robust_points(UniqueSubRange1 const& range_p,
- UniqueSubRange2 const& range_q,
- RobustPolicy const& robust_policy)
+ inline robust_point_calculator(UniqueSubRange1 const& range_p,
+ UniqueSubRange2 const& range_q,
+ RobustPolicy const& robust_policy)
: m_robust_policy(robust_policy)
, m_range_p(range_p)
, m_range_q(range_q)
@@ -214,18 +216,52 @@ private :
mutable bool m_qk_retrieved;
};
+// Default version (empty - specialized below)
template
<
typename UniqueSubRange1, typename UniqueSubRange2,
- typename TurnPoint, typename UmbrellaStrategy, typename RobustPolicy>
-class intersection_info_base
- : private robust_points
+ typename TurnPoint, typename UmbrellaStrategy,
+ typename RobustPolicy,
+ typename Tag = typename rescale_policy_type::type
+>
+class intersection_info_base {};
+
+// Version with rescaling, having robust points
+template
+<
+ typename UniqueSubRange1, typename UniqueSubRange2,
+ typename TurnPoint, typename UmbrellaStrategy,
+ typename RobustPolicy
+>
+class intersection_info_base
{
- typedef robust_points base;
+ typedef robust_point_calculator
+ <
+ UniqueSubRange1, UniqueSubRange2,
+ RobustPolicy
+ >
+ robust_calc_type;
public:
- typedef typename base::robust_point1_type robust_point1_type;
- typedef typename base::robust_point2_type robust_point2_type;
+ typedef segment_intersection_points
+ <
+ TurnPoint,
+ geometry::segment_ratio
+ > intersection_point_type;
+ typedef policies::relate::segments_tupled
+ <
+ policies::relate::segments_intersection_points
+ <
+ intersection_point_type
+ >,
+ policies::relate::segments_direction
+ > intersection_policy_type;
+
+ typedef typename intersection_policy_type::return_type result_type;
+
+ typedef typename robust_calc_type::robust_point1_type robust_point1_type;
+ typedef typename robust_calc_type::robust_point2_type robust_point2_type;
typedef robust_subrange_adapter robust_subrange1;
typedef robust_subrange_adapter robust_subrange2;
@@ -246,28 +282,31 @@ public:
UniqueSubRange2 const& range_q,
UmbrellaStrategy const& umbrella_strategy,
RobustPolicy const& robust_policy)
- : base(range_p, range_q, robust_policy)
- , m_range_p(range_p)
+ : m_range_p(range_p)
, m_range_q(range_q)
- , m_robust_range_p(range_p, base::m_rpi, base::m_rpj, robust_policy)
- , m_robust_range_q(range_q, base::m_rqi, base::m_rqj, robust_policy)
+ , m_robust_calc(range_p, range_q, robust_policy)
+ , m_robust_range_p(range_p, m_robust_calc.m_rpi, m_robust_calc.m_rpj, robust_policy)
+ , m_robust_range_q(range_q, m_robust_calc.m_rqi, m_robust_calc.m_rqj, robust_policy)
, m_side_calc(m_robust_range_p, m_robust_range_q,
umbrella_strategy.get_side_strategy())
+ , m_result(umbrella_strategy.apply(range_p, range_q,
+ intersection_policy_type(),
+ m_robust_range_p, m_robust_range_q))
{}
- inline typename UniqueSubRange1::point_type const& pi() const { return m_range_p.at(0); }
- inline typename UniqueSubRange2::point_type const& qi() const { return m_range_q.at(0); }
+ inline bool p_is_last_segment() const { return m_range_p.is_last_segment(); }
+ inline bool q_is_last_segment() const { return m_range_q.is_last_segment(); }
- inline robust_point1_type const& rpi() const { return base::m_rpi; }
- inline robust_point1_type const& rpj() const { return base::m_rpj; }
- inline robust_point1_type const& rpk() const { return base::get_rpk(); }
+ inline robust_point1_type const& rpi() const { return m_robust_calc.m_rpi; }
+ inline robust_point1_type const& rpj() const { return m_robust_calc.m_rpj; }
+ inline robust_point1_type const& rpk() const { return m_robust_calc.get_rpk(); }
- inline robust_point2_type const& rqi() const { return base::m_rqi; }
- inline robust_point2_type const& rqj() const { return base::m_rqj; }
- inline robust_point2_type const& rqk() const { return base::get_rqk(); }
+ inline robust_point2_type const& rqi() const { return m_robust_calc.m_rqi; }
+ inline robust_point2_type const& rqj() const { return m_robust_calc.m_rqj; }
+ inline robust_point2_type const& rqk() const { return m_robust_calc.get_rqk(); }
inline side_calculator_type const& sides() const { return m_side_calc; }
-
+
robust_swapped_side_calculator_type get_swapped_sides() const
{
robust_swapped_side_calculator_type result(
@@ -276,31 +315,49 @@ public:
return result;
}
+private :
+
// Owned by get_turns
UniqueSubRange1 const& m_range_p;
UniqueSubRange2 const& m_range_q;
-private :
+
// Owned by this class
+ robust_calc_type m_robust_calc;
robust_subrange1 m_robust_range_p;
robust_subrange2 m_robust_range_q;
side_calculator_type m_side_calc;
+
+protected :
+ result_type m_result;
};
+// Version without rescaling
template
<
typename UniqueSubRange1, typename UniqueSubRange2,
- typename TurnPoint, typename UmbrellaStrategy
+ typename TurnPoint, typename UmbrellaStrategy,
+ typename RobustPolicy
>
class intersection_info_base
+ TurnPoint, UmbrellaStrategy, RobustPolicy, no_rescale_policy_tag>
{
public:
+
+ typedef segment_intersection_points intersection_point_type;
+ typedef policies::relate::segments_tupled
+ <
+ policies::relate::segments_intersection_points
+ <
+ intersection_point_type
+ >,
+ policies::relate::segments_direction
+ > intersection_policy_type;
+
+ typedef typename intersection_policy_type::return_type result_type;
+
typedef typename UniqueSubRange1::point_type point1_type;
typedef typename UniqueSubRange2::point_type point2_type;
- typedef typename UniqueSubRange1::point_type robust_point1_type;
- typedef typename UniqueSubRange2::point_type robust_point2_type;
-
typedef typename UmbrellaStrategy::cs_tag cs_tag;
typedef typename UmbrellaStrategy::side_strategy_type side_strategy_type;
@@ -315,13 +372,17 @@ public:
intersection_info_base(UniqueSubRange1 const& range_p,
UniqueSubRange2 const& range_q,
UmbrellaStrategy const& umbrella_strategy,
- no_rescale_policy const& /*robust_policy*/)
+ no_rescale_policy const& )
: m_range_p(range_p)
, m_range_q(range_q)
, m_side_calc(range_p, range_q,
umbrella_strategy.get_side_strategy())
+ , m_result(umbrella_strategy.apply(range_p, range_q, intersection_policy_type()))
{}
+ inline bool p_is_last_segment() const { return m_range_p.is_last_segment(); }
+ inline bool q_is_last_segment() const { return m_range_q.is_last_segment(); }
+
inline point1_type const& rpi() const { return m_side_calc.get_pi(); }
inline point1_type const& rpj() const { return m_side_calc.get_pj(); }
inline point1_type const& rpk() const { return m_side_calc.get_pk(); }
@@ -340,13 +401,16 @@ public:
return result;
}
-protected :
+private :
// Owned by get_turns
UniqueSubRange1 const& m_range_p;
UniqueSubRange2 const& m_range_q;
-private :
- // Owned here, passed by .get_side_strategy()
+
+ // Owned by this class
side_calculator_type m_side_calc;
+
+protected :
+ result_type m_result;
};
@@ -365,37 +429,17 @@ class intersection_info
TurnPoint, UmbrellaStrategy, RobustPolicy> base;
public:
- typedef segment_intersection_points
- <
- TurnPoint,
- typename geometry::segment_ratio_type
- <
- TurnPoint, RobustPolicy
- >::type
- > intersection_point_type;
typedef typename UniqueSubRange1::point_type point1_type;
typedef typename UniqueSubRange2::point_type point2_type;
- // NOTE: formerly defined in intersection_strategies
- typedef policies::relate::segments_tupled
- <
- policies::relate::segments_intersection_points
- <
- intersection_point_type
- >,
- policies::relate::segments_direction
- > intersection_policy_type;
-
typedef UmbrellaStrategy intersection_strategy_type;
typedef typename UmbrellaStrategy::side_strategy_type side_strategy_type;
typedef typename UmbrellaStrategy::cs_tag cs_tag;
- typedef model::referring_segment segment_type1;
- typedef model::referring_segment segment_type2;
typedef typename base::side_calculator_type side_calculator_type;
+ typedef typename base::result_type result_type;
- typedef typename intersection_policy_type::return_type result_type;
typedef typename boost::tuples::element<0, result_type>::type i_info_type; // intersection_info
typedef typename boost::tuples::element<1, result_type>::type d_info_type; // dir_info
@@ -405,20 +449,13 @@ public:
RobustPolicy const& robust_policy)
: base(range_p, range_q,
umbrella_strategy, robust_policy)
- , m_result(umbrella_strategy.apply(
- segment_type1(range_p.at(0), range_p.at(1)),
- segment_type2(range_q.at(0), range_q.at(1)),
- intersection_policy_type(),
- robust_policy,
- base::rpi(), base::rpj(),
- base::rqi(), base::rqj()))
, m_intersection_strategy(umbrella_strategy)
, m_robust_policy(robust_policy)
{}
- inline result_type const& result() const { return m_result; }
- inline i_info_type const& i_info() const { return m_result.template get<0>(); }
- inline d_info_type const& d_info() const { return m_result.template get<1>(); }
+ inline result_type const& result() const { return base::m_result; }
+ inline i_info_type const& i_info() const { return base::m_result.template get<0>(); }
+ inline d_info_type const& d_info() const { return base::m_result.template get<1>(); }
inline side_strategy_type get_side_strategy() const
{
@@ -428,7 +465,7 @@ public:
// TODO: it's more like is_spike_ip_p
inline bool is_spike_p() const
{
- if (base::m_range_p.is_last_segment())
+ if (base::p_is_last_segment())
{
return false;
}
@@ -443,7 +480,7 @@ public:
}
// TODO: why is q used to determine spike property in p?
- bool const has_qk = ! base::m_range_q.is_last_segment();
+ bool const has_qk = ! base::q_is_last_segment();
int const qk_p1 = has_qk ? base::sides().qk_wrt_p1() : 0;
int const qk_p2 = has_qk ? base::sides().qk_wrt_p2() : 0;
@@ -467,7 +504,7 @@ public:
inline bool is_spike_q() const
{
- if (base::m_range_q.is_last_segment())
+ if (base::q_is_last_segment())
{
return false;
}
@@ -481,7 +518,7 @@ public:
}
// TODO: why is p used to determine spike property in q?
- bool const has_pk = ! base::m_range_p.is_last_segment();
+ bool const has_pk = ! base::p_is_last_segment();
int const pk_q1 = has_pk ? base::sides().pk_wrt_q1() : 0;
int const pk_q2 = has_pk ? base::sides().pk_wrt_q2() : 0;
@@ -523,7 +560,6 @@ private:
}
}
- result_type m_result;
UmbrellaStrategy const& m_intersection_strategy;
RobustPolicy const& m_robust_policy;
};
diff --git a/include/boost/geometry/algorithms/detail/overlay/get_turns.hpp b/include/boost/geometry/algorithms/detail/overlay/get_turns.hpp
index 886f8b683..a19691d61 100644
--- a/include/boost/geometry/algorithms/detail/overlay/get_turns.hpp
+++ b/include/boost/geometry/algorithms/detail/overlay/get_turns.hpp
@@ -209,7 +209,6 @@ private :
RobustPolicy m_robust_policy;
};
-
template
<
typename Geometry1, typename Geometry2,
diff --git a/include/boost/geometry/algorithms/detail/overlay/handle_colocations.hpp b/include/boost/geometry/algorithms/detail/overlay/handle_colocations.hpp
index c417e7d1a..d948f9f27 100644
--- a/include/boost/geometry/algorithms/detail/overlay/handle_colocations.hpp
+++ b/include/boost/geometry/algorithms/detail/overlay/handle_colocations.hpp
@@ -84,15 +84,6 @@ struct turn_operation_index
signed_size_type op_index; // only 0,1
};
-struct is_discarded
-{
- template
- inline bool operator()(Turn const& turn) const
- {
- return turn.discarded;
- }
-};
-
template
struct less_by_fraction_and_type
{
@@ -534,80 +525,6 @@ inline segment_identifier get_preceding_segment_id(segment_identifier const& id,
return result;
}
-// Turns marked with method can be generated but are often duplicate,
-// unless (by floating point precision) the preceding touching turn is just missed.
-// This means that all (nearly) colocated with preceding touching turn
-// can be deleted. This is done before colocation itself (because in colocated,
-// they are only discarded, and that can give issues in traversal)
-template