Merge branch 'develop' into feature/meridian_andoyer

This commit is contained in:
Adam Wulkiewicz
2017-10-31 15:50:42 +01:00
committed by GitHub
168 changed files with 9747 additions and 3386 deletions

View File

@@ -16,6 +16,8 @@ machine:
environment:
# define tests list, if parallelism is enabled they are run in parallel
TESTS: test index/test
TESTS0: test/core test/concepts test/geometries test/arithmetic test/algorithms test/formulas test/iterators
TESTS1: test/strategies test/policies test/io test/util test/views index/test
# this is not fully bulletproof, ideally one should check
# if the current branch originates in master or develop
@@ -109,7 +111,11 @@ test:
#- cd $BOOST_ROOT/libs/geometry && index=0 ; run_tests() { for i in "$1"/* ; do if [ -f "$i"/Jamfile* ] ; then ((index++)) ; echo "$index - $i" ; ../../b2 cxxflags="--coverage" linkflags="--coverage" "$i" ; run_tests "$i" ; fi ; done } ; run_tests test
# so for now just run the tests from the list
- cd $BOOST_ROOT/libs/geometry && status=0; index=0 ; for t in ${TESTS[@]} ; do if [ $(((index++)%CIRCLE_NODE_TOTAL)) == $CIRCLE_NODE_INDEX ] ; then ../../b2 -j2 cxxflags="--coverage" linkflags="--coverage" $t ; fi || status=$? ; done ; exit $status :
#- cd $BOOST_ROOT/libs/geometry && status=0; index=0 ; for t in ${TESTS[@]} ; do if [ $(((index++)%CIRCLE_NODE_TOTAL)) == $CIRCLE_NODE_INDEX ] ; then ../../b2 -j2 cxxflags="--coverage" linkflags="--coverage" $t ; fi || status=$? ; done ; exit $status :
# parallel: true
# so for now just run the tests from 2 lists
- cd $BOOST_ROOT/libs/geometry && status=0; case $CIRCLE_NODE_INDEX in 0) for t in ${TESTS0[@]} ; do ../../b2 -j2 cxxflags="--coverage" linkflags="--coverage" $t || status=$? ; done ;; 1) for t in ${TESTS1[@]} ; do ../../b2 -j2 cxxflags="--coverage" linkflags="--coverage" $t || status=$? ; done ;; esac ; exit $status :
parallel: true
post:

View File

@@ -546,7 +546,7 @@ where a strategy is specified explicitly and constructed with a radius.
[heading Point Concept]
The five traits classes mentioned in the previous sections form together the
Point Concept. Any point type for which specializations are implemented in
the traits namespace should be accepted a as valid type. So the Point Concept
the traits namespace should be accepted as a valid type. So the Point Concept
consists of:
* a specialization for `traits::tag`
@@ -637,6 +637,20 @@ and modify our distance function:
Of course also the apply functions in the dispatch specializations will return a result like this.
They have a strategy as a template parameter everywhere, making the less verbose version possible.
[heading Axis Order]
This is an important note for users who develop GIS applications, require compliance with OGC
standards or use variety of coordinate reference systems (CRS).
Boost.Geometry convention is that coordinate values of 2D tuple is always given according to
mathematical axis order: X,Y. Considering GIS applications, that always means easting,northing or,
in terms of geographic coordinate system: longitude,latitude.
Boost.Geometry does not allow or respect coordinate values listed in the axis order as
specified by coordinate reference system (CRS).
In practice, users may easily adapt point types with alternate axis ordering and
specify coordinate access in order as expected by Boost.Geometry.
[heading Summary]
In this design rationale, __boost_geometry__ is step by step designed using tag dispatching,

View File

@@ -69,14 +69,19 @@ Examples of some basic queries may be found in the tables below. The query regio
]
[table
[[intersects(Ring)] [intersects(Polygon)] [intersects(MultiPolygon)] [intersects(Segment)] [intersects(Linestring)]]
[[[$img/index/rtree/intersects_ring.png]] [[$img/index/rtree/intersects_poly.png]] [[$img/index/rtree/intersects_mpoly.png]] [[$img/index/rtree/intersects_segment.png]] [[$img/index/rtree/intersects_linestring.png]]]
[[intersects(Segment)] [intersects(Box)] [disjoint(Box)] [intersects(Box)] [disjoint(Box)]]
[[[$img/index/rtree/intersects_segment.png]] [[$img/index/rtree/rtree_pt_intersects_box.png]] [[$img/index/rtree/rtree_pt_disjoint_box.png]] [[$img/index/rtree/rtree_seg_intersects_box.png]] [[$img/index/rtree/rtree_seg_disjoint_box.png]]]
]
[table
[/table
[[intersects(Ring)] [intersects(Polygon)] [intersects(MultiPolygon)] [intersects(Segment)] [intersects(Linestring)]]
[[[$img/index/rtree/intersects_ring.png]] [[$img/index/rtree/intersects_poly.png]] [[$img/index/rtree/intersects_mpoly.png]] [[$img/index/rtree/intersects_segment.png]] [[$img/index/rtree/intersects_linestring.png]]]
/]
[/table
[[intersects(Box)] [disjoint(Box)] [intersects(Box)] [disjoint(Box)]]
[[[$img/index/rtree/rtree_pt_intersects_box.png]] [[$img/index/rtree/rtree_pt_disjoint_box.png]] [[$img/index/rtree/rtree_seg_intersects_box.png]] [[$img/index/rtree/rtree_seg_disjoint_box.png]]]
]
/]
Spatial predicates are generated by functions defined in `boost::geometry::index` namespace.

View File

@@ -89,7 +89,10 @@
[include generated/clear.qbk]
[include generated/convert.qbk]
[include generated/convex_hull.qbk]
[section:correct correct]
[include generated/correct.qbk]
[endsect]
[section:covered_by covered_by]
[include generated/covered_by.qbk]

View File

@@ -18,20 +18,48 @@
[section:release_notes Release Notes]
[/=================]
[heading Boost 1.66]
[/=================]
[*Improvements]
[*Solved issues]
* [@https://svn.boost.org/trac10/ticket/12503 12503] Validity of complex polygon
[*Bugfixes]
* Fixes in validity of union/intersection/differece which were sometimes invalid. In most cases, results are valid now.
* Fixes in results of union/intersection/differece which could be incorrect in very complex cases
[/=================]
[heading Boost 1.65]
[/=================]
[*Improvements]
* Add correct() overload taking area strategy
* Add is_convex() overload taking side strategy
* Add missing relational operations (covered_by, crosses, equals, etc.) for MultiPoint/AnyGeometry
[*Solved issues]
* [@https://svn.boost.org/trac/boost/ticket/12410 12410] Lack of support of geographic coordinate system in correct()
* [@https://svn.boost.org/trac/boost/ticket/13035 13035] Wrong result of non-cartesian intersection strategies for segments near poles.
* [@https://svn.boost.org/trac/boost/ticket/13057 13057] Wrong result of intersects() for linestrings caused by numerical issue in disjoint() for boxes.
[*Bugfixes]
* Fix is_valid which could return false for multipolygons where an interior ring touches another interior ring
* Fix union which could produce invalid results (for some cases, this needs to define BOOST_GEOMETRY_INCLUDE_SELF_TURNS
* Fix is_valid which could return false for multipolygons where a polygon was located in an interior ring, all touching each other
* Fix union which could produce invalid results (for some cases, this needs to define BOOST_GEOMETRY_INCLUDE_SELF_TURNS)
* Fix intersection (idem), but some cases are still not yet valid
* Fix difference (idem), but some cases are still not yet valid
* Fix propagation of area strategy into the internals of various algorithms from intersection strategy
* Fix uninitialized variable in relate and reference to temporary in overlay
* Fix error in disjoint for geographic Segment/Box
* Fix handling of non-cartesian geometries in various algorithms
[/=================]
[heading Boost 1.64]

File diff suppressed because one or more lines are too long

View File

@@ -5,6 +5,10 @@
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
// 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.
@@ -28,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>
@@ -41,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>
@@ -61,7 +65,8 @@ namespace detail { namespace correct
template <typename Geometry>
struct correct_nop
{
static inline void apply(Geometry& )
template <typename Strategy>
static inline void apply(Geometry& , Strategy const& )
{}
};
@@ -104,8 +109,8 @@ struct correct_box_loop<Box, DimensionCount, DimensionCount>
template <typename Box>
struct correct_box
{
static inline void apply(Box& box)
template <typename Strategy>
static inline void apply(Box& box, Strategy const& )
{
// Currently only for Cartesian coordinates
// (or spherical without crossing dateline)
@@ -119,18 +124,12 @@ struct correct_box
// Close a ring, if not closed
template <typename Ring, typename Predicate>
template <typename Ring, template <typename> class Predicate>
struct correct_ring
{
typedef typename point_type<Ring>::type point_type;
typedef typename coordinate_type<Ring>::type coordinate_type;
typedef typename strategy::area::services::default_strategy
<
typename cs_tag<point_type>::type,
point_type
>::type strategy_type;
typedef detail::area::ring_area
<
order_as_direction<geometry::point_order<Ring>::value>::value,
@@ -138,30 +137,17 @@ struct correct_ring
> ring_area_type;
static inline void apply(Ring& r)
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;
// Correct closure if necessary
detail::correct_closure::close_or_open_ring<Ring>::apply(r);
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);
}
}
// Check area
Predicate predicate;
typedef typename default_area_result<Ring>::type area_result_type;
area_result_type const zero = area_result_type();
if (predicate(ring_area_type::apply(r, strategy_type()), zero))
typedef typename Strategy::return_type area_result_type;
Predicate<area_result_type> predicate;
area_result_type const zero = 0;
if (predicate(ring_area_type::apply(r, strategy), zero))
{
std::reverse(boost::begin(r), boost::end(r));
}
@@ -174,15 +160,15 @@ template <typename Polygon>
struct correct_polygon
{
typedef typename ring_type<Polygon>::type ring_type;
typedef typename default_area_result<Polygon>::type area_result_type;
static inline void apply(Polygon& poly)
template <typename Strategy>
static inline void apply(Polygon& poly, Strategy const& strategy)
{
correct_ring
<
ring_type,
std::less<area_result_type>
>::apply(exterior_ring(poly));
std::less
>::apply(exterior_ring(poly), strategy);
typename interior_return_type<Polygon>::type
rings = interior_rings(poly);
@@ -192,8 +178,8 @@ struct correct_polygon
correct_ring
<
ring_type,
std::greater<area_result_type>
>::apply(*it);
std::greater
>::apply(*it, strategy);
}
}
};
@@ -237,7 +223,7 @@ struct correct<Ring, ring_tag>
: detail::correct::correct_ring
<
Ring,
std::less<typename default_area_result<Ring>::type>
std::less
>
{};
@@ -281,29 +267,36 @@ namespace resolve_variant {
template <typename Geometry>
struct correct
{
static inline void apply(Geometry& geometry)
template <typename Strategy>
static inline void apply(Geometry& geometry, Strategy const& strategy)
{
concepts::check<Geometry const>();
dispatch::correct<Geometry>::apply(geometry);
dispatch::correct<Geometry>::apply(geometry, strategy);
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct correct<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
{
template <typename Strategy>
struct visitor: boost::static_visitor<void>
{
Strategy const& m_strategy;
visitor(Strategy const& strategy): m_strategy(strategy) {}
template <typename Geometry>
void operator()(Geometry& geometry) const
{
correct<Geometry>::apply(geometry);
correct<Geometry>::apply(geometry, m_strategy);
}
};
template <typename Strategy>
static inline void
apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry)
apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry, Strategy const& strategy)
{
boost::apply_visitor(visitor(), geometry);
boost::apply_visitor(visitor<Strategy>(strategy), geometry);
}
};
@@ -325,7 +318,37 @@ struct correct<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
template <typename Geometry>
inline void correct(Geometry& geometry)
{
resolve_variant::correct<Geometry>::apply(geometry);
typedef typename point_type<Geometry>::type point_type;
typedef typename strategy::area::services::default_strategy
<
typename cs_tag<point_type>::type,
point_type
>::type strategy_type;
resolve_variant::correct<Geometry>::apply(geometry, strategy_type());
}
/*!
\brief Corrects a geometry
\details Corrects a geometry: all rings which are wrongly oriented with respect
to their expected orientation are reversed. To all rings which do not have a
closing point and are typed as they should have one, the first point is
appended. Also boxes can be corrected.
\ingroup correct
\tparam Geometry \tparam_geometry
\tparam Strategy \tparam_strategy{Area}
\param geometry \param_geometry which will be corrected if necessary
\param strategy \param_strategy{area}
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/correct.qbk]}
*/
template <typename Geometry, typename Strategy>
inline void correct(Geometry& geometry, Strategy const& strategy)
{
resolve_variant::correct<Geometry>::apply(geometry, strategy);
}
#if defined(_MSC_VER)

View File

@@ -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

View File

@@ -122,7 +122,8 @@ struct buffer_range
typename DistanceStrategy,
typename JoinStrategy,
typename EndStrategy,
typename RobustPolicy
typename RobustPolicy,
typename Strategy
>
static inline
void add_join(Collection& collection,
@@ -133,18 +134,19 @@ struct buffer_range
Point const& input,
output_point_type const& perp1,
output_point_type const& perp2,
strategy::buffer::buffer_side_selector side,
geometry::strategy::buffer::buffer_side_selector side,
DistanceStrategy const& distance,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
RobustPolicy const& )
RobustPolicy const& ,
Strategy const& strategy) // side strategy
{
output_point_type intersection_point;
geometry::assign_zero(intersection_point);
strategy::buffer::join_selector join
= get_join_type(penultimate_input, previous_input, input);
if (join == strategy::buffer::join_convex)
geometry::strategy::buffer::join_selector join
= get_join_type(penultimate_input, previous_input, input, strategy);
if (join == geometry::strategy::buffer::join_convex)
{
// Calculate the intersection-point formed by the two sides.
// It might be that the two sides are not convex, but continue
@@ -157,23 +159,23 @@ struct buffer_range
switch(join)
{
case strategy::buffer::join_continue :
case geometry::strategy::buffer::join_continue :
// No join, we get two consecutive sides
break;
case strategy::buffer::join_concave :
case geometry::strategy::buffer::join_concave :
{
std::vector<output_point_type> range_out;
range_out.push_back(prev_perp2);
range_out.push_back(previous_input);
collection.add_piece(strategy::buffer::buffered_concave, previous_input, range_out);
collection.add_piece(geometry::strategy::buffer::buffered_concave, previous_input, range_out);
range_out.clear();
range_out.push_back(previous_input);
range_out.push_back(perp1);
collection.add_piece(strategy::buffer::buffered_concave, previous_input, range_out);
collection.add_piece(geometry::strategy::buffer::buffered_concave, previous_input, range_out);
}
break;
case strategy::buffer::join_spike :
case geometry::strategy::buffer::join_spike :
{
// For linestrings, only add spike at one side to avoid
// duplicates
@@ -183,7 +185,7 @@ struct buffer_range
collection.set_current_ring_concave();
}
break;
case strategy::buffer::join_convex :
case geometry::strategy::buffer::join_convex :
{
// The corner is convex, we create a join
// TODO (future) - avoid a separate vector, add the piece directly
@@ -193,7 +195,7 @@ struct buffer_range
distance.apply(previous_input, input, side),
range_out))
{
collection.add_piece(strategy::buffer::buffered_join,
collection.add_piece(geometry::strategy::buffer::buffered_join,
previous_input, range_out);
}
}
@@ -201,27 +203,24 @@ struct buffer_range
}
}
static inline strategy::buffer::join_selector get_join_type(
template <typename Strategy>
static inline geometry::strategy::buffer::join_selector get_join_type(
output_point_type const& p0,
output_point_type const& p1,
output_point_type const& p2)
output_point_type const& p2,
Strategy const& strategy) // side strategy
{
typedef typename strategy::side::services::default_strategy
<
typename cs_tag<output_point_type>::type
>::type side_strategy;
int const side = side_strategy::apply(p0, p1, p2);
return side == -1 ? strategy::buffer::join_convex
: side == 1 ? strategy::buffer::join_concave
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)
) ? strategy::buffer::join_continue
: strategy::buffer::join_spike;
) ? geometry::strategy::buffer::join_continue
: geometry::strategy::buffer::join_spike;
}
template
@@ -232,16 +231,18 @@ struct buffer_range
typename SideStrategy,
typename JoinStrategy,
typename EndStrategy,
typename RobustPolicy
typename RobustPolicy,
typename Strategy
>
static inline strategy::buffer::result_code iterate(Collection& collection,
static inline geometry::strategy::buffer::result_code iterate(Collection& collection,
Iterator begin, Iterator end,
strategy::buffer::buffer_side_selector side,
geometry::strategy::buffer::buffer_side_selector side,
DistanceStrategy const& distance_strategy,
SideStrategy const& side_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
RobustPolicy const& robust_policy,
Strategy const& strategy, // side strategy
output_point_type& first_p1,
output_point_type& first_p2,
output_point_type& last_p1,
@@ -273,7 +274,7 @@ struct buffer_range
* pup: penultimate_point
*/
strategy::buffer::result_code result = strategy::buffer::result_no_output;
geometry::strategy::buffer::result_code result = geometry::strategy::buffer::result_no_output;
bool first = true;
Iterator it = begin;
@@ -284,25 +285,25 @@ struct buffer_range
for (Iterator prev = it++; it != end; ++it)
{
generated_side.clear();
strategy::buffer::result_code error_code
geometry::strategy::buffer::result_code error_code
= side_strategy.apply(*prev, *it, side,
distance_strategy, generated_side);
if (error_code == strategy::buffer::result_no_output)
if (error_code == geometry::strategy::buffer::result_no_output)
{
// Because input is simplified, this is improbable,
// but it can happen for degenerate geometries
// Further handling of this side is skipped
continue;
}
else if (error_code == strategy::buffer::result_error_numerical)
else if (error_code == geometry::strategy::buffer::result_error_numerical)
{
return error_code;
}
BOOST_GEOMETRY_ASSERT(! generated_side.empty());
result = strategy::buffer::result_normal;
result = geometry::strategy::buffer::result_normal;
if (! first)
{
@@ -312,7 +313,7 @@ struct buffer_range
*it, generated_side.front(), generated_side.back(),
side,
distance_strategy, join_strategy, end_strategy,
robust_policy);
robust_policy, strategy);
}
collection.add_side_piece(*prev, *it, generated_side, first);
@@ -350,7 +351,8 @@ struct buffer_multi
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
typename RobustPolicy
typename RobustPolicy,
typename Strategy
>
static inline void apply(Multi const& multi,
Collection& collection,
@@ -359,7 +361,8 @@ struct buffer_multi
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
PointStrategy const& point_strategy,
RobustPolicy const& robust_policy)
RobustPolicy const& robust_policy,
Strategy const& strategy) // side strategy
{
for (typename boost::range_iterator<Multi const>::type
it = boost::begin(multi);
@@ -369,7 +372,7 @@ struct buffer_multi
Policy::apply(*it, collection,
distance_strategy, side_strategy,
join_strategy, end_strategy, point_strategy,
robust_policy);
robust_policy, strategy);
}
}
};
@@ -396,9 +399,9 @@ inline void buffer_point(Point const& point, Collection& collection,
collection.start_new_ring();
std::vector<OutputPointType> range_out;
point_strategy.apply(point, distance_strategy, range_out);
collection.add_piece(strategy::buffer::buffered_point, range_out, false);
collection.add_piece(geometry::strategy::buffer::buffered_point, range_out, false);
collection.set_piece_center(point);
collection.finish_ring(strategy::buffer::result_normal);
collection.finish_ring(geometry::strategy::buffer::result_normal);
}
@@ -436,7 +439,8 @@ struct buffer_inserter<point_tag, Point, RingOutput>
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
typename RobustPolicy
typename RobustPolicy,
typename Strategy
>
static inline void apply(Point const& point, Collection& collection,
DistanceStrategy const& distance_strategy,
@@ -444,7 +448,8 @@ struct buffer_inserter<point_tag, Point, RingOutput>
JoinStrategy const& ,
EndStrategy const& ,
PointStrategy const& point_strategy,
RobustPolicy const& )
RobustPolicy const& ,
Strategy const& ) // side strategy
{
detail::buffer::buffer_point
<
@@ -472,29 +477,32 @@ struct buffer_inserter_ring
typename SideStrategy,
typename JoinStrategy,
typename EndStrategy,
typename RobustPolicy
typename RobustPolicy,
typename Strategy
>
static inline strategy::buffer::result_code iterate(Collection& collection,
static inline geometry::strategy::buffer::result_code iterate(Collection& collection,
Iterator begin, Iterator end,
strategy::buffer::buffer_side_selector side,
geometry::strategy::buffer::buffer_side_selector side,
DistanceStrategy const& distance_strategy,
SideStrategy const& side_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
RobustPolicy const& robust_policy)
RobustPolicy const& robust_policy,
Strategy const& strategy) // side strategy
{
output_point_type first_p1, first_p2, last_p1, last_p2;
typedef detail::buffer::buffer_range<RingOutput> buffer_range;
strategy::buffer::result_code result
geometry::strategy::buffer::result_code result
= buffer_range::iterate(collection, begin, end,
side,
distance_strategy, side_strategy, join_strategy, end_strategy, robust_policy,
distance_strategy, side_strategy, join_strategy, end_strategy,
robust_policy, strategy,
first_p1, first_p2, last_p1, last_p2);
// Generate closing join
if (result == strategy::buffer::result_normal)
if (result == geometry::strategy::buffer::result_normal)
{
buffer_range::add_join(collection,
*(end - 2),
@@ -502,7 +510,7 @@ struct buffer_inserter_ring
*(begin + 1), first_p1, first_p2,
side,
distance_strategy, join_strategy, end_strategy,
robust_policy);
robust_policy, strategy);
}
// Buffer is closed automatically by last closing corner
@@ -517,21 +525,23 @@ struct buffer_inserter_ring
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
typename RobustPolicy
typename RobustPolicy,
typename Strategy
>
static inline strategy::buffer::result_code apply(RingInput const& ring,
static inline geometry::strategy::buffer::result_code apply(RingInput const& ring,
Collection& collection,
DistanceStrategy const& distance,
SideStrategy const& side_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
PointStrategy const& point_strategy,
RobustPolicy const& robust_policy)
RobustPolicy const& robust_policy,
Strategy const& strategy) // side strategy
{
RingInput simplified;
detail::buffer::simplify_input(ring, distance, simplified);
strategy::buffer::result_code code = strategy::buffer::result_no_output;
geometry::strategy::buffer::result_code code = geometry::strategy::buffer::result_no_output;
std::size_t n = boost::size(simplified);
std::size_t const min_points = core_detail::closure::minimum_ring_size
@@ -546,18 +556,20 @@ struct buffer_inserter_ring
{
// Walk backwards (rings will be reversed afterwards)
code = iterate(collection, boost::rbegin(view), boost::rend(view),
strategy::buffer::buffer_side_right,
distance, side_strategy, join_strategy, end_strategy, robust_policy);
geometry::strategy::buffer::buffer_side_right,
distance, side_strategy, join_strategy, end_strategy,
robust_policy, strategy);
}
else
{
code = iterate(collection, boost::begin(view), boost::end(view),
strategy::buffer::buffer_side_left,
distance, side_strategy, join_strategy, end_strategy, robust_policy);
geometry::strategy::buffer::buffer_side_left,
distance, side_strategy, join_strategy, end_strategy,
robust_policy, strategy);
}
}
if (code == strategy::buffer::result_no_output && n >= 1)
if (code == geometry::strategy::buffer::result_no_output && n >= 1)
{
// Use point_strategy to buffer degenerated ring
detail::buffer::buffer_point<output_point_type>
@@ -586,23 +598,25 @@ struct buffer_inserter<ring_tag, RingInput, RingOutput>
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
typename RobustPolicy
typename RobustPolicy,
typename Strategy
>
static inline strategy::buffer::result_code apply(RingInput const& ring,
static inline geometry::strategy::buffer::result_code apply(RingInput const& ring,
Collection& collection,
DistanceStrategy const& distance,
SideStrategy const& side_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
PointStrategy const& point_strategy,
RobustPolicy const& robust_policy)
RobustPolicy const& robust_policy,
Strategy const& strategy) // side strategy
{
collection.start_new_ring();
strategy::buffer::result_code const code
geometry::strategy::buffer::result_code const code
= buffer_inserter_ring<RingInput, RingOutput>::apply(ring,
collection, distance,
side_strategy, join_strategy, end_strategy, point_strategy,
robust_policy);
robust_policy, strategy);
collection.finish_ring(code);
return code;
}
@@ -627,16 +641,18 @@ struct buffer_inserter<linestring_tag, Linestring, Polygon>
typename SideStrategy,
typename JoinStrategy,
typename EndStrategy,
typename RobustPolicy
typename RobustPolicy,
typename Strategy
>
static inline strategy::buffer::result_code iterate(Collection& collection,
static inline geometry::strategy::buffer::result_code iterate(Collection& collection,
Iterator begin, Iterator end,
strategy::buffer::buffer_side_selector side,
geometry::strategy::buffer::buffer_side_selector side,
DistanceStrategy const& distance_strategy,
SideStrategy const& side_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
RobustPolicy const& robust_policy,
Strategy const& strategy, // side strategy
output_point_type& first_p1)
{
input_point_type const& ultimate_point = *(end - 1);
@@ -647,18 +663,18 @@ struct buffer_inserter<linestring_tag, Linestring, Polygon>
// we have it already from the first phase (left).
// But for the first pass, we have to generate it
output_point_type reverse_p1;
if (side == strategy::buffer::buffer_side_right)
if (side == geometry::strategy::buffer::buffer_side_right)
{
reverse_p1 = first_p1;
}
else
{
std::vector<output_point_type> generated_side;
strategy::buffer::result_code code
geometry::strategy::buffer::result_code code
= side_strategy.apply(ultimate_point, penultimate_point,
strategy::buffer::buffer_side_right,
geometry::strategy::buffer::buffer_side_right,
distance_strategy, generated_side);
if (code != strategy::buffer::result_normal)
if (code != geometry::strategy::buffer::result_normal)
{
// No output or numerical error
return code;
@@ -668,16 +684,18 @@ struct buffer_inserter<linestring_tag, Linestring, Polygon>
output_point_type first_p2, last_p1, last_p2;
strategy::buffer::result_code result
geometry::strategy::buffer::result_code result
= detail::buffer::buffer_range<output_ring_type>::iterate(collection,
begin, end, side,
distance_strategy, side_strategy, join_strategy, end_strategy, robust_policy,
distance_strategy, side_strategy, join_strategy, end_strategy,
robust_policy, strategy,
first_p1, first_p2, last_p1, last_p2);
if (result == strategy::buffer::result_normal)
if (result == geometry::strategy::buffer::result_normal)
{
std::vector<output_point_type> range_out;
end_strategy.apply(penultimate_point, last_p2, ultimate_point, reverse_p1, side, distance_strategy, range_out);
end_strategy.apply(penultimate_point, last_p2, ultimate_point, reverse_p1,
side, distance_strategy, range_out);
collection.add_endcap(end_strategy, range_out, ultimate_point);
}
return result;
@@ -691,20 +709,23 @@ struct buffer_inserter<linestring_tag, Linestring, Polygon>
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
typename RobustPolicy
typename RobustPolicy,
typename Strategy
>
static inline strategy::buffer::result_code apply(Linestring const& linestring, Collection& collection,
static inline geometry::strategy::buffer::result_code apply(Linestring const& linestring,
Collection& collection,
DistanceStrategy const& distance,
SideStrategy const& side_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
PointStrategy const& point_strategy,
RobustPolicy const& robust_policy)
RobustPolicy const& robust_policy,
Strategy const& strategy) // side strategy
{
Linestring simplified;
detail::buffer::simplify_input(linestring, distance, simplified);
strategy::buffer::result_code code = strategy::buffer::result_no_output;
geometry::strategy::buffer::result_code code = geometry::strategy::buffer::result_no_output;
std::size_t n = boost::size(simplified);
if (n > 1)
{
@@ -712,21 +733,23 @@ struct buffer_inserter<linestring_tag, Linestring, Polygon>
output_point_type first_p1;
code = iterate(collection,
boost::begin(simplified), boost::end(simplified),
strategy::buffer::buffer_side_left,
distance, side_strategy, join_strategy, end_strategy, robust_policy,
geometry::strategy::buffer::buffer_side_left,
distance, side_strategy, join_strategy, end_strategy,
robust_policy, strategy,
first_p1);
if (code == strategy::buffer::result_normal)
if (code == geometry::strategy::buffer::result_normal)
{
code = iterate(collection,
boost::rbegin(simplified), boost::rend(simplified),
strategy::buffer::buffer_side_right,
distance, side_strategy, join_strategy, end_strategy, robust_policy,
geometry::strategy::buffer::buffer_side_right,
distance, side_strategy, join_strategy, end_strategy,
robust_policy, strategy,
first_p1);
}
collection.finish_ring(code);
}
if (code == strategy::buffer::result_no_output && n >= 1)
if (code == geometry::strategy::buffer::result_no_output && n >= 1)
{
// Use point_strategy to buffer degenerated linestring
detail::buffer::buffer_point<output_point_type>
@@ -763,7 +786,8 @@ private:
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
typename RobustPolicy
typename RobustPolicy,
typename Strategy
>
static inline
void iterate(Iterator begin, Iterator end,
@@ -774,15 +798,16 @@ private:
EndStrategy const& end_strategy,
PointStrategy const& point_strategy,
RobustPolicy const& robust_policy,
Strategy const& strategy, // side strategy
bool is_interior)
{
for (Iterator it = begin; it != end; ++it)
{
collection.start_new_ring();
strategy::buffer::result_code const code
geometry::strategy::buffer::result_code const code
= policy::apply(*it, collection, distance, side_strategy,
join_strategy, end_strategy, point_strategy,
robust_policy);
robust_policy, strategy);
collection.finish_ring(code, is_interior);
}
@@ -797,7 +822,8 @@ private:
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
typename RobustPolicy
typename RobustPolicy,
typename Strategy
>
static inline
void apply_interior_rings(InteriorRings const& interior_rings,
@@ -807,12 +833,13 @@ private:
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
PointStrategy const& point_strategy,
RobustPolicy const& robust_policy)
RobustPolicy const& robust_policy,
Strategy const& strategy) // side strategy
{
iterate(boost::begin(interior_rings), boost::end(interior_rings),
collection, distance, side_strategy,
join_strategy, end_strategy, point_strategy,
robust_policy, true);
robust_policy, strategy, true);
}
public:
@@ -824,7 +851,8 @@ public:
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
typename RobustPolicy
typename RobustPolicy,
typename Strategy
>
static inline void apply(PolygonInput const& polygon,
Collection& collection,
@@ -833,16 +861,17 @@ public:
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
PointStrategy const& point_strategy,
RobustPolicy const& robust_policy)
RobustPolicy const& robust_policy,
Strategy const& strategy) // side strategy
{
{
collection.start_new_ring();
strategy::buffer::result_code const code
geometry::strategy::buffer::result_code const code
= policy::apply(exterior_ring(polygon), collection,
distance, side_strategy,
join_strategy, end_strategy, point_strategy,
robust_policy);
robust_policy, strategy);
collection.finish_ring(code, false,
geometry::num_interior_rings(polygon) > 0u);
@@ -851,7 +880,7 @@ public:
apply_interior_rings(interior_rings(polygon),
collection, distance, side_strategy,
join_strategy, end_strategy, point_strategy,
robust_policy);
robust_policy, strategy);
}
};
@@ -945,7 +974,7 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator
>::apply(geometry_input, collection,
distance_strategy, side_strategy, join_strategy,
end_strategy, point_strategy,
robust_policy);
robust_policy, intersection_strategy.get_side_strategy());
collection.get_turns();
collection.classify_turns(linear);

View File

@@ -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>
@@ -142,10 +143,20 @@ struct buffered_piece_collection
robust_point_type
>::type robust_comparable_radius_type;
typedef typename strategy::side::services::default_strategy
typedef typename IntersectionStrategy::side_strategy_type side_strategy_type;
typedef typename IntersectionStrategy::template area_strategy
<
typename cs_tag<point_type>::type
>::type side_strategy;
point_type
>::type area_strategy_type;
typedef typename IntersectionStrategy::template area_strategy
<
robust_point_type
>::type robust_area_strategy_type;
typedef typename area_strategy_type::return_type area_result_type;
typedef typename robust_area_strategy_type::return_type robust_area_result_type;
typedef typename geometry::rescale_policy_type
<
@@ -306,7 +317,10 @@ struct buffered_piece_collection
cluster_type m_clusters;
IntersectionStrategy const& m_intersection_strategy;
IntersectionStrategy m_intersection_strategy;
side_strategy_type m_side_strategy;
area_strategy_type m_area_strategy;
robust_area_strategy_type m_robust_area_strategy;
RobustPolicy const& m_robust_policy;
struct redundant_turn
@@ -321,6 +335,9 @@ struct buffered_piece_collection
RobustPolicy const& robust_policy)
: m_first_piece_index(-1)
, m_intersection_strategy(intersection_strategy)
, m_side_strategy(intersection_strategy.get_side_strategy())
, m_area_strategy(intersection_strategy.template get_area_strategy<point_type>())
, m_robust_area_strategy(intersection_strategy.template get_area_strategy<robust_point_type>())
, m_robust_policy(robust_policy)
{}
@@ -478,7 +495,7 @@ struct buffered_piece_collection
for (typename occupation_map_type::iterator it = occupation_map.begin();
it != occupation_map.end(); ++it)
{
it->second.get_left_turns(it->first, m_turns);
it->second.get_left_turns(it->first, m_turns, m_side_strategy);
}
}
@@ -699,7 +716,7 @@ struct buffered_piece_collection
++it)
{
piece& pc = *it;
if (geometry::area(pc.robust_ring) < 0)
if (geometry::area(pc.robust_ring, m_robust_area_strategy) < 0)
{
// Rings can be ccw:
// - in a concave piece
@@ -1220,14 +1237,9 @@ struct buffered_piece_collection
inline void enrich()
{
typedef typename strategy::side::services::default_strategy
<
typename cs_tag<Ring>::type
>::type side_strategy_type;
enrich_intersection_points<false, false, overlay_buffer>(m_turns,
m_clusters, offsetted_rings, offsetted_rings,
m_robust_policy, side_strategy_type());
m_robust_policy, m_side_strategy);
}
// Discards all rings which do have not-OK intersection points only.
@@ -1314,7 +1326,7 @@ struct buffered_piece_collection
buffered_ring<Ring>& ring = *it;
if (! ring.has_intersections()
&& boost::size(ring) > 0u
&& geometry::area(ring) < 0)
&& geometry::area(ring, m_area_strategy) < 0)
{
if (! point_coveredby_original(geometry::range::front(ring)))
{
@@ -1358,12 +1370,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);
}
@@ -1391,7 +1405,7 @@ struct buffered_piece_collection
template <typename GeometryOutput, typename OutputIterator>
inline OutputIterator assign(OutputIterator out) const
{
typedef detail::overlay::ring_properties<point_type> properties;
typedef detail::overlay::ring_properties<point_type, area_result_type> properties;
std::map<ring_identifier, properties> selected;
@@ -1407,7 +1421,7 @@ struct buffered_piece_collection
if (! it->has_intersections()
&& ! it->is_untouched_outside_original)
{
properties p = properties(*it);
properties p = properties(*it, m_area_strategy);
if (p.valid)
{
ring_identifier id(0, index, -1);
@@ -1423,7 +1437,7 @@ struct buffered_piece_collection
it != boost::end(traversed_rings);
++it, ++index)
{
properties p = properties(*it);
properties p = properties(*it, m_area_strategy);
if (p.valid)
{
ring_identifier id(2, index, -1);
@@ -1431,7 +1445,10 @@ struct buffered_piece_collection
}
}
detail::overlay::assign_parents(offsetted_rings, traversed_rings, selected, m_intersection_strategy, true);
// 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);
}

View File

@@ -127,26 +127,31 @@ class piece_turn_visitor
template <std::size_t Dimension, typename Iterator, typename Box>
inline void move_begin_iterator(Iterator& it_begin, Iterator it_beyond,
signed_size_type& index, int dir, Box const& other_bounding_box)
signed_size_type& index, int dir,
Box const& this_bounding_box,
Box const& other_bounding_box)
{
for(; it_begin != it_beyond
&& it_begin + 1 != it_beyond
&& detail::section::preceding<Dimension>(dir, *(it_begin + 1),
other_bounding_box, m_robust_policy);
this_bounding_box,
other_bounding_box,
m_robust_policy);
++it_begin, index++)
{}
}
template <std::size_t Dimension, typename Iterator, typename Box>
inline void move_end_iterator(Iterator it_begin, Iterator& it_beyond,
int dir, Box const& other_bounding_box)
int dir, Box const& this_bounding_box,
Box const& other_bounding_box)
{
while (it_beyond != it_begin
&& it_beyond - 1 != it_begin
&& it_beyond - 2 != it_begin)
{
if (detail::section::exceeding<Dimension>(dir, *(it_beyond - 2),
other_bounding_box, m_robust_policy))
this_bounding_box, other_bounding_box, m_robust_policy))
{
--it_beyond;
}
@@ -192,23 +197,23 @@ class piece_turn_visitor
// Set begin/end of monotonic ranges, in both x/y directions
signed_size_type index1 = sec1_first_index;
move_begin_iterator<0>(it1_first, it1_beyond, index1,
section1.directions[0], section2.bounding_box);
section1.directions[0], section1.bounding_box, section2.bounding_box);
move_end_iterator<0>(it1_first, it1_beyond,
section1.directions[0], section2.bounding_box);
section1.directions[0], section1.bounding_box, section2.bounding_box);
move_begin_iterator<1>(it1_first, it1_beyond, index1,
section1.directions[1], section2.bounding_box);
section1.directions[1], section1.bounding_box, section2.bounding_box);
move_end_iterator<1>(it1_first, it1_beyond,
section1.directions[1], section2.bounding_box);
section1.directions[1], section1.bounding_box, section2.bounding_box);
signed_size_type index2 = sec2_first_index;
move_begin_iterator<0>(it2_first, it2_beyond, index2,
section2.directions[0], section1.bounding_box);
section2.directions[0], section2.bounding_box, section1.bounding_box);
move_end_iterator<0>(it2_first, it2_beyond,
section2.directions[0], section1.bounding_box);
section2.directions[0], section2.bounding_box, section1.bounding_box);
move_begin_iterator<1>(it2_first, it2_beyond, index2,
section2.directions[1], section1.bounding_box);
section2.directions[1], section2.bounding_box, section1.bounding_box);
move_end_iterator<1>(it2_first, it2_beyond,
section2.directions[1], section1.bounding_box);
section2.directions[1], section2.bounding_box, section1.bounding_box);
turn_type the_model;
the_model.operations[0].piece_index = piece1.index;

View File

@@ -2,10 +2,11 @@
// Copyright (c) 2015 Barend Gehrels, Amsterdam, the Netherlands.
// 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
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -17,14 +18,22 @@
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/select_coordinate_type.hpp>
#include <boost/geometry/util/normalize_spheroidal_coordinates.hpp>
#include <boost/mpl/assert.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
// TODO: remove
template <std::size_t Index, typename Point1, typename Point2>
inline int sign_of_difference(Point1 const& point1, Point2 const& point2)
{
@@ -37,6 +46,193 @@ inline int sign_of_difference(Point1 const& point1, Point2 const& point2)
}
template <typename Point, typename CSTag = typename cs_tag<Point>::type>
struct direction_code_impl
{
BOOST_MPL_ASSERT_MSG((false), NOT_IMPLEMENTED_FOR_THIS_CS, (CSTag));
};
template <typename Point>
struct direction_code_impl<Point, cartesian_tag>
{
template <typename Point1, typename Point2>
static inline int apply(Point1 const& segment_a, Point1 const& segment_b,
Point2 const& p)
{
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))) )
{
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)
{
s1 = x1 > 0 ? 1 : -1;
s2 = x2 > 0 ? 1 : -1;
}
else
{
s1 = y1 > 0 ? 1 : -1;
s2 = y2 > 0 ? 1 : -1;
}
return s1 == s2 ? -1 : 1;
}
};
template <typename Point>
struct direction_code_impl<Point, spherical_equatorial_tag>
{
template <typename Point1, typename Point2>
static inline int apply(Point1 const& segment_a, Point1 const& segment_b,
Point2 const& p)
{
typedef typename coordinate_type<Point1>::type coord1_t;
typedef typename coordinate_type<Point2>::type coord2_t;
typedef typename coordinate_system<Point1>::type::units units_t;
typedef typename coordinate_system<Point2>::type::units units2_t;
BOOST_MPL_ASSERT_MSG((boost::is_same<units_t, units2_t>::value),
NOT_IMPLEMENTED_FOR_DIFFERENT_UNITS,
(units_t, units2_t));
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;
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);
coord1_t const b0 = geometry::get<0>(segment_b);
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);
if ( (math::equals(b0, a0) && math::equals(b1, a1))
|| (math::equals(b0, p0) && math::equals(b1, p1)) )
{
return 0;
}
bool const is_a_pole = math::equals(pi_half1, math::abs(a1));
bool const is_b_pole = math::equals(pi_half1, math::abs(b1));
bool const is_p_pole = math::equals(pi_half2, math::abs(p1));
if ( is_b_pole && ((is_a_pole && math::sign(b1) == math::sign(a1))
|| (is_p_pole && math::sign(b1) == math::sign(p1))) )
{
return 0;
}
// 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, 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<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 :
(std::min)(is_antilon1 ? c0 : math::abs(dlon1),
is_antilon2 ? c0 : math::abs(dlon2));
calc_t my = (std::min)(math::abs(dlat1),
math::abs(dlat2));
int s1 = 0, s2 = 0;
if (mx >= my)
{
s1 = dlon1 > 0 ? 1 : -1;
s2 = dlon2 > 0 ? 1 : -1;
}
else
{
s1 = dlat1 > 0 ? 1 : -1;
s2 = dlat2 > 0 ? 1 : -1;
}
return s1 == s2 ? -1 : 1;
}
template <typename Units, typename T>
static inline T latitude_distance_signed(T const& lat1, T const& lat2, T const& lon_ds, bool & is_antilon)
{
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;
is_antilon = math::equals(math::abs(lon_ds), pi);
if (is_antilon)
{
res = lat2 + lat1;
if (res >= c0)
res = pi - res;
else
res = -pi - res;
}
return res;
}
};
template <typename Point>
struct direction_code_impl<Point, spherical_polar_tag>
{
template <typename Point1, typename Point2>
static inline int apply(Point1 segment_a, Point1 segment_b,
Point2 p)
{
typedef math::detail::constants_on_spheroid
<
typename coordinate_type<Point1>::type,
typename coordinate_system<Point1>::type::units
> constants1;
typedef math::detail::constants_on_spheroid
<
typename coordinate_type<Point2>::type,
typename coordinate_system<Point2>::type::units
> constants2;
geometry::set<1>(segment_a,
constants1::max_latitude() - geometry::get<1>(segment_a));
geometry::set<1>(segment_b,
constants1::max_latitude() - geometry::get<1>(segment_b));
geometry::set<1>(p,
constants2::max_latitude() - geometry::get<1>(p));
return direction_code_impl
<
Point, spherical_equatorial_tag
>::apply(segment_a, segment_b, p);
}
};
template <typename Point>
struct direction_code_impl<Point, geographic_tag>
: direction_code_impl<Point, spherical_equatorial_tag>
{};
// Gives sense of direction for point p, collinear w.r.t. segment (a,b)
// Returns -1 if p goes backward w.r.t (a,b), so goes from b in direction of a
// Returns 1 if p goes forward, so extends (a,b)
@@ -44,28 +240,9 @@ inline int sign_of_difference(Point1 const& point1, Point2 const& point2)
// Note that it does not do any collinearity test, that should be done before
template <typename Point1, typename Point2>
inline int direction_code(Point1 const& segment_a, Point1 const& segment_b,
const Point2& p)
Point2 const& p)
{
// Suppose segment = (4 3,4 4) and p =(4 2)
// Then sign_a1 = 1 and sign_p1 = 1 -> goes backward -> return -1
int const sign_a0 = sign_of_difference<0>(segment_b, segment_a);
int const sign_a1 = sign_of_difference<1>(segment_b, segment_a);
if (sign_a0 == 0 && sign_a1 == 0)
{
return 0;
}
int const sign_p0 = sign_of_difference<0>(segment_b, p);
int const sign_p1 = sign_of_difference<1>(segment_b, p);
if (sign_p0 == 0 && sign_p1 == 0)
{
return 0;
}
return sign_a0 == sign_p0 && sign_a1 == sign_p1 ? -1 : 1;
return direction_code_impl<Point1>::apply(segment_a, segment_b, p);
}
@@ -73,7 +250,6 @@ inline int direction_code(Point1 const& segment_a, Point1 const& segment_b,
#endif //DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DIRECITON_CODE_HPP

View File

@@ -121,9 +121,18 @@ struct box_box<Box1, Box2, 0, DimensionCount, spherical_tag>
// calculate positive longitude translation with b1_min as origin
calc_t const diff_min = math::longitude_distance_unsigned<units_t>(b1_min, b2_min);
calc_t const b2_min_transl = b1_min + diff_min; // always right of b1_min
calc_t b2_max_transl = b2_min_transl - constants::period() + diff2;
if (b2_min_transl > b1_max // b2_min right of b1_max
&& b2_min_transl - constants::period() + diff2 < b1_min) // b2_max left of b1_min
// if the translation is too close then use the original point
// note that math::abs(b2_max_transl - b2_max) takes values very
// close to k*2*constants::period() for k=0,1,2,...
if (math::abs(b2_max_transl - b2_max) < constants::period() / 2)
{
b2_max_transl = b2_max;
}
if (b2_min_transl > b1_max // b2_min right of b1_max
&& b2_max_transl < b1_min) // b2_max left of b1_min
{
return true;
}

View File

@@ -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
<

View File

@@ -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
<

View File

@@ -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,12 +147,18 @@ 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

View File

@@ -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);
}

View File

@@ -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,12 +103,18 @@ 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

View File

@@ -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;

View File

@@ -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
{
@@ -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);
}
};

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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
>
{};

View File

@@ -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

View File

@@ -5,6 +5,11 @@
// Copyright (c) 2009-2013 Mateusz Loskot, London, UK.
// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
// 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)
@@ -117,12 +122,6 @@ struct extreme_points_on_ring
typedef typename boost::range_iterator<Ring const>::type range_iterator;
typedef typename geometry::point_type<Ring>::type point_type;
typedef typename geometry::strategy::side::services::default_strategy
<
typename geometry::cs_tag<point_type>::type
>::type side_strategy;
template <typename CirclingIterator, typename Points>
static inline bool extend(CirclingIterator& it,
std::size_t n,
@@ -214,10 +213,11 @@ struct extreme_points_on_ring
return true;
}
template <typename Extremes, typename Intruders, typename CirclingIterator>
template <typename Extremes, typename Intruders, typename CirclingIterator, typename SideStrategy>
static inline void get_intruders(Ring const& ring, CirclingIterator left, CirclingIterator right,
Extremes const& extremes,
Intruders& intruders)
Intruders& intruders,
SideStrategy const& strategy)
{
if (boost::size(extremes) < 3)
{
@@ -238,8 +238,8 @@ struct extreme_points_on_ring
if (coordinate > min_value && other_coordinate > other_min && other_coordinate < other_max)
{
int const factor = geometry::point_order<Ring>::value == geometry::clockwise ? 1 : -1;
int const first_side = side_strategy::apply(*right, extremes.front(), *(extremes.begin() + 1)) * factor;
int const last_side = side_strategy::apply(*right, *(extremes.rbegin() + 1), extremes.back()) * factor;
int const first_side = strategy.apply(*right, extremes.front(), *(extremes.begin() + 1)) * factor;
int const last_side = strategy.apply(*right, *(extremes.rbegin() + 1), extremes.back()) * factor;
// If not lying left from any of the extemes side
if (first_side != 1 && last_side != 1)
@@ -263,10 +263,11 @@ struct extreme_points_on_ring
}
}
template <typename Extremes, typename Intruders>
template <typename Extremes, typename Intruders, typename SideStrategy>
static inline void get_intruders(Ring const& ring,
Extremes const& extremes,
Intruders& intruders)
Intruders& intruders,
SideStrategy const& strategy)
{
std::size_t const n = boost::size(ring);
if (n >= 3)
@@ -275,12 +276,12 @@ struct extreme_points_on_ring
geometry::ever_circling_range_iterator<Ring const> right(ring);
++right;
get_intruders(ring, left, right, extremes, intruders);
get_intruders(ring, left, right, extremes, intruders, strategy);
}
}
template <typename Iterator>
static inline bool right_turn(Ring const& ring, Iterator it)
template <typename Iterator, typename SideStrategy>
static inline bool right_turn(Ring const& ring, Iterator it, SideStrategy const& strategy)
{
typename std::iterator_traits<Iterator>::difference_type const index
= std::distance(boost::begin(ring), it);
@@ -295,8 +296,8 @@ struct extreme_points_on_ring
}
int const factor = geometry::point_order<Ring>::value == geometry::clockwise ? 1 : -1;
int const first_side = side_strategy::apply(*(right - 1), *right, *left) * factor;
int const last_side = side_strategy::apply(*left, *(left + 1), *right) * factor;
int const first_side = strategy.apply(*(right - 1), *right, *left) * factor;
int const last_side = strategy.apply(*left, *(left + 1), *right) * factor;
//std::cout << "Candidate at " << geometry::wkt(*it) << " first=" << first_side << " last=" << last_side << std::endl;
@@ -306,8 +307,11 @@ struct extreme_points_on_ring
// Gets the extreme segments (top point plus neighbouring points), plus intruders, if any, on the same ring
template <typename Extremes, typename Intruders>
static inline bool apply(Ring const& ring, Extremes& extremes, Intruders& intruders)
template <typename Extremes, typename Intruders, typename SideStrategy>
static inline bool apply(Ring const& ring,
Extremes& extremes,
Intruders& intruders,
SideStrategy const& strategy)
{
std::size_t const n = boost::size(ring);
if (n < 3)
@@ -321,7 +325,7 @@ struct extreme_points_on_ring
compare<Dimension> smaller;
for (range_iterator it = max_it + 1; it != boost::end(ring); ++it)
{
if (smaller(*max_it, *it) && right_turn(ring, it))
if (smaller(*max_it, *it) && right_turn(ring, it, strategy))
{
max_it = it;
}
@@ -365,7 +369,7 @@ struct extreme_points_on_ring
std::copy(points.begin(), points.end(), std::back_inserter(extremes));
get_intruders(ring, left, right, extremes, intruders);
get_intruders(ring, left, right, extremes, intruders, strategy);
return true;
}
@@ -403,8 +407,9 @@ struct extreme_points<Ring, Dimension, ring_tag>
template<typename Polygon, std::size_t Dimension>
struct extreme_points<Polygon, Dimension, polygon_tag>
{
template <typename Extremes, typename Intruders>
static inline bool apply(Polygon const& polygon, Extremes& extremes, Intruders& intruders)
template <typename Extremes, typename Intruders, typename SideStrategy>
static inline bool apply(Polygon const& polygon, Extremes& extremes, Intruders& intruders,
SideStrategy const& strategy)
{
typedef typename geometry::ring_type<Polygon>::type ring_type;
typedef detail::extreme_points::extreme_points_on_ring
@@ -412,7 +417,8 @@ struct extreme_points<Polygon, Dimension, polygon_tag>
ring_type, Dimension
> ring_implementation;
if (! ring_implementation::apply(geometry::exterior_ring(polygon), extremes, intruders))
if (! ring_implementation::apply(geometry::exterior_ring(polygon),
extremes, intruders, strategy))
{
return false;
}
@@ -423,7 +429,7 @@ struct extreme_points<Polygon, Dimension, polygon_tag>
for (typename detail::interior_iterator<Polygon const>::type
it = boost::begin(rings); it != boost::end(rings); ++it)
{
ring_implementation::get_intruders(*it, extremes, intruders);
ring_implementation::get_intruders(*it, extremes, intruders, strategy);
}
return true;
@@ -433,8 +439,9 @@ struct extreme_points<Polygon, Dimension, polygon_tag>
template<typename Box>
struct extreme_points<Box, 1, box_tag>
{
template <typename Extremes, typename Intruders>
static inline bool apply(Box const& box, Extremes& extremes, Intruders& )
template <typename Extremes, typename Intruders, typename SideStrategy>
static inline bool apply(Box const& box, Extremes& extremes, Intruders& ,
SideStrategy const& )
{
extremes.resize(4);
geometry::detail::assign_box_corners_oriented<false>(box, extremes);
@@ -446,8 +453,9 @@ struct extreme_points<Box, 1, box_tag>
template<typename Box>
struct extreme_points<Box, 0, box_tag>
{
template <typename Extremes, typename Intruders>
static inline bool apply(Box const& box, Extremes& extremes, Intruders& )
template <typename Extremes, typename Intruders, typename SideStrategy>
static inline bool apply(Box const& box, Extremes& extremes, Intruders& ,
SideStrategy const& )
{
extremes.resize(4);
geometry::detail::assign_box_corners_oriented<false>(box, extremes);
@@ -460,8 +468,9 @@ struct extreme_points<Box, 0, box_tag>
template<typename MultiPolygon, std::size_t Dimension>
struct extreme_points<MultiPolygon, Dimension, multi_polygon_tag>
{
template <typename Extremes, typename Intruders>
static inline bool apply(MultiPolygon const& multi, Extremes& extremes, Intruders& intruders)
template <typename Extremes, typename Intruders, typename SideStrategy>
static inline bool apply(MultiPolygon const& multi, Extremes& extremes,
Intruders& intruders, SideStrategy const& strategy)
{
// Get one for the very first polygon, that is (for the moment) enough.
// It is not guaranteed the "extreme" then, but for the current purpose
@@ -473,7 +482,7 @@ struct extreme_points<MultiPolygon, Dimension, multi_polygon_tag>
typename boost::range_value<MultiPolygon const>::type,
Dimension,
polygon_tag
>::apply(*boost::begin(multi), extremes, intruders);
>::apply(*boost::begin(multi), extremes, intruders, strategy);
}
return false;
@@ -489,8 +498,18 @@ struct extreme_points<MultiPolygon, Dimension, multi_polygon_tag>
for Edge=0 in dimension 0, the right side)
\note We could specify a strategy (less/greater) to get bottom/left side too. However, until now we don't need that.
*/
template <std::size_t Edge, typename Geometry, typename Extremes, typename Intruders>
inline bool extreme_points(Geometry const& geometry, Extremes& extremes, Intruders& intruders)
template
<
std::size_t Edge,
typename Geometry,
typename Extremes,
typename Intruders,
typename SideStrategy
>
inline bool extreme_points(Geometry const& geometry,
Extremes& extremes,
Intruders& intruders,
SideStrategy const& strategy)
{
concepts::check<Geometry const>();
@@ -509,7 +528,11 @@ inline bool extreme_points(Geometry const& geometry, Extremes& extremes, Intrude
const
>();
return dispatch::extreme_points<Geometry, Edge>::apply(geometry, extremes, intruders);
return dispatch::extreme_points
<
Geometry,
Edge
>::apply(geometry, extremes, intruders, strategy);
}

View File

@@ -2,6 +2,11 @@
// Copyright (c) 2012-2014 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)
@@ -60,17 +65,14 @@ inline int squared_length(Vector const& vector)
}
template <typename Point>
template <typename Point, typename SideStrategy>
struct angle_less
{
typedef Point vector_type;
typedef typename strategy::side::services::default_strategy
<
typename cs_tag<Point>::type
>::type side_strategy_type;
angle_less(Point const& origin)
angle_less(Point const& origin, SideStrategy const& strategy)
: m_origin(origin)
, m_strategy(strategy)
{}
template <typename Angle>
@@ -89,8 +91,7 @@ struct angle_less
return quadrant_p < quadrant_q;
}
// Same quadrant, check if p is located left of q
int const side = side_strategy_type::apply(m_origin, q.point,
p.point);
int const side = m_strategy.apply(m_origin, q.point, p.point);
if (side != 0)
{
return side == 1;
@@ -114,19 +115,17 @@ struct angle_less
private:
Point m_origin;
SideStrategy m_strategy;
};
template <typename Point>
template <typename Point, typename SideStrategy>
struct angle_equal_to
{
typedef Point vector_type;
typedef typename strategy::side::services::default_strategy
<
typename cs_tag<Point>::type
>::type side_strategy_type;
inline angle_equal_to(Point const& origin)
inline angle_equal_to(Point const& origin, SideStrategy const& strategy)
: m_origin(origin)
, m_strategy(strategy)
{}
template <typename Angle>
@@ -143,13 +142,13 @@ struct angle_equal_to
return false;
}
// Same quadrant, check if p/q are collinear
int const side = side_strategy_type::apply(m_origin, q.point,
p.point);
int const side = m_strategy.apply(m_origin, q.point, p.point);
return side == 0;
}
private:
Point m_origin;
SideStrategy m_strategy;
};
template <typename AngleCollection, typename Turns>
@@ -193,13 +192,14 @@ inline void get_left_turns(AngleCollection const& sorted_angles,
//! Returns the number of clusters
template <typename Point, typename AngleCollection>
inline std::size_t assign_cluster_indices(AngleCollection& sorted, Point const& origin)
template <typename Point, typename AngleCollection, typename SideStrategy>
inline std::size_t assign_cluster_indices(AngleCollection& sorted, Point const& origin,
SideStrategy const& strategy)
{
// Assign same cluster_index for all turns in same direction
BOOST_GEOMETRY_ASSERT(boost::size(sorted) >= 4u);
angle_equal_to<Point> comparator(origin);
angle_equal_to<Point, SideStrategy> comparator(origin, strategy);
typename boost::range_iterator<AngleCollection>::type it = sorted.begin();
std::size_t cluster_index = 0;

View File

@@ -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;

View File

@@ -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,

View File

@@ -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;
}
};

View File

@@ -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);
@@ -236,7 +237,9 @@ inline bool has_self_intersections(Linear const& linear, Strategy const& strateg
template <typename Linestring, bool CheckSelfIntersections = true>
struct is_simple_linestring
{
static inline bool apply(Linestring const& linestring)
template <typename Strategy>
static inline bool apply(Linestring const& linestring,
Strategy const& strategy)
{
simplicity_failure_policy policy;
return ! boost::empty(linestring)
@@ -247,7 +250,7 @@ struct is_simple_linestring
&& ! detail::is_valid::has_spikes
<
Linestring, closed
>::apply(linestring, policy);
>::apply(linestring, policy, strategy.get_side_strategy());
}
};
@@ -258,7 +261,10 @@ struct is_simple_linestring<Linestring, true>
static inline bool apply(Linestring const& linestring,
Strategy const& strategy)
{
return is_simple_linestring<Linestring, false>::apply(linestring)
return is_simple_linestring
<
Linestring, false
>::apply(linestring, strategy)
&& ! has_self_intersections(linestring, strategy);
}
};
@@ -267,23 +273,44 @@ struct is_simple_linestring<Linestring, true>
template <typename MultiLinestring>
struct is_simple_multilinestring
{
private:
template <typename Strategy>
struct per_linestring
{
per_linestring(Strategy const& strategy)
: m_strategy(strategy)
{}
template <typename Linestring>
inline bool apply(Linestring const& linestring) const
{
return detail::is_simple::is_simple_linestring
<
Linestring,
false // do not compute self-intersections
>::apply(linestring, m_strategy);
}
Strategy const& m_strategy;
};
public:
template <typename Strategy>
static inline bool apply(MultiLinestring const& multilinestring,
Strategy const& strategy)
{
typedef per_linestring<Strategy> per_ls;
// check each of the linestrings for simplicity
// but do not compute self-intersections yet; these will be
// computed for the entire multilinestring
if ( ! detail::check_iterator_range
<
is_simple_linestring
<
typename boost::range_value<MultiLinestring>::type,
false // do not compute self-intersections
>,
per_ls, // do not compute self-intersections
true // allow empty multilinestring
>::apply(boost::begin(multilinestring),
boost::end(multilinestring))
boost::end(multilinestring),
per_ls(strategy))
)
{
return false;

View File

@@ -1,8 +1,9 @@
// 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
@@ -91,8 +92,9 @@ struct has_spikes
return std::find_if(second, last, not_equal(*first));
}
template <typename VisitPolicy>
static inline bool apply(Range const& range, VisitPolicy& visitor)
template <typename VisitPolicy, typename SideStrategy>
static inline bool apply(Range const& range, VisitPolicy& visitor,
SideStrategy const& strategy)
{
boost::ignore_unused(visitor);
@@ -124,9 +126,8 @@ struct has_spikes
while (next != boost::end(view))
{
if ( geometry::detail::point_is_spike_or_equal(*prev,
*next,
*cur) )
if ( geometry::detail::point_is_spike_or_equal(*prev, *next, *cur,
strategy) )
{
return
! visitor.template apply<failure_spikes>(is_linear, *cur);
@@ -146,7 +147,7 @@ struct has_spikes
boost::rend(view));
iterator next = find_different_from_first(cur, boost::end(view));
if (detail::point_is_spike_or_equal(*prev, *next, *cur))
if (detail::point_is_spike_or_equal(*prev, *next, *cur, strategy))
{
return
! visitor.template apply<failure_spikes>(is_linear, *cur);

View File

@@ -125,34 +125,6 @@ private:
typedef typename boost::range_value<MultiPolygon>::type polygon;
typedef is_acceptable_turn<polygon> base;
template <typename Operation>
static inline
bool check_int_ext(Operation const& op1,
detail::overlay::operation_type optype1,
Operation const& op2,
detail::overlay::operation_type optype2)
{
// u/i is acceptable for touch of interior ring with another exterior ring
// (but only if there is a colocated uu-turn of its exterior, TODO)
return op1.seg_id.ring_index == -1
&& op2.seg_id.ring_index >= 0
&& op1.operation == optype1
&& op2.operation == optype2;
}
template <typename Operation>
static inline
bool check_int_int(Operation const& op1,
Operation const& op2,
detail::overlay::operation_type optype)
{
// i/i is acceptable for touching interior/interior rings
return op1.seg_id.ring_index >= 0
&& op2.seg_id.ring_index >= 0
&& op1.operation == optype
&& op2.operation == optype;
}
public:
template <typename Turn>
static inline bool apply(Turn const& turn)
@@ -172,26 +144,11 @@ public:
return true;
}
if (turn.method != method_touch)
{
return false;
}
operation_type const reverse_op
= op == operation_union
? operation_intersection
: operation_union;
if ( check_int_int(turn.operations[0], turn.operations[1], reverse_op)
|| check_int_ext(turn.operations[0], reverse_op,
turn.operations[1], op)
|| check_int_ext(turn.operations[1], reverse_op,
turn.operations[0], op))
{
return true;
}
return false;
// Turn is acceptable only in case of a touch(interior) and both lines
// (polygons) do not cross
return (turn.method == method_touch
|| turn.method == method_touch_interior)
&& turn.touch_only;
}
};

View File

@@ -43,9 +43,10 @@ namespace detail { namespace is_valid
template <typename Linestring>
struct is_valid_linestring
{
template <typename VisitPolicy>
template <typename VisitPolicy, typename Strategy>
static inline bool apply(Linestring const& linestring,
VisitPolicy& visitor)
VisitPolicy& visitor,
Strategy const& strategy)
{
if (has_invalid_coordinate<Linestring>::apply(linestring, visitor))
{
@@ -75,15 +76,12 @@ struct is_valid_linestring
{
return visitor.template apply<no_failure>();
}
return ! has_spikes<Linestring, closed>::apply(linestring, visitor);
}
template <typename VisitPolicy, typename Strategy>
static inline bool apply(Linestring const& linestring,
VisitPolicy& visitor,
Strategy const&)
{
return apply(linestring, visitor);
return ! has_spikes
<
Linestring, closed
>::apply(linestring, visitor,
strategy.get_side_strategy());
}
};
@@ -132,10 +130,13 @@ class is_valid
>
{
private:
template <typename VisitPolicy>
template <typename VisitPolicy, typename Strategy>
struct per_linestring
{
per_linestring(VisitPolicy& policy) : m_policy(policy) {}
per_linestring(VisitPolicy& policy, Strategy const& strategy)
: m_policy(policy)
, m_strategy(strategy)
{}
template <typename Linestring>
inline bool apply(Linestring const& linestring) const
@@ -143,17 +144,18 @@ private:
return detail::is_valid::is_valid_linestring
<
Linestring
>::apply(linestring, m_policy);
>::apply(linestring, m_policy, m_strategy);
}
VisitPolicy& m_policy;
Strategy const& m_strategy;
};
public:
template <typename VisitPolicy, typename Strategy>
static inline bool apply(MultiLinestring const& multilinestring,
VisitPolicy& visitor,
Strategy const&)
Strategy const& strategy)
{
if (BOOST_GEOMETRY_CONDITION(
AllowEmptyMultiGeometries && boost::empty(multilinestring)))
@@ -161,13 +163,15 @@ public:
return visitor.template apply<no_failure>();
}
typedef per_linestring<VisitPolicy, Strategy> per_ls;
return detail::check_iterator_range
<
per_linestring<VisitPolicy>,
per_ls,
false // do not check for empty multilinestring (done above)
>::apply(boost::begin(multilinestring),
boost::end(multilinestring),
per_linestring<VisitPolicy>(visitor));
per_ls(visitor, strategy));
}
};

View File

@@ -89,12 +89,15 @@ private:
{
boost::ignore_unused(visitor);
// collect all polygons that have turns
// collect all polygons that have crossing turns
std::set<signed_size_type> multi_indices;
for (TurnIterator tit = turns_first; tit != turns_beyond; ++tit)
{
multi_indices.insert(tit->operations[0].seg_id.multi_index);
multi_indices.insert(tit->operations[1].seg_id.multi_index);
if (! tit->touch_only)
{
multi_indices.insert(tit->operations[0].seg_id.multi_index);
multi_indices.insert(tit->operations[1].seg_id.multi_index);
}
}
typedef geometry::model::box<typename point_type<MultiPolygon>::type> box_type;

View File

@@ -45,6 +45,7 @@
#include <boost/geometry/algorithms/expand.hpp>
#include <boost/geometry/algorithms/num_interior_rings.hpp>
#include <boost/geometry/algorithms/validity_failure_type.hpp>
#include <boost/geometry/algorithms/detail/point_on_border.hpp>
#include <boost/geometry/algorithms/within.hpp>
#include <boost/geometry/algorithms/detail/check_iterator_range.hpp>
@@ -216,14 +217,26 @@ protected:
, m_strategy(strategy)
{}
template <typename Item>
inline bool is_within(Item const& first, Item const& second)
{
typename point_type<Polygon>::type point;
typedef detail::point_on_border::point_on_range<true> pob;
// TODO: this should check for a point on the interior, instead
// of on border. Or it should check using the overlap function.
return pob::apply(point, points_begin(first), points_end(first))
&& geometry::within(point, second, m_strategy);
}
template <typename Iterator, typename Box>
inline bool apply(partition_item<Iterator, Box> const& item1,
partition_item<Iterator, Box> const& item2)
{
if (! items_overlap
&& (geometry::within(*points_begin(*item1.get()), *item2.get(), m_strategy)
|| geometry::within(*points_begin(*item2.get()), *item1.get(), m_strategy))
)
&& (is_within(*item1.get(), *item2.get())
|| is_within(*item2.get(), *item1.get())))
{
items_overlap = true;
return false; // interrupt

View File

@@ -115,7 +115,10 @@ struct is_properly_oriented
geometry::closure<Ring>::value
> ring_area_type;
typedef typename default_area_result<Ring>::type area_result_type;
typedef typename Strategy::template area_strategy
<
point_type
>::type::return_type area_result_type;
typename ring_area_predicate
<
@@ -195,7 +198,7 @@ struct is_valid_ring
return
is_topologically_closed<Ring, closure>::apply(ring, visitor)
&& ! has_duplicates<Ring, closure>::apply(ring, visitor)
&& ! has_spikes<Ring, closure>::apply(ring, visitor)
&& ! has_spikes<Ring, closure>::apply(ring, visitor, strategy.get_side_strategy())
&& (! CheckSelfIntersections
|| has_valid_self_turns<Ring>::apply(ring, visitor, strategy))
&& is_properly_oriented<Ring, IsInteriorRing>::apply(ring, visitor, strategy);

View File

@@ -4,6 +4,10 @@
// 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.
@@ -40,6 +44,18 @@ struct multi_modify
Policy::apply(*it);
}
}
template <typename Strategy>
static inline void apply(MultiGeometry& multi, Strategy const& strategy)
{
typedef typename boost::range_iterator<MultiGeometry>::type iterator_type;
for (iterator_type it = boost::begin(multi);
it != boost::end(multi);
++it)
{
Policy::apply(*it, strategy);
}
}
};

View File

@@ -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);
@@ -234,6 +237,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
<
@@ -251,6 +263,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
<

View File

@@ -2,6 +2,11 @@
// Copyright (c) 2012-2014 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)
@@ -99,12 +104,18 @@ public :
}
}
template <typename RobustPoint, typename Turns>
inline void get_left_turns(RobustPoint const& origin, Turns& turns)
template <typename RobustPoint, typename Turns, typename SideStrategy>
inline void get_left_turns(RobustPoint const& origin, Turns& turns,
SideStrategy const& strategy)
{
typedef detail::left_turns::angle_less
<
typename AngleInfo::point_type,
SideStrategy
> angle_less;
// Sort on angle
std::sort(m_angles.begin(), m_angles.end(),
detail::left_turns::angle_less<typename AngleInfo::point_type>(origin));
std::sort(m_angles.begin(), m_angles.end(), angle_less(origin, strategy));
// Group same-angled elements
std::size_t cluster_size = detail::left_turns::assign_cluster_indices(m_angles, origin);

View File

@@ -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;

View File

@@ -2,8 +2,8 @@
// 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 Adam Wulkiewicz, on behalf of Oracle
@@ -63,8 +63,9 @@ inline bool points_equal_or_close(Point1 const& point1,
}
template <typename Range, typename Point, typename RobustPolicy>
template <typename Range, typename Point, typename SideStrategy, typename RobustPolicy>
inline void append_no_dups_or_spikes(Range& range, Point const& point,
SideStrategy const& strategy,
RobustPolicy const& robust_policy)
{
#ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION
@@ -92,6 +93,7 @@ inline void append_no_dups_or_spikes(Range& range, Point const& point,
&& point_is_spike_or_equal(point,
*(boost::end(range) - 3),
*(boost::end(range) - 2),
strategy,
robust_policy))
{
// Use the Concept/traits, so resize and append again
@@ -100,8 +102,9 @@ inline void append_no_dups_or_spikes(Range& range, Point const& point,
}
}
template <typename Range, typename RobustPolicy>
template <typename Range, typename SideStrategy, typename RobustPolicy>
inline void clean_closing_dups_and_spikes(Range& range,
SideStrategy const& strategy,
RobustPolicy const& robust_policy)
{
std::size_t const minsize
@@ -135,7 +138,7 @@ inline void clean_closing_dups_and_spikes(Range& range,
// Check if closing point is a spike (this is so if the second point is
// considered as a spike w.r.t. the last segment)
if (point_is_spike_or_equal(*second, *ultimate, *first, robust_policy))
if (point_is_spike_or_equal(*second, *ultimate, *first, strategy, robust_policy))
{
range::erase(range, first);
if (BOOST_GEOMETRY_CONDITION(closed))

View File

@@ -107,21 +107,19 @@ static inline bool within_selected_input(Item const& item2,
}
template <typename Point>
template <typename Point, typename AreaType>
struct ring_info_helper
{
typedef typename geometry::default_area_result<Point>::type area_type;
ring_identifier id;
area_type real_area;
area_type abs_area;
AreaType real_area;
AreaType abs_area;
model::box<Point> envelope;
inline ring_info_helper()
: real_area(0), abs_area(0)
{}
inline ring_info_helper(ring_identifier i, area_type a)
inline ring_info_helper(ring_identifier i, AreaType const& a)
: id(i), real_area(a), abs_area(geometry::math::abs(a))
{}
};
@@ -226,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;
@@ -234,11 +233,15 @@ inline void assign_parents(Geometry1 const& geometry1,
typedef typename RingMap::mapped_type ring_info_type;
typedef typename ring_info_type::point_type point_type;
typedef model::box<point_type> box_type;
typedef typename Strategy::template area_strategy
<
point_type
>::type::return_type area_result_type;
typedef typename RingMap::iterator map_iterator_type;
{
typedef ring_info_helper<point_type> helper;
typedef ring_info_helper<point_type, area_result_type> helper;
typedef std::vector<helper> vector_type;
typedef typename boost::range_iterator<vector_type const>::type vector_iterator_type;
@@ -332,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;
}
}
}
@@ -370,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,
@@ -382,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);
}

View File

@@ -2,8 +2,8 @@
// 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 Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -57,12 +57,14 @@ struct copy_segments_ring
<
typename Ring,
typename SegmentIdentifier,
typename SideStrategy,
typename RobustPolicy,
typename RangeOut
>
static inline void apply(Ring const& ring,
SegmentIdentifier const& seg_id,
signed_size_type to_index,
SideStrategy const& strategy,
RobustPolicy const& robust_policy,
RangeOut& current_output)
{
@@ -109,7 +111,7 @@ struct copy_segments_ring
for (signed_size_type i = 0; i < count; ++i, ++it)
{
detail::overlay::append_no_dups_or_spikes(current_output, *it, robust_policy);
detail::overlay::append_no_dups_or_spikes(current_output, *it, strategy, robust_policy);
}
}
};
@@ -119,20 +121,23 @@ class copy_segments_linestring
{
private:
// remove spikes
template <typename RangeOut, typename Point, typename RobustPolicy>
template <typename RangeOut, typename Point, typename SideStrategy, typename RobustPolicy>
static inline void append_to_output(RangeOut& current_output,
Point const& point,
SideStrategy const& strategy,
RobustPolicy const& robust_policy,
boost::true_type const&)
{
detail::overlay::append_no_dups_or_spikes(current_output, point,
strategy,
robust_policy);
}
// keep spikes
template <typename RangeOut, typename Point, typename RobustPolicy>
template <typename RangeOut, typename Point, typename SideStrategy, typename RobustPolicy>
static inline void append_to_output(RangeOut& current_output,
Point const& point,
SideStrategy const&,
RobustPolicy const&,
boost::false_type const&)
{
@@ -144,12 +149,14 @@ public:
<
typename LineString,
typename SegmentIdentifier,
typename SideStrategy,
typename RobustPolicy,
typename RangeOut
>
static inline void apply(LineString const& ls,
SegmentIdentifier const& seg_id,
signed_size_type to_index,
SideStrategy const& strategy,
RobustPolicy const& robust_policy,
RangeOut& current_output)
{
@@ -170,7 +177,7 @@ public:
for (signed_size_type i = 0; i < count; ++i, ++it)
{
append_to_output(current_output, *it, robust_policy,
append_to_output(current_output, *it, strategy, robust_policy,
boost::integral_constant<bool, RemoveSpikes>());
}
}
@@ -183,12 +190,14 @@ struct copy_segments_polygon
<
typename Polygon,
typename SegmentIdentifier,
typename SideStrategy,
typename RobustPolicy,
typename RangeOut
>
static inline void apply(Polygon const& polygon,
SegmentIdentifier const& seg_id,
signed_size_type to_index,
SideStrategy const& strategy,
RobustPolicy const& robust_policy,
RangeOut& current_output)
{
@@ -199,6 +208,7 @@ struct copy_segments_polygon
? geometry::exterior_ring(polygon)
: range::at(geometry::interior_rings(polygon), seg_id.ring_index),
seg_id, to_index,
strategy,
robust_policy,
current_output
);
@@ -213,12 +223,14 @@ struct copy_segments_box
<
typename Box,
typename SegmentIdentifier,
typename SideStrategy,
typename RobustPolicy,
typename RangeOut
>
static inline void apply(Box const& box,
SegmentIdentifier const& seg_id,
signed_size_type to_index,
SideStrategy const& strategy,
RobustPolicy const& robust_policy,
RangeOut& current_output)
{
@@ -239,7 +251,7 @@ struct copy_segments_box
for (signed_size_type i = 0; i < count; i++, index++)
{
detail::overlay::append_no_dups_or_spikes(current_output,
bp[index % 5], robust_policy);
bp[index % 5], strategy, robust_policy);
}
}
@@ -253,12 +265,14 @@ struct copy_segments_multi
<
typename MultiGeometry,
typename SegmentIdentifier,
typename SideStrategy,
typename RobustPolicy,
typename RangeOut
>
static inline void apply(MultiGeometry const& multi_geometry,
SegmentIdentifier const& seg_id,
signed_size_type to_index,
SideStrategy const& strategy,
RobustPolicy const& robust_policy,
RangeOut& current_output)
{
@@ -272,6 +286,7 @@ struct copy_segments_multi
// Call the single-version
Policy::apply(range::at(multi_geometry, seg_id.multi_index),
seg_id, to_index,
strategy,
robust_policy,
current_output);
}
@@ -341,12 +356,14 @@ template
bool Reverse,
typename Geometry,
typename SegmentIdentifier,
typename SideStrategy,
typename RobustPolicy,
typename RangeOut
>
inline void copy_segments(Geometry const& geometry,
SegmentIdentifier const& seg_id,
signed_size_type to_index,
SideStrategy const& strategy,
RobustPolicy const& robust_policy,
RangeOut& range_out)
{
@@ -356,7 +373,7 @@ inline void copy_segments(Geometry const& geometry,
<
typename tag<Geometry>::type,
Reverse
>::apply(geometry, seg_id, to_index, robust_policy, range_out);
>::apply(geometry, seg_id, to_index, strategy, robust_policy, range_out);
}

View File

@@ -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)
@@ -59,7 +64,7 @@ template
typename Turns,
typename Geometry1, typename Geometry2,
typename RobustPolicy,
typename Strategy
typename SideStrategy
>
inline void enrich_sort(Operations& operations,
Turns const& turns,
@@ -67,7 +72,7 @@ inline void enrich_sort(Operations& operations,
Geometry1 const& geometry1,
Geometry2 const& geometry2,
RobustPolicy const& robust_policy,
Strategy const& /*strategy*/)
SideStrategy const& strategy)
{
std::sort(boost::begin(operations),
boost::end(operations),
@@ -77,8 +82,9 @@ inline void enrich_sort(Operations& operations,
typename boost::range_value<Operations>::type,
Geometry1, Geometry2,
RobustPolicy,
SideStrategy,
Reverse1, Reverse2
>(turns, for_operation, geometry1, geometry2, robust_policy));
>(turns, for_operation, geometry1, geometry2, robust_policy, strategy));
}
@@ -112,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)
@@ -239,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];
@@ -255,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)
{
@@ -279,7 +281,7 @@ inline void calculate_remaining_distance(Turns& turns)
\tparam Clusters type of cluster container
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\tparam Strategy side strategy type
\tparam SideStrategy side strategy type
\param turns container containing intersection points
\param clusters container containing clusters
\param geometry1 \param_geometry
@@ -295,13 +297,13 @@ template
typename Clusters,
typename Geometry1, typename Geometry2,
typename RobustPolicy,
typename Strategy
typename SideStrategy
>
inline void enrich_intersection_points(Turns& turns,
Clusters& clusters,
Geometry1 const& geometry1, Geometry2 const& geometry2,
RobustPolicy const& robust_policy,
Strategy const& strategy)
SideStrategy const& strategy)
{
static const detail::overlay::operation_type target_operation
= detail::overlay::operation_from_overlay<OverlayType>::value;
@@ -353,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;
}
@@ -373,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
@@ -415,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
@@ -424,7 +428,8 @@ inline void enrich_intersection_points(Turns& turns,
Reverse1,
Reverse2,
OverlayType
>(clusters, turns, target_operation, geometry1, geometry2);
>(clusters, turns, target_operation,
geometry1, geometry2, strategy);
detail::overlay::cleanup_clusters(turns, clusters);
}

View File

@@ -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
@@ -157,6 +158,7 @@ struct action_selector<overlay_intersection, RemoveSpikes>
typename LineString,
typename Point,
typename Operation,
typename SideStrategy,
typename RobustPolicy
>
static inline void enter(LineStringOut& current_piece,
@@ -164,6 +166,7 @@ struct action_selector<overlay_intersection, RemoveSpikes>
segment_identifier& segment_id,
signed_size_type , Point const& point,
Operation const& operation,
SideStrategy const& ,
RobustPolicy const& ,
OutputIterator& )
{
@@ -180,6 +183,7 @@ struct action_selector<overlay_intersection, RemoveSpikes>
typename LineString,
typename Point,
typename Operation,
typename SideStrategy,
typename RobustPolicy
>
static inline void leave(LineStringOut& current_piece,
@@ -187,6 +191,7 @@ struct action_selector<overlay_intersection, RemoveSpikes>
segment_identifier& segment_id,
signed_size_type index, Point const& point,
Operation const& ,
SideStrategy const& strategy,
RobustPolicy const& robust_policy,
OutputIterator& out)
{
@@ -195,7 +200,7 @@ struct action_selector<overlay_intersection, RemoveSpikes>
detail::copy_segments::copy_segments_linestring
<
false, RemoveSpikes
>::apply(linestring, segment_id, index, robust_policy, current_piece);
>::apply(linestring, segment_id, index, strategy, robust_policy, current_piece);
detail::overlay::append_no_duplicates(current_piece, point);
if (::boost::size(current_piece) > 1)
{
@@ -254,6 +259,7 @@ struct action_selector<overlay_difference, RemoveSpikes>
typename LineString,
typename Point,
typename Operation,
typename SideStrategy,
typename RobustPolicy
>
static inline void enter(LineStringOut& current_piece,
@@ -261,11 +267,12 @@ struct action_selector<overlay_difference, RemoveSpikes>
segment_identifier& segment_id,
signed_size_type index, Point const& point,
Operation const& operation,
SideStrategy const& strategy,
RobustPolicy const& robust_policy,
OutputIterator& out)
{
normal_action::leave(current_piece, linestring, segment_id, index,
point, operation, robust_policy, out);
point, operation, strategy, robust_policy, out);
}
template
@@ -275,6 +282,7 @@ struct action_selector<overlay_difference, RemoveSpikes>
typename LineString,
typename Point,
typename Operation,
typename SideStrategy,
typename RobustPolicy
>
static inline void leave(LineStringOut& current_piece,
@@ -282,11 +290,12 @@ struct action_selector<overlay_difference, RemoveSpikes>
segment_identifier& segment_id,
signed_size_type index, Point const& point,
Operation const& operation,
SideStrategy const& strategy,
RobustPolicy const& robust_policy,
OutputIterator& out)
{
normal_action::enter(current_piece, linestring, segment_id, index,
point, operation, robust_policy, out);
point, operation, strategy, robust_policy, out);
}
template
@@ -335,6 +344,7 @@ template
class follow
{
#ifdef BOOST_GEOMETRY_SETOPS_LA_OLD_BEHAVIOR
template <typename Turn>
struct sort_on_segment
{
@@ -381,7 +391,7 @@ class follow
}
};
#endif // BOOST_GEOMETRY_SETOPS_LA_OLD_BEHAVIOR
public :
@@ -425,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);
@@ -456,7 +474,7 @@ public :
entered = true;
action::enter(current_piece, linestring, current_segment_id,
iit->seg_id.segment_index, it->point, *iit,
robust_policy,
strategy, robust_policy,
out);
}
else if (following::is_leaving(*it, *iit, entered, first, linestring, polygon, pt_in_poly_strategy))
@@ -466,7 +484,7 @@ public :
entered = false;
action::leave(current_piece, linestring, current_segment_id,
iit->seg_id.segment_index, it->point, *iit,
robust_policy,
strategy, robust_policy,
out);
}
first = false;
@@ -480,7 +498,7 @@ public :
>::apply(linestring,
current_segment_id,
static_cast<signed_size_type>(boost::size(linestring) - 1),
robust_policy,
strategy, robust_policy,
current_piece);
}

View File

@@ -2,12 +2,14 @@
// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
// 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_FOLLOW_LINEAR_LINEAR_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_LINEAR_LINEAR_HPP
@@ -183,7 +185,8 @@ protected:
typename TurnIterator,
typename TurnOperationIterator,
typename SegmentIdentifier,
typename OutputIterator
typename OutputIterator,
typename SideStrategy
>
static inline OutputIterator
process_turn(TurnIterator it,
@@ -193,7 +196,8 @@ protected:
Linestring const& linestring,
LinestringOut& current_piece,
SegmentIdentifier& current_segment_id,
OutputIterator oit)
OutputIterator oit,
SideStrategy const& strategy)
{
// We don't rescale linear/linear
detail::no_rescale_policy robust_policy;
@@ -208,7 +212,7 @@ protected:
action::enter(current_piece, linestring,
current_segment_id,
op_it->seg_id.segment_index,
it->point, *op_it, robust_policy, oit);
it->point, *op_it, strategy, robust_policy, oit);
}
++enter_count;
}
@@ -223,7 +227,7 @@ protected:
action::leave(current_piece, linestring,
current_segment_id,
op_it->seg_id.segment_index,
it->point, *op_it, robust_policy, oit);
it->point, *op_it, strategy, robust_policy, oit);
}
}
else if ( FollowIsolatedPoints
@@ -249,14 +253,16 @@ protected:
template
<
typename SegmentIdentifier,
typename OutputIterator
typename OutputIterator,
typename SideStrategy
>
static inline OutputIterator
process_end(bool entered,
Linestring const& linestring,
SegmentIdentifier const& current_segment_id,
LinestringOut& current_piece,
OutputIterator oit)
OutputIterator oit,
SideStrategy const& strategy)
{
if ( action::is_entered(entered) )
{
@@ -269,6 +275,7 @@ protected:
>::apply(linestring,
current_segment_id,
static_cast<signed_size_type>(boost::size(linestring) - 1),
strategy,
robust_policy,
current_piece);
}
@@ -283,11 +290,12 @@ protected:
}
public:
template <typename TurnIterator, typename OutputIterator>
template <typename TurnIterator, typename OutputIterator, typename SideStrategy>
static inline OutputIterator
apply(Linestring const& linestring, Linear const&,
TurnIterator first, TurnIterator beyond,
OutputIterator oit)
OutputIterator oit,
SideStrategy const& strategy)
{
// Iterate through all intersection points (they are
// ordered along the each line)
@@ -304,7 +312,8 @@ public:
entered, enter_count,
linestring,
current_piece, current_segment_id,
oit);
oit,
strategy);
}
#if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW)
@@ -318,7 +327,8 @@ public:
return process_end(entered, linestring,
current_segment_id, current_piece,
oit);
oit,
strategy);
}
};
@@ -413,11 +423,12 @@ protected:
};
public:
template <typename TurnIterator, typename OutputIterator>
template <typename TurnIterator, typename OutputIterator, typename SideStrategy>
static inline OutputIterator
apply(MultiLinestring const& multilinestring, Linear const& linear,
TurnIterator first, TurnIterator beyond,
OutputIterator oit)
OutputIterator oit,
SideStrategy const& strategy)
{
BOOST_GEOMETRY_ASSERT( first != beyond );
@@ -447,7 +458,7 @@ public:
has_other_multi_id(current_multi_id));
oit = Base::apply(*(ls_first + current_multi_id),
linear, per_ls_current, per_ls_next, oit);
linear, per_ls_current, per_ls_next, oit, strategy);
signed_size_type next_multi_id = -1;
linestring_iterator ls_next = ls_beyond;

View File

@@ -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)
@@ -31,20 +36,15 @@ namespace detail { namespace overlay
but we still need to know which comes first.
Therefore, it is useful that using sides we are able to discover this.
*/
template <typename Point1>
struct get_relative_order
{
typedef typename strategy::side::services::default_strategy
<
typename cs_tag<Point1>::type
>::type strategy;
template <typename Point>
template <typename Point, typename SideStrategy>
static inline int value_via_product(Point const& ti, Point const& tj,
Point const& ui, Point const& uj, int factor)
Point const& ui, Point const& uj, int factor,
SideStrategy const& strategy)
{
int const side_ti_u = strategy::apply(ti, tj, ui);
int const side_tj_u = strategy::apply(ti, tj, uj);
int const side_ti_u = strategy.apply(ti, tj, ui);
int const side_tj_u = strategy.apply(ti, tj, uj);
#ifdef BOOST_GEOMETRY_DEBUG_RELATIVE_ORDER
std::cout << (factor == 1 ? " r//s " : " s//r ")
@@ -57,13 +57,15 @@ struct get_relative_order
}
template <typename Point1, typename SideStrategy>
static inline int apply(
Point1 const& pi, Point1 const& pj,
Point1 const& ri, Point1 const& rj,
Point1 const& si, Point1 const& sj)
Point1 const& si, Point1 const& sj,
SideStrategy const& strategy)
{
int const side_ri_p = strategy::apply(pi, pj, ri);
int const side_si_p = strategy::apply(pi, pj, si);
int const side_ri_p = strategy.apply(pi, pj, ri);
int const side_si_p = strategy.apply(pi, pj, si);
#ifdef BOOST_GEOMETRY_DEBUG_RELATIVE_ORDER
int const side_rj_p = strategy::apply(pi, pj, rj);
@@ -72,10 +74,10 @@ struct get_relative_order
std::cout << " s//p: " << side_si_p << " / " << side_sj_p;
#endif
int value = value_via_product(si, sj, ri, rj, 1);
int value = value_via_product(si, sj, ri, rj, 1, strategy);
if (value == 0)
{
value = value_via_product(ri, rj, si, sj, -1);
value = value_via_product(ri, rj, si, sj, -1, strategy);
}
int const order = side_ri_p * side_ri_p * side_si_p * value;

View File

@@ -190,6 +190,7 @@ struct touch_interior : public base_turn_handler
// Q turns left on the right side of P (test "MR3")
// Both directions for "intersection"
both(ti, operation_intersection);
ti.touch_only = true;
}
else if (side_qi_p == 1 && side_qk_p == 1 && side_qk_q == -1)
{
@@ -197,6 +198,7 @@ struct touch_interior : public base_turn_handler
// Union: take both operation
// Intersection: skip
both(ti, operation_union);
ti.touch_only = true;
}
else if (side_qi_p == side_qk_p && side_qi_p == side_qk_q)
{
@@ -207,6 +209,7 @@ struct touch_interior : public base_turn_handler
unsigned int index = side_qk_q == 1 ? index_q : index_p;
ti.operations[index].operation = operation_union;
ti.operations[1 - index].operation = operation_intersection;
ti.touch_only = true;
}
else if (side_qk_p == 0)
{
@@ -346,6 +349,7 @@ struct touch : public base_turn_handler
if (side_pk_q2 == -side_qk_q)
{
ui_else_iu(! q_turns_left, ti);
ti.touch_only = true;
return;
}
@@ -358,6 +362,10 @@ struct touch : public base_turn_handler
{
ti.operations[1].operation = operation_blocked;
}
else
{
ti.touch_only = true;
}
//block_second(block_q, ti);
return;
}
@@ -373,6 +381,10 @@ struct touch : public base_turn_handler
: side_qi_p1 == 1 || side_qk_p1 == 1
? operation_union
: operation_intersection;
if (! block_q)
{
ti.touch_only = true;
}
return;
}
@@ -400,6 +412,7 @@ struct touch : public base_turn_handler
if (side_pk_q1 == side_qk_p1)
{
uu_else_ii(right_to_left, ti);
ti.touch_only = true;
return;
}
}
@@ -418,6 +431,7 @@ struct touch : public base_turn_handler
if (side_pk_q2 == side_qk_p1)
{
ui_else_iu(right_to_left, ti);
ti.touch_only = true;
return;
}
}

View File

@@ -66,7 +66,7 @@ struct side_calculator
Qj const& m_qj;
Qk const& m_qk;
SideStrategy const& m_side_strategy;
SideStrategy m_side_strategy;
};
template <typename Point1, typename Point2, typename RobustPolicy>

View File

@@ -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,
@@ -233,7 +228,7 @@ public :
// section 2: [--------------]
// section 1: |----|---|---|---|---|
for (prev1 = it1++, next1++;
it1 != end1 && ! detail::section::exceeding<0>(dir1, *prev1, sec2.bounding_box, robust_policy);
it1 != end1 && ! detail::section::exceeding<0>(dir1, *prev1, sec1.bounding_box, sec2.bounding_box, robust_policy);
++prev1, ++it1, ++index1, ++next1, ++ndi1)
{
ever_circling_iterator<range1_iterator> nd_next1(
@@ -251,25 +246,35 @@ public :
next2++;
for (prev2 = it2++, next2++;
it2 != end2 && ! detail::section::exceeding<0>(dir2, *prev2, sec1.bounding_box, robust_policy);
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)
// Sources and rings are the same
// Also skip if index1 < index2 to avoid getting all
// intersections twice (only do this on same source!)
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 = (skip_larger && index1 >= index2)
|| ndi2 == ndi1 + 1
|| neighbouring<Geometry1>(sec1, index1, index2)
;
// 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)
@@ -359,7 +364,7 @@ private :
// skips to the begin-point, we loose the index or have to recalculate it)
// So we mimic it here
template <typename Range, typename Section, typename Box, typename RobustPolicy>
static inline void get_start_point_iterator(Section & section,
static inline void get_start_point_iterator(Section const& section,
Range const& range,
typename boost::range_iterator<Range const>::type& it,
typename boost::range_iterator<Range const>::type& prev,
@@ -373,7 +378,7 @@ private :
// Mimic section-iterator:
// Skip to point such that section interects other box
prev = it++;
for(; it != end && detail::section::preceding<0>(dir, *it, other_bounding_box, robust_policy);
for(; it != end && detail::section::preceding<0>(dir, *it, section.bounding_box, other_bounding_box, robust_policy);
prev = it++, index++, ndi++)
{}
// Go back one step because we want to start completely preceding
@@ -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);

View File

@@ -2,6 +2,11 @@
// Copyright (c) 2015 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)
@@ -19,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>
@@ -176,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);
@@ -309,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;
@@ -498,6 +505,7 @@ inline void discard_interior_exterior_turns(Turns& turns, Clusters& clusters)
template
<
overlay_type OverlayType,
typename Turns,
typename Clusters
>
@@ -512,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))
if (turn.both(operation_from_overlay<OverlayType>::value))
{
has_ii = true;
}
if (turn.both(operation_union) || turn.combination(operation_union, operation_blocked))
{
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)
if (both_target)
{
turn.colocated_ii = true;
}
if (has_uu)
{
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
@@ -622,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();
@@ -635,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,
@@ -697,11 +738,13 @@ template
typename Turns,
typename Clusters,
typename Geometry1,
typename Geometry2
typename Geometry2,
typename SideStrategy
>
inline void gather_cluster_properties(Clusters& clusters, Turns& turns,
operation_type for_operation,
Geometry1 const& geometry1, Geometry2 const& geometry2)
Geometry1 const& geometry1, Geometry2 const& geometry2,
SideStrategy const& strategy)
{
typedef typename boost::range_value<Turns>::type turn_type;
typedef typename turn_type::point_type point_type;
@@ -711,7 +754,7 @@ inline void gather_cluster_properties(Clusters& clusters, Turns& turns,
// right side
typedef sort_by_side::side_sorter
<
Reverse1, Reverse2, OverlayType, point_type, std::less<int>
Reverse1, Reverse2, OverlayType, point_type, SideStrategy, std::less<int>
> sbs_type;
for (typename Clusters::iterator mit = clusters.begin();
@@ -724,7 +767,7 @@ inline void gather_cluster_properties(Clusters& clusters, Turns& turns,
continue;
}
sbs_type sbs;
sbs_type sbs(strategy);
point_type turn_point; // should be all the same for all turns in cluster
bool first = true;
@@ -751,7 +794,9 @@ 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
// 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];
@@ -773,6 +818,13 @@ inline void gather_cluster_properties(Clusters& clusters, Turns& turns,
op.enriched.rank = ranked.rank;
op.enriched.zone = ranked.zone;
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

View File

@@ -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
void apply(Turns& turns,
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, 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

View File

@@ -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)
{
: public detail::intersection::intersection_areal_areal_point
<
PointOut
>
{};
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;
}
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
// dispatch for difference/intersection of linear geometries
template
<
typename Geometry1, typename Geometry2, typename GeometryOut,
typename Linear1, typename Linear2, typename LineStringOut,
overlay_type OverlayType,
bool Reverse1, bool Reverse2, bool ReverseOut,
typename TagIn1, typename TagIn2
>
struct intersection_insert
<
Geometry1, Geometry2, GeometryOut,
OverlayType,
Reverse1, Reverse2, ReverseOut,
TagIn1, TagIn2, linestring_tag,
false, false, false
> : intersection_insert
<
Geometry1, Geometry2, GeometryOut,
OverlayType,
Reverse1, Reverse2, ReverseOut,
typename tag_cast<TagIn1, pointlike_tag, linear_tag>::type,
typename tag_cast<TagIn2, pointlike_tag, linear_tag>::type,
linestring_tag,
false, false, false
>
{};
// dispatch for difference/intersection of linear geometries
template
<
typename Linear1, typename Linear2, typename LineStringOut,
overlay_type OverlayType,
bool Reverse1, bool Reverse2, bool ReverseOut
>
struct intersection_insert
<
Linear1, Linear2, LineStringOut, OverlayType,
Reverse1, Reverse2, ReverseOut,
linear_tag, linear_tag, linestring_tag,
false, false, false
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>

View File

@@ -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)

View File

@@ -2,6 +2,11 @@
// Copyright (c) 2007-2015 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)
@@ -60,6 +65,7 @@ template
typename Indexed,
typename Geometry1, typename Geometry2,
typename RobustPolicy,
typename SideStrategy,
bool Reverse1, bool Reverse2
>
struct less_by_segment_ratio
@@ -68,12 +74,14 @@ struct less_by_segment_ratio
, operation_type for_operation
, Geometry1 const& geometry1
, Geometry2 const& geometry2
, RobustPolicy const& robust_policy)
, RobustPolicy const& robust_policy
, SideStrategy const& strategy)
: m_turns(turns)
, m_for_operation(for_operation)
, m_geometry1(geometry1)
, m_geometry2(geometry2)
, m_robust_policy(robust_policy)
, m_strategy(strategy)
{
}
@@ -84,6 +92,7 @@ private :
Geometry1 const& m_geometry1;
Geometry2 const& m_geometry2;
RobustPolicy const& m_robust_policy;
SideStrategy const& m_strategy;
typedef typename geometry::point_type<Geometry1>::type point_type;
@@ -108,13 +117,8 @@ private :
*right.other_seg_id,
si, sj);
typedef typename strategy::side::services::default_strategy
<
typename cs_tag<point_type>::type
>::type strategy;
int const side_rj_p = strategy::apply(pi, pj, rj);
int const side_sj_p = strategy::apply(pi, pj, sj);
int const side_rj_p = m_strategy.apply(pi, pj, rj);
int const side_sj_p = m_strategy.apply(pi, pj, sj);
// Put the one turning left (1; right == -1) as last
if (side_rj_p != side_sj_p)
@@ -122,8 +126,8 @@ private :
return side_rj_p < side_sj_p;
}
int const side_sj_r = strategy::apply(ri, rj, sj);
int const side_rj_s = strategy::apply(si, sj, rj);
int const side_sj_r = m_strategy.apply(ri, rj, sj);
int const side_rj_s = m_strategy.apply(si, sj, rj);
// If they both turn left: the most left as last
// If they both turn right: this is not relevant, but take also here most left

View File

@@ -194,13 +194,15 @@ protected:
typename Turns,
typename LinearGeometry1,
typename LinearGeometry2,
typename OutputIterator
typename OutputIterator,
typename IntersectionStrategy
>
static inline OutputIterator
sort_and_follow_turns(Turns& turns,
LinearGeometry1 const& linear1,
LinearGeometry2 const& linear2,
OutputIterator oit)
OutputIterator oit,
IntersectionStrategy const& strategy)
{
// remove turns that have no added value
turns::filter_continue_turns
@@ -228,7 +230,7 @@ protected:
FollowIsolatedPoints,
!EnableFilterContinueTurns || OverlayType == overlay_intersection
>::apply(linear1, linear2, boost::begin(turns), boost::end(turns),
oit);
oit, strategy.get_side_strategy());
}
public:
@@ -277,7 +279,7 @@ public:
OverlayType,
EnableFollowIsolatedPoints
&& OverlayType == overlay_intersection
>(turns, linear1, linear2, oit);
>(turns, linear1, linear2, oit, strategy);
}
};

View File

@@ -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

View File

@@ -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;
turn_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());
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
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;
}
// So don't set has_traversed_turn here
}
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,
@@ -197,7 +197,16 @@ inline OutputIterator return_if_one_input_is_empty(Geometry1 const& geometry1,
typename geometry::ring_type<GeometryOut>::type
> ring_container_type;
typedef ring_properties<typename geometry::point_type<Geometry1>::type> properties;
typedef typename geometry::point_type<Geometry1>::type point_type1;
typedef ring_properties
<
point_type1,
typename Strategy::template area_strategy
<
point_type1
>::type::return_type
> properties;
// Silence warning C4127: conditional expression is constant
#if defined(_MSC_VER)
@@ -297,9 +306,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);
}
@@ -309,8 +322,9 @@ std::cout << "get turns" << std::endl;
#ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE
std::cout << "enrich" << std::endl;
#endif
typename Strategy::side_strategy_type side_strategy;
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,
@@ -334,17 +348,21 @@ 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;
typedef ring_properties
<
typename geometry::point_type<GeometryOut>::type
> properties;
<
point_type,
typename area_strategy_type::return_type
> properties;
// Select all rings which are NOT touched by any intersection point
std::map<ring_identifier, properties> selected_ring_properties;
@@ -353,13 +371,15 @@ std::cout << "traverse" << std::endl;
// Add rings created during traversal
{
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);
it != boost::end(rings);
++it)
{
selected_ring_properties[id] = properties(*it);
selected_ring_properties[id] = properties(*it, area_strategy);
selected_ring_properties[id].reversed = ReverseOut;
id.multi_index++;
}

View File

@@ -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
@@ -41,6 +42,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

View File

@@ -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>

View File

@@ -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::sort(points2.begin(), points2.end(), detail::relate::less());
std::vector<point2_type> points2(boost::begin(multipoint2),
boost::end(multipoint2));
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
<

View File

@@ -27,11 +27,11 @@ namespace boost { namespace geometry
namespace detail { namespace overlay
{
template <typename Point>
template <typename Point, typename AreaType>
struct ring_properties
{
typedef Point point_type;
typedef typename default_area_result<Point>::type area_type;
typedef AreaType area_type;
bool valid;
@@ -56,13 +56,13 @@ struct ring_properties
, parent_area(-1)
{}
template <typename RingOrBox>
inline ring_properties(RingOrBox const& ring_or_box)
template <typename RingOrBox, typename AreaStrategy>
inline ring_properties(RingOrBox const& ring_or_box, AreaStrategy const& strategy)
: reversed(false)
, discarded(false)
, parent_area(-1)
{
this->area = geometry::area(ring_or_box);
this->area = geometry::area(ring_or_box, strategy);
valid = geometry::point_on_border(this->point, ring_or_box);
}

View File

@@ -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)
{}
};
@@ -59,41 +61,45 @@ namespace dispatch
template <typename Box>
struct select_rings<box_tag, Box>
{
template <typename Geometry, typename RingPropertyMap>
template <typename Geometry, typename RingPropertyMap, typename AreaStrategy>
static inline void apply(Box const& box, Geometry const& ,
ring_identifier const& id, RingPropertyMap& ring_properties)
ring_identifier const& id, RingPropertyMap& ring_properties,
AreaStrategy const& strategy)
{
ring_properties[id] = typename RingPropertyMap::mapped_type(box);
ring_properties[id] = typename RingPropertyMap::mapped_type(box, strategy);
}
template <typename RingPropertyMap>
template <typename RingPropertyMap, typename AreaStrategy>
static inline void apply(Box const& box,
ring_identifier const& id, RingPropertyMap& ring_properties)
ring_identifier const& id, RingPropertyMap& ring_properties,
AreaStrategy const& strategy)
{
ring_properties[id] = typename RingPropertyMap::mapped_type(box);
ring_properties[id] = typename RingPropertyMap::mapped_type(box, strategy);
}
};
template <typename Ring>
struct select_rings<ring_tag, Ring>
{
template <typename Geometry, typename RingPropertyMap>
template <typename Geometry, typename RingPropertyMap, typename AreaStrategy>
static inline void apply(Ring const& ring, Geometry const& ,
ring_identifier const& id, RingPropertyMap& ring_properties)
ring_identifier const& id, RingPropertyMap& ring_properties,
AreaStrategy const& strategy)
{
if (boost::size(ring) > 0)
{
ring_properties[id] = typename RingPropertyMap::mapped_type(ring);
ring_properties[id] = typename RingPropertyMap::mapped_type(ring, strategy);
}
}
template <typename RingPropertyMap>
template <typename RingPropertyMap, typename AreaStrategy>
static inline void apply(Ring const& ring,
ring_identifier const& id, RingPropertyMap& ring_properties)
ring_identifier const& id, RingPropertyMap& ring_properties,
AreaStrategy const& strategy)
{
if (boost::size(ring) > 0)
{
ring_properties[id] = typename RingPropertyMap::mapped_type(ring);
ring_properties[id] = typename RingPropertyMap::mapped_type(ring, strategy);
}
}
};
@@ -102,14 +108,15 @@ namespace dispatch
template <typename Polygon>
struct select_rings<polygon_tag, Polygon>
{
template <typename Geometry, typename RingPropertyMap>
template <typename Geometry, typename RingPropertyMap, typename AreaStrategy>
static inline void apply(Polygon const& polygon, Geometry const& geometry,
ring_identifier id, RingPropertyMap& ring_properties)
ring_identifier id, RingPropertyMap& ring_properties,
AreaStrategy const& strategy)
{
typedef typename geometry::ring_type<Polygon>::type ring_type;
typedef select_rings<ring_tag, ring_type> per_ring;
per_ring::apply(exterior_ring(polygon), geometry, id, ring_properties);
per_ring::apply(exterior_ring(polygon), geometry, id, ring_properties, strategy);
typename interior_return_type<Polygon const>::type
rings = interior_rings(polygon);
@@ -117,18 +124,19 @@ namespace dispatch
it = boost::begin(rings); it != boost::end(rings); ++it)
{
id.ring_index++;
per_ring::apply(*it, geometry, id, ring_properties);
per_ring::apply(*it, geometry, id, ring_properties, strategy);
}
}
template <typename RingPropertyMap>
template <typename RingPropertyMap, typename AreaStrategy>
static inline void apply(Polygon const& polygon,
ring_identifier id, RingPropertyMap& ring_properties)
ring_identifier id, RingPropertyMap& ring_properties,
AreaStrategy const& strategy)
{
typedef typename geometry::ring_type<Polygon>::type ring_type;
typedef select_rings<ring_tag, ring_type> per_ring;
per_ring::apply(exterior_ring(polygon), id, ring_properties);
per_ring::apply(exterior_ring(polygon), id, ring_properties, strategy);
typename interior_return_type<Polygon const>::type
rings = interior_rings(polygon);
@@ -136,7 +144,7 @@ namespace dispatch
it = boost::begin(rings); it != boost::end(rings); ++it)
{
id.ring_index++;
per_ring::apply(*it, id, ring_properties);
per_ring::apply(*it, id, ring_properties, strategy);
}
}
};
@@ -144,9 +152,10 @@ namespace dispatch
template <typename Multi>
struct select_rings<multi_polygon_tag, Multi>
{
template <typename Geometry, typename RingPropertyMap>
template <typename Geometry, typename RingPropertyMap, typename AreaStrategy>
static inline void apply(Multi const& multi, Geometry const& geometry,
ring_identifier id, RingPropertyMap& ring_properties)
ring_identifier id, RingPropertyMap& ring_properties,
AreaStrategy const& strategy)
{
typedef typename boost::range_iterator
<
@@ -159,7 +168,7 @@ namespace dispatch
for (iterator_type it = boost::begin(multi); it != boost::end(multi); ++it)
{
id.ring_index = -1;
per_polygon::apply(*it, geometry, id, ring_properties);
per_polygon::apply(*it, geometry, id, ring_properties, strategy);
id.multi_index++;
}
}
@@ -258,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;
}
@@ -311,12 +320,16 @@ inline void select_rings(Geometry1 const& geometry1, Geometry2 const& geometry2,
{
typedef typename geometry::tag<Geometry1>::type tag1;
typedef typename geometry::tag<Geometry2>::type tag2;
typedef typename geometry::point_type<Geometry1>::type point1_type;
typedef typename geometry::point_type<Geometry2>::type point2_type;
RingPropertyMap all_ring_properties;
dispatch::select_rings<tag1, Geometry1>::apply(geometry1, geometry2,
ring_identifier(0, -1, -1), all_ring_properties);
ring_identifier(0, -1, -1), all_ring_properties,
strategy.template get_area_strategy<point1_type>());
dispatch::select_rings<tag2, Geometry2>::apply(geometry2, geometry1,
ring_identifier(1, -1, -1), all_ring_properties);
ring_identifier(1, -1, -1), all_ring_properties,
strategy.template get_area_strategy<point2_type>());
update_ring_selection<OverlayType>(geometry1, geometry2, turn_info_per_ring,
all_ring_properties, selected_ring_properties,
@@ -337,10 +350,12 @@ inline void select_rings(Geometry const& geometry,
Strategy const& strategy)
{
typedef typename geometry::tag<Geometry>::type tag;
typedef typename geometry::point_type<Geometry>::type point_type;
RingPropertyMap all_ring_properties;
dispatch::select_rings<tag, Geometry>::apply(geometry,
ring_identifier(0, -1, -1), all_ring_properties);
ring_identifier(0, -1, -1), all_ring_properties,
strategy.template get_area_strategy<point_type>());
update_ring_selection<OverlayType>(geometry, geometry, turn_info_per_ring,
all_ring_properties, selected_ring_properties,

View File

@@ -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);
}

View File

@@ -2,6 +2,11 @@
// Copyright (c) 2015 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)
@@ -18,7 +23,6 @@
#include <boost/geometry/algorithms/detail/overlay/get_ring.hpp>
#include <boost/geometry/algorithms/detail/direction_code.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
#include <boost/geometry/strategies/side.hpp>
namespace boost { namespace geometry
{
@@ -87,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;
}
};
@@ -106,17 +117,13 @@ struct less_false
}
};
template <typename Point, typename LessOnSame, typename Compare>
template <typename Point, typename SideStrategy, typename LessOnSame, typename Compare>
struct less_by_side
{
typedef typename strategy::side::services::default_strategy
<
typename cs_tag<Point>::type
>::type side;
less_by_side(const Point& p1, const Point& p2)
less_by_side(const Point& p1, const Point& p2, SideStrategy const& strategy)
: m_p1(p1)
, m_p2(p2)
, m_strategy(strategy)
{}
template <typename T>
@@ -125,8 +132,8 @@ struct less_by_side
LessOnSame on_same;
Compare compare;
int const side_first = side::apply(m_p1, m_p2, first.point);
int const side_second = side::apply(m_p1, m_p2, second.point);
int const side_first = m_strategy.apply(m_p1, m_p2, first.point);
int const side_second = m_strategy.apply(m_p1, m_p2, second.point);
if (side_first == 0 && side_second == 0)
{
@@ -166,7 +173,7 @@ struct less_by_side
// They are both left, both right, and/or both collinear (with each other and/or with p1,p2)
// Check mutual side
int const side_second_wrt_first = side::apply(m_p2, first.point, second.point);
int const side_second_wrt_first = m_strategy.apply(m_p2, first.point, second.point);
if (side_second_wrt_first == 0)
{
@@ -184,6 +191,7 @@ struct less_by_side
private :
Point m_p1, m_p2;
SideStrategy const& m_strategy;
};
// Sorts vectors in counter clockwise order (by default)
@@ -193,6 +201,7 @@ template
bool Reverse2,
overlay_type OverlayType,
typename Point,
typename SideStrategy,
typename Compare
>
struct side_sorter
@@ -223,9 +232,10 @@ private :
};
public :
side_sorter()
side_sorter(SideStrategy const& strategy)
: m_origin_count(0)
, m_origin_segment_distance(0)
, m_strategy(strategy)
{}
template <typename Operation, typename Geometry1, typename Geometry2>
@@ -309,8 +319,8 @@ public :
// to give colinear points
// Sort by side and assign rank
less_by_side<Point, less_by_index, Compare> less_unique(m_origin, turn_point);
less_by_side<Point, less_false, Compare> less_non_unique(m_origin, turn_point);
less_by_side<Point, SideStrategy, less_by_index, Compare> less_unique(m_origin, turn_point, m_strategy);
less_by_side<Point, SideStrategy, less_false, Compare> less_non_unique(m_origin, turn_point, m_strategy);
std::sort(m_ranked_points.begin(), m_ranked_points.end(), less_unique);
@@ -425,6 +435,7 @@ public :
Point m_origin;
std::size_t m_origin_count;
int m_origin_segment_distance;
SideStrategy m_strategy;
private :

View File

@@ -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)
@@ -94,6 +99,7 @@ template
typename Turns,
typename Clusters,
typename RobustPolicy,
typename SideStrategy,
typename Visitor
>
struct traversal
@@ -108,22 +114,25 @@ struct traversal
typedef sort_by_side::side_sorter
<
Reverse1, Reverse2, OverlayType,
point_type, side_compare_type
point_type, SideStrategy, side_compare_type
> sbs_type;
inline traversal(Geometry1 const& geometry1, Geometry2 const& geometry2,
Turns& turns, Clusters const& clusters,
RobustPolicy const& robust_policy, Visitor& visitor)
RobustPolicy const& robust_policy, SideStrategy const& strategy,
Visitor& visitor)
: m_geometry1(geometry1)
, m_geometry2(geometry2)
, m_turns(turns)
, m_clusters(clusters)
, m_robust_policy(robust_policy)
, m_strategy(strategy)
, m_visitor(visitor)
{
}
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);
@@ -134,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();
}
}
@@ -184,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);
}
@@ -245,7 +280,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);
}
@@ -372,13 +407,50 @@ 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 counts: in some cases interior rings might be generated with
// polygons on both sides
// Check finalized: TODO: this should be finetuned, it is not necessary
bool const ok = op.enriched.count_left == 0
&& op.enriched.count_right > 0
&& ! op.visited.finalized();
if (! ok)
{
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
@@ -394,62 +466,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)
if (ranked_point.rank > selected_rank)
{
// Sorted on rank, so it makes no sense to continue
break;
}
int const code
= select_turn_in_cluster_union(selected_rank, ranked_point,
start_turn_index, start_op_index);
if (code > best_code)
{
// 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;
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;
}
result = 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)
{
return false;
}
turn_type const& turn = m_turns[rwd.turn_index];
if (! turn.both(op_type))
{
return false;
}
// Check if this is not yet taken
turn_operation_type const& op = turn.operations[rwd.operation_index];
if (op.visited.finalized())
{
return false;
}
}
return true;
return result;
}
inline bool analyze_cluster_intersection(signed_size_type& turn_index,
@@ -467,12 +509,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++)
{
@@ -522,7 +566,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;
@@ -537,6 +581,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++)
{
@@ -554,8 +601,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;
}
}
}
@@ -573,13 +625,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());
@@ -587,7 +639,7 @@ struct traversal
cluster_info const& cinfo = mit->second;
std::set<signed_size_type> const& ids = cinfo.turn_indices;
sbs_type sbs;
sbs_type sbs(m_strategy);
for (typename std::set<signed_size_type>::const_iterator sit = ids.begin();
sit != ids.end(); ++sit)
@@ -620,7 +672,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
{
@@ -633,7 +686,7 @@ struct traversal
turn_type const& current_turn,
segment_identifier const& previous_seg_id)
{
sbs_type sbs;
sbs_type sbs(m_strategy);
// Add this turn to the sort-by-side sorter
for (int i = 0; i < 2; i++)
@@ -661,7 +714,9 @@ 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;
}
@@ -689,6 +744,9 @@ struct traversal
bool const correct
= ! 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)
@@ -762,7 +820,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)
@@ -773,7 +831,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,
@@ -784,10 +842,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;
}
@@ -825,6 +883,7 @@ private :
Turns& m_turns;
Clusters const& m_clusters;
RobustPolicy const& m_robust_policy;
SideStrategy m_strategy;
Visitor& m_visitor;
};

View File

@@ -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

View File

@@ -41,6 +41,7 @@ template
typename Geometry1,
typename Geometry2,
typename Turns,
typename TurnInfoMap,
typename Clusters,
typename IntersectionStrategy,
typename RobustPolicy,
@@ -49,9 +50,13 @@ template
>
struct traversal_ring_creator
{
typedef traversal<Reverse1, Reverse2, OverlayType,
Geometry1, Geometry2, Turns, Clusters, RobustPolicy, Visitor>
traversal_type;
typedef traversal
<
Reverse1, Reverse2, OverlayType,
Geometry1, Geometry2, Turns, Clusters,
RobustPolicy, typename IntersectionStrategy::side_strategy_type,
Visitor
> traversal_type;
typedef typename boost::range_value<Turns>::type turn_type;
typedef typename turn_type::turn_operation_type turn_operation_type;
@@ -60,13 +65,17 @@ 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, robust_policy,visitor)
: m_trav(geometry1, geometry2, turns, clusters,
robust_policy, intersection_strategy.get_side_strategy(),
visitor)
, 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)
@@ -103,12 +112,14 @@ struct traversal_ring_creator
{
geometry::copy_segments<Reverse1>(m_geometry1,
previous_op.seg_id, to_vertex_index,
m_intersection_strategy.get_side_strategy(),
m_robust_policy, current_ring);
}
else
{
geometry::copy_segments<Reverse2>(m_geometry2,
previous_op.seg_id, to_vertex_index,
m_intersection_strategy.get_side_strategy(),
m_robust_policy, current_ring);
}
}
@@ -152,6 +163,7 @@ struct traversal_ring_creator
turn_type& current_turn = m_turns[turn_index];
turn_operation_type& op = current_turn.operations[op_index];
detail::overlay::append_no_dups_or_spikes(current_ring, current_turn.point,
m_intersection_strategy.get_side_strategy(),
m_robust_policy);
// Register the visit
@@ -169,6 +181,7 @@ struct traversal_ring_creator
turn_operation_type& start_op = m_turns[start_turn_index].operations[start_op_index];
detail::overlay::append_no_dups_or_spikes(ring, start_turn.point,
m_intersection_strategy.get_side_strategy(),
m_robust_policy);
signed_size_type current_turn_index = start_turn_index;
@@ -193,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)
@@ -271,10 +284,12 @@ struct traversal_ring_creator
if (geometry::num_points(ring) >= min_num_points)
{
clean_closing_dups_and_spikes(ring, m_robust_policy);
clean_closing_dups_and_spikes(ring,
m_intersection_strategy.get_side_strategy(),
m_robust_policy);
rings.push_back(ring);
m_trav.finalize_visit_info();
m_trav.finalize_visit_info(m_turn_info_map);
finalized_ring_size++;
}
}
@@ -335,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;

View File

@@ -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)
{
signed_size_type const& id = *it;
if (other_turn_ids.count(id) == 0)
{
turn_id_difference.insert(id);
}
}
return true;
}
bool one_connection_to_another_region(region_properties const& region) const
{
// For example:
// +----------------------+
// | __ |
// | / \|
// | | x
// | \__/|
// | |
// +----------------------+
if (region.connected_region_counts.size() == 1)
{
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;
}
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)
{
connection_properties const& cprop = it->second;
if (cprop.cluster_indices.size() != 1)
if (cprop.count != 1)
{
// Either no cluster (non colocated point), or more clusters
all_colocated = false;
return false;
}
int const cluster_id = *cprop.cluster_indices.begin();
if (cluster_id == -1)
signed_size_type const unique_turn_id = *cprop.unique_turn_ids.begin();
if (first)
{
all_colocated = false;
first_turn_id = unique_turn_id;
first = false;
}
else if (unique_cluster_id == -1)
else if (first_turn_id != unique_turn_id)
{
unique_cluster_id = cluster_id;
}
else if (unique_cluster_id != cluster_id)
{
all_colocated = false;
return false;
}
}
if (all_colocated)
{
return isolation_yes;
}
return true;
}
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;
// 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)
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)
{
// Normal situation, skip its direct parent
continue;
}
if (visited.count(region_id) > 0)
{
// Find one of its ancestors again, this is a ring. Not isolated.
return isolation_no;
}
if (cprop.count > 1)
{
return isolation_no;
}
typename region_connection_map::iterator mit = m_connected_regions.find(region_id);
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;
region_properties& prop = mit->second;
if (prop.isolated == isolation_unknown)
bool const multiple = connected_region.isolated == isolation_multiple;
if (cprop.count != 1)
{
isolation_type const iso = get_isolation(prop, properties.region_id, vis);
prop.isolated = iso;
if (iso == isolation_no)
if (! multiple)
{
child_not_isolated = true;
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))
{
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)
}
}
}
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];
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)
{
// 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];
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);
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,7 +620,7 @@ 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
@@ -513,8 +636,8 @@ struct traversal_switch_detector
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 +652,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 << " -> "

View File

@@ -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);

View File

@@ -89,22 +89,21 @@ struct turn_info
Point point;
method_type method;
signed_size_type cluster_id; // For multiple turns on same location, >= 0. Else -1
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. 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;
inline turn_info()
: method(method_none)
, touch_only(false)
, cluster_id(-1)
, discarded(false)
, colocated_ii(false)
, colocated_uu(false)
, has_colocated_both(false)
, switch_source(false)
{}
@@ -136,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

View File

@@ -5,10 +5,11 @@
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// Copyright (c) 2013-2015 Adam Wulkiewicz, Lodz, Poland.
// 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
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -19,11 +20,13 @@
#include <boost/geometry/algorithms/detail/direction_code.hpp>
#include <boost/geometry/algorithms/detail/recalculate.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/policies/robustness/robust_point_type.hpp>
#include <boost/geometry/strategies/side.hpp>
#include <boost/geometry/util/condition.hpp>
#include <boost/geometry/util/math.hpp>
namespace boost { namespace geometry
{
@@ -32,6 +35,26 @@ namespace boost { namespace geometry
namespace detail
{
template <typename Point1, typename Point2, typename Point3>
inline bool collinear_point_is_spike_or_equal(Point1 const& last_point,
Point2 const& segment_a,
Point3 const& segment_b)
{
// Check if segment is equal
int const sgn_x1 = sign_of_difference<0>(last_point, segment_b);
int const sgn_y1 = sign_of_difference<1>(last_point, segment_b);
if (sgn_x1 == 0 && sgn_y1 == 0)
{
return true;
}
// Check if segment moves forward
int const sgn_x2 = sign_of_difference<0>(segment_b, segment_a);
int const sgn_y2 = sign_of_difference<1>(segment_b, segment_a);
return sgn_x1 != sgn_x2 || sgn_y1 != sgn_y2;
}
// Checks if a point ("last_point") causes a spike w.r.t.
// the specified two other points (segment_a, segment_b)
//
@@ -42,33 +65,29 @@ namespace detail
// So specify last point first, then (a,b)
// The segment's orientation does matter: if lp is to the right of b
// no spike is reported
template <typename Point1, typename Point2, typename Point3>
static inline bool point_is_spike_or_equal(Point1 const& last_point,
Point2 const& segment_a,
Point3 const& segment_b)
template
<
typename Point1, typename Point2, typename Point3,
typename SideStrategy
>
static inline bool point_is_spike_or_equal(Point1 const& last_point, // prev | back
Point2 const& segment_a, // next | back - 2
Point3 const& segment_b, // curr | back - 1 | spike's vertex
SideStrategy const& strategy)
{
typedef typename strategy::side::services::default_strategy
<
typename cs_tag<Point1>::type
>::type side_strategy;
int const side = side_strategy::apply(last_point, segment_a, segment_b);
int const side = strategy.apply(segment_a, segment_b, last_point);
if (side == 0)
{
// Last point is collinear w.r.t previous segment.
// Check if it is equal
int const sgn_x1 = sign_of_difference<0>(last_point, segment_b);
int const sgn_y1 = sign_of_difference<1>(last_point, segment_b);
if (sgn_x1 == 0 && sgn_y1 == 0)
{
return true;
}
// Check if it moves forward
int const sgn_x2 = sign_of_difference<0>(segment_b, segment_a);
int const sgn_y2 = sign_of_difference<1>(segment_b, segment_a);
return sgn_x1 != sgn_x2 || sgn_y1 != sgn_y2;
#ifdef BOOST_GEOMETRY_ENABLE_POINT_IS_SPIKE_OR_EQUAL_TEST
bool r1 = collinear_point_is_spike_or_equal(last_point, segment_a, segment_b);
bool r2 = direction_code(segment_a, segment_b, last_point) < 1;
if (r1 != r2)
std::cout << "spike detection failure with: " << r1 << " " << r2 << std::endl;
return r2;
#else
return direction_code(segment_a, segment_b, last_point) < 1;
#endif
}
return false;
}
@@ -78,14 +97,16 @@ template
typename Point1,
typename Point2,
typename Point3,
typename SideStrategy,
typename RobustPolicy
>
static inline bool point_is_spike_or_equal(Point1 const& last_point,
Point2 const& segment_a,
Point3 const& segment_b,
SideStrategy const& strategy,
RobustPolicy const& robust_policy)
{
if (point_is_spike_or_equal(last_point, segment_a, segment_b))
if (point_is_spike_or_equal(last_point, segment_a, segment_b, strategy))
{
return true;
}
@@ -111,7 +132,8 @@ static inline bool point_is_spike_or_equal(Point1 const& last_point,
(
last_point_rob,
segment_a_rob,
segment_b_rob
segment_b_rob,
strategy
);
}

View File

@@ -84,43 +84,49 @@ struct midpoint_helper<Point, DimensionCount, DimensionCount>
template <bool Midpoint>
struct point_on_range
{
// Version with iterator
template<typename Point, typename Iterator>
static inline bool apply(Point& point, Iterator begin, Iterator end)
{
Iterator it = begin;
if (it == end)
{
return false;
}
if (! Midpoint)
{
geometry::detail::conversion::convert_point_to_point(*it, point);
return true;
}
Iterator prev = it++;
// Go to next non-duplicate point
while (it != end
&& detail::equals::equals_point_point(*it, *prev))
{
prev = it++;
}
if (it != end)
{
return midpoint_helper
<
Point,
0, dimension<Point>::value
>::apply(point, *prev, *it);
}
return false;
}
// Version with range
template<typename Point, typename Range>
static inline bool apply(Point& point, Range const& range)
{
typedef typename geometry::cs_tag<Point>::type cs_tag;
BOOST_STATIC_ASSERT((! Midpoint || boost::is_same<cs_tag, cartesian_tag>::value));
const std::size_t n = boost::size(range);
if (Midpoint && n > 1)
{
typedef typename boost::range_iterator
<
Range const
>::type iterator;
iterator it = boost::begin(range);
iterator prev = it++;
while (it != boost::end(range)
&& detail::equals::equals_point_point(*it, *prev))
{
prev = it++;
}
if (it != boost::end(range))
{
return midpoint_helper
<
Point,
0, dimension<Point>::value
>::apply(point, *prev, *it);
}
}
if (n > 0)
{
geometry::detail::conversion::convert_point_to_point(*boost::begin(range), point);
return true;
}
return false;
return apply(point, boost::begin(range), boost::end(range));
}
};

View File

@@ -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

View File

@@ -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 ) )

View File

@@ -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);

View File

@@ -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

View File

@@ -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>
@@ -165,6 +166,8 @@ private:
m_endpoints.reserve(boost::size(m_mls) * 2);
m_has_interior = false;
typedef typename boost::range_iterator<MultiLinestring const>::type ls_iterator;
for ( ls_iterator it = boost::begin(m_mls) ; it != boost::end(m_mls) ; ++it )
{
@@ -212,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());
}
@@ -222,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);
}

View File

@@ -2,8 +2,8 @@
// Copyright (c) 2015 Barend Gehrels, Amsterdam, the Netherlands.
// 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
@@ -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
{
@@ -27,6 +30,90 @@ namespace boost { namespace geometry
namespace detail { namespace section
{
template
<
std::size_t Dimension,
typename Geometry,
typename CastedCSTag = typename tag_cast
<
typename cs_tag<Geometry>::type,
spherical_tag
>::type
>
struct preceding_check
{
template <typename Point, typename Box>
static inline bool apply(int dir, Point const& point, Box const& /*point_box*/, Box const& other_box)
{
return (dir == 1 && get<Dimension>(point) < get<min_corner, Dimension>(other_box))
|| (dir == -1 && get<Dimension>(point) > get<max_corner, Dimension>(other_box));
}
};
template <typename Geometry>
struct preceding_check<0, Geometry, spherical_tag>
{
template <typename Point, typename Box>
static inline bool apply(int dir, Point const& point, Box const& point_box, Box const& other_box)
{
typedef typename select_coordinate_type
<
Point, Box
>::type calc_t;
typedef typename coordinate_system<Point>::type::units units_t;
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
>(other_min, value);
calc_t const diff_min_min = math::longitude_distance_signed
<
units_t, calc_t
>(other_min, get<min_corner, 0>(point_box));
return diff_min < c0 && diff_min_min <= c0 && diff_min_min <= diff_min;
}
else if (dir == -1)
{
calc_t const diff_max = math::longitude_distance_signed
<
units_t, calc_t
>(other_max, value);
calc_t const diff_max_max = math::longitude_distance_signed
<
units_t, calc_t
>(other_max, get<max_corner, 0>(point_box));
return diff_max > c0 && diff_max_max >= c0 && diff_max <= diff_max_max;
}
return false;
}
};
template
<
std::size_t Dimension,
@@ -34,14 +121,15 @@ template
typename RobustBox,
typename RobustPolicy
>
static inline bool preceding(int dir, Point const& point,
RobustBox const& robust_box,
RobustPolicy const& robust_policy)
static inline bool preceding(int dir,
Point const& point,
RobustBox const& point_robust_box,
RobustBox const& other_robust_box,
RobustPolicy const& robust_policy)
{
typename geometry::robust_point_type<Point, RobustPolicy>::type robust_point;
geometry::recalculate(robust_point, point, robust_policy);
return (dir == 1 && get<Dimension>(robust_point) < get<min_corner, Dimension>(robust_box))
|| (dir == -1 && get<Dimension>(robust_point) > get<max_corner, Dimension>(robust_box));
return preceding_check<Dimension, Point>::apply(dir, robust_point, point_robust_box, other_robust_box);
}
template
@@ -51,14 +139,13 @@ template
typename RobustBox,
typename RobustPolicy
>
static inline bool exceeding(int dir, Point const& point,
RobustBox const& robust_box,
RobustPolicy const& robust_policy)
static inline bool exceeding(int dir,
Point const& point,
RobustBox const& point_robust_box,
RobustBox const& other_robust_box,
RobustPolicy const& robust_policy)
{
typename geometry::robust_point_type<Point, RobustPolicy>::type robust_point;
geometry::recalculate(robust_point, point, robust_policy);
return (dir == 1 && get<Dimension>(robust_point) > get<max_corner, Dimension>(robust_box))
|| (dir == -1 && get<Dimension>(robust_point) < get<min_corner, Dimension>(robust_box));
return preceding<Dimension>(-dir, point, point_robust_box, other_robust_box, robust_policy);
}

View File

@@ -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 2013, 2014, 2015.
// Modifications copyright (c) 2013-2015 Oracle and/or its affiliates.
// This file was modified by Oracle on 2013, 2014, 2015, 2017.
// Modifications copyright (c) 2013-2017 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
@@ -136,11 +136,21 @@ struct sections : std::vector<section<Box, DimensionCount> >
namespace detail { namespace sectionalize
{
// NOTE: This utility will NOT work for latitudes, dimension 1 in spherical
// and geographic coordinate system because in these coordinate systems
// e.g. a segment on northern hemisphere may go towards greater latitude
// and then towards lesser latitude.
template
<
typename Point,
typename DimensionVector,
std::size_t Index,
std::size_t Count
std::size_t Count,
typename CastedCSTag = typename tag_cast
<
typename cs_tag<Point>::type,
spherical_tag
>::type
>
struct get_direction_loop
{
@@ -161,21 +171,67 @@ struct get_direction_loop
get_direction_loop
<
Point,
DimensionVector,
Index + 1,
Count
Count,
CastedCSTag
>::apply(seg, directions);
}
};
template <typename DimensionVector, std::size_t Count>
struct get_direction_loop<DimensionVector, Count, Count>
template
<
typename Point,
typename DimensionVector,
std::size_t Count
>
struct get_direction_loop<Point, DimensionVector, 0, Count, spherical_tag>
{
typedef typename boost::mpl::at_c<DimensionVector, 0>::type dimension;
template <typename Segment>
static inline void apply(Segment const& seg,
int directions[Count])
{
typedef typename coordinate_type<Segment>::type coordinate_type;
typedef typename coordinate_system<Point>::type::units units_t;
coordinate_type const diff = math::longitude_distance_signed
<
units_t, coordinate_type
>(geometry::get<0, 0>(seg),
geometry::get<1, 0>(seg));
coordinate_type zero = coordinate_type();
directions[0] = diff > zero ? 1 : diff < zero ? -1 : 0;
get_direction_loop
<
Point,
DimensionVector,
1,
Count,
spherical_tag
>::apply(seg, directions);
}
};
template
<
typename Point,
typename DimensionVector,
std::size_t Count,
typename CastedCSTag
>
struct get_direction_loop<Point, DimensionVector, Count, Count, CastedCSTag>
{
template <typename Segment>
static inline void apply(Segment const&, int [Count])
{}
};
//! Copy one static array to another
template <typename T, std::size_t Index, std::size_t Count>
struct copy_loop
@@ -410,7 +466,7 @@ struct sectionalize_part
int direction_classes[dimension_count] = {0};
get_direction_loop
<
DimensionVector, 0, dimension_count
Point, DimensionVector, 0, dimension_count
>::apply(robust_segment, direction_classes);
// if "dir" == 0 for all point-dimensions, it is duplicate.
@@ -929,9 +985,12 @@ inline void sectionalize(Geometry const& geometry,
typename cs_tag<Geometry>::type
>::type envelope_strategy_type;
sectionalize<Reverse, DimensionVector>(geometry, robust_policy, sections,
envelope_strategy_type(),
source_index, max_count);
boost::geometry::sectionalize
<
Reverse, DimensionVector
>(geometry, robust_policy, sections,
envelope_strategy_type(),
source_index, max_count);
}
}} // namespace boost::geometry

View File

@@ -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();
}

View File

@@ -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);

View File

@@ -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,

View File

@@ -2,6 +2,11 @@
// Copyright (c) 2015 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)
@@ -10,17 +15,23 @@
#define BOOST_GEOMETRY_ALGORITHMS_IS_CONVEX_HPP
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/iterators/ever_circling_iterator.hpp>
#include <boost/geometry/strategies/default_strategy.hpp>
#include <boost/geometry/strategies/side.hpp>
#include <boost/geometry/strategies/cartesian/side_by_triangle.hpp>
#include <boost/geometry/views/detail/normalized_view.hpp>
namespace boost { namespace geometry
{
@@ -31,15 +42,9 @@ namespace detail { namespace is_convex
struct ring_is_convex
{
template <typename Ring>
static inline bool apply(Ring const& ring)
template <typename Ring, typename SideStrategy>
static inline bool apply(Ring const& ring, SideStrategy const& strategy)
{
typedef typename geometry::point_type<Ring>::type point_type;
typedef typename strategy::side::services::default_strategy
<
typename cs_tag<point_type>::type
>::type side_strategy_type;
std::size_t n = boost::size(ring);
if (boost::size(ring) < core_detail::closure::minimum_ring_size
<
@@ -86,7 +91,7 @@ struct ring_is_convex
// iterator
for (std::size_t i = 0; i < n; i++)
{
int const side = side_strategy_type::apply(*previous, *current, *next);
int const side = strategy.apply(*previous, *current, *next);
if (side == 1)
{
// Next is on the left side of clockwise ring:
@@ -129,7 +134,8 @@ struct is_convex : not_implemented<Tag>
template <typename Box>
struct is_convex<Box, box_tag>
{
static inline bool apply(Box const& )
template <typename Strategy>
static inline bool apply(Box const& , Strategy const& )
{
// Any box is convex (TODO: consider spherical boxes)
return true;
@@ -144,13 +150,71 @@ struct is_convex<Box, ring_tag> : detail::is_convex::ring_is_convex
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
// TODO: variants
namespace resolve_variant {
template <typename Geometry>
struct is_convex
{
template <typename Strategy>
static bool apply(Geometry const& geometry, Strategy const& strategy)
{
concepts::check<Geometry>();
return dispatch::is_convex<Geometry>::apply(geometry, strategy);
}
static bool apply(Geometry const& geometry, geometry::default_strategy const&)
{
typedef typename strategy::side::services::default_strategy
<
typename cs_tag<Geometry>::type
>::type side_strategy;
return apply(geometry, side_strategy());
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct is_convex<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
{
template <typename Strategy>
struct visitor: boost::static_visitor<bool>
{
Strategy const& m_strategy;
visitor(Strategy const& strategy) : m_strategy(strategy) {}
template <typename Geometry>
bool operator()(Geometry const& geometry) const
{
return is_convex<Geometry>::apply(geometry, m_strategy);
}
};
template <typename Strategy>
static inline bool apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
Strategy const& strategy)
{
return boost::apply_visitor(visitor<Strategy>(strategy), geometry);
}
};
} // namespace resolve_variant
// TODO: documentation / qbk
template<typename Geometry>
inline bool is_convex(Geometry const& geometry)
{
return dispatch::is_convex<Geometry>::apply(geometry);
return resolve_variant::is_convex
<
Geometry
>::apply(geometry, geometry::default_strategy());
}
// TODO: documentation / qbk
template<typename Geometry, typename Strategy>
inline bool is_convex(Geometry const& geometry, Strategy const& strategy)
{
return resolve_variant::is_convex<Geometry>::apply(geometry, strategy);
}

View File

@@ -5,8 +5,8 @@
// Copyright (c) 2009-2013 Mateusz Loskot, London, UK.
// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland.
// 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 Adam Wulkiewicz, on behalf of Oracle
@@ -33,6 +33,7 @@
#include <boost/geometry/algorithms/detail/extreme_points.hpp>
#include <boost/geometry/strategies/cartesian/centroid_bashein_detmer.hpp>
#include <boost/geometry/strategies/side.hpp>
namespace boost { namespace geometry
@@ -241,8 +242,9 @@ inline void replace_extremes_for_self_tangencies(Extremes& extremes, Intruders&
extremes = triangle;
}
template <int Dimension, typename Geometry, typename Point>
inline bool calculate_point_on_surface(Geometry const& geometry, Point& point)
template <int Dimension, typename Geometry, typename Point, typename SideStrategy>
inline bool calculate_point_on_surface(Geometry const& geometry, Point& point,
SideStrategy const& strategy)
{
typedef typename geometry::point_type<Geometry>::type point_type;
typedef typename geometry::coordinate_type<Geometry>::type coordinate_type;
@@ -250,7 +252,7 @@ inline bool calculate_point_on_surface(Geometry const& geometry, Point& point)
typedef std::vector<std::vector<point_type> > intruders_type;
intruders_type intruders;
geometry::extreme_points<Dimension>(geometry, extremes, intruders);
geometry::extreme_points<Dimension>(geometry, extremes, intruders, strategy);
if (extremes.size() < 3)
{
@@ -291,21 +293,57 @@ inline bool calculate_point_on_surface(Geometry const& geometry, Point& point)
\tparam Geometry geometry type. This also defines the type of the output point
\param geometry Geometry to take point from
\param point Point to assign
\param strategy side strategy
*/
template <typename Geometry, typename Point>
inline void point_on_surface(Geometry const& geometry, Point & point)
template <typename Geometry, typename Point, typename SideStrategy>
inline void point_on_surface(Geometry const& geometry, Point & point,
SideStrategy const& strategy)
{
concepts::check<Point>();
concepts::check<Geometry const>();
// First try in Y-direction (which should always succeed for valid polygons)
if (! detail::point_on_surface::calculate_point_on_surface<1>(geometry, point))
if (! detail::point_on_surface::calculate_point_on_surface<1>(geometry, point, strategy))
{
// For invalid polygons, we might try X-direction
detail::point_on_surface::calculate_point_on_surface<0>(geometry, point);
detail::point_on_surface::calculate_point_on_surface<0>(geometry, point, strategy);
}
}
/*!
\brief Assigns a Point guaranteed to lie on the surface of the Geometry
\tparam Geometry geometry type. This also defines the type of the output point
\param geometry Geometry to take point from
\param point Point to assign
*/
template <typename Geometry, typename Point>
inline void point_on_surface(Geometry const& geometry, Point & point)
{
typedef typename strategy::side::services::default_strategy
<
typename cs_tag<Geometry>::type
>::type strategy_type;
point_on_surface(geometry, point, strategy_type());
}
/*!
\brief Returns point guaranteed to lie on the surface of the Geometry
\tparam Geometry geometry type. This also defines the type of the output point
\param geometry Geometry to take point from
\param strategy side strategy
\return The Point guaranteed to lie on the surface of the Geometry
*/
template<typename Geometry, typename SideStrategy>
inline typename geometry::point_type<Geometry>::type
return_point_on_surface(Geometry const& geometry, SideStrategy const& strategy)
{
typename geometry::point_type<Geometry>::type result;
geometry::point_on_surface(geometry, result, strategy);
return result;
}
/*!
\brief Returns point guaranteed to lie on the surface of the Geometry
\tparam Geometry geometry type. This also defines the type of the output point

View File

@@ -5,6 +5,11 @@
// Copyright (c) 2009-2013 Mateusz Loskot, London, UK.
// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
// 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)
@@ -34,6 +39,8 @@
#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
#include <boost/geometry/algorithms/clear.hpp>
#include <boost/geometry/strategies/default_strategy.hpp>
#include <boost/geometry/util/condition.hpp>
@@ -59,20 +66,13 @@ namespace detail { namespace remove_spikes
{
template <typename Range>
struct range_remove_spikes
{
typedef typename strategy::side::services::default_strategy
<
typename cs_tag<Range>::type
>::type side_strategy;
typedef typename coordinate_type<Range>::type coordinate_type;
typedef typename point_type<Range>::type point_type;
static inline void apply(Range& range)
template <typename Range, typename SideStrategy>
static inline void apply(Range& range, SideStrategy const& strategy)
{
typedef typename point_type<Range>::type point_type;
std::size_t n = boost::size(range);
std::size_t const min_num_points = core_detail::closure::minimum_ring_size
<
@@ -91,7 +91,10 @@ struct range_remove_spikes
cleaned.push_back(*it);
while(cleaned.size() >= 3
&& detail::point_is_spike_or_equal(cleaned.back(), *(cleaned.end() - 3), *(cleaned.end() - 2)))
&& detail::point_is_spike_or_equal(cleaned.back(),
*(cleaned.end() - 3),
*(cleaned.end() - 2),
strategy))
{
// Remove pen-ultimate point causing the spike (or which was equal)
cleaned.erase(cleaned.end() - 2);
@@ -110,13 +113,21 @@ struct range_remove_spikes
found = false;
// Check for spike in first point
int const penultimate = 2;
while(cleaned.size() >= 3 && detail::point_is_spike_or_equal(cleaned.front(), *(cleaned.end() - penultimate), cleaned.back()))
while(cleaned.size() >= 3
&& detail::point_is_spike_or_equal(cleaned.front(),
*(cleaned.end() - penultimate),
cleaned.back(),
strategy))
{
cleaned.pop_back();
found = true;
}
// Check for spike in second point
while(cleaned.size() >= 3 && detail::point_is_spike_or_equal(*(cleaned.begin() + 1), cleaned.back(), cleaned.front()))
while(cleaned.size() >= 3
&& detail::point_is_spike_or_equal(*(cleaned.begin() + 1),
cleaned.back(),
cleaned.front(),
strategy))
{
cleaned.pop_front();
found = true;
@@ -144,15 +155,13 @@ struct range_remove_spikes
};
template <typename Polygon>
struct polygon_remove_spikes
{
static inline void apply(Polygon& polygon)
template <typename Polygon, typename SideStrategy>
static inline void apply(Polygon& polygon, SideStrategy const& strategy)
{
typedef typename geometry::ring_type<Polygon>::type ring_type;
typedef range_remove_spikes<ring_type> per_range;
per_range::apply(exterior_ring(polygon));
typedef range_remove_spikes per_range;
per_range::apply(exterior_ring(polygon), strategy);
typename interior_return_type<Polygon>::type
rings = interior_rings(polygon);
@@ -160,23 +169,24 @@ struct polygon_remove_spikes
for (typename detail::interior_iterator<Polygon>::type
it = boost::begin(rings); it != boost::end(rings); ++it)
{
per_range::apply(*it);
per_range::apply(*it, strategy);
}
}
};
template <typename MultiGeometry, typename SingleVersion>
template <typename SingleVersion>
struct multi_remove_spikes
{
static inline void apply(MultiGeometry& multi)
template <typename MultiGeometry, typename SideStrategy>
static inline void apply(MultiGeometry& multi, SideStrategy const& strategy)
{
for (typename boost::range_iterator<MultiGeometry>::type
it = boost::begin(multi);
it != boost::end(multi);
++it)
{
SingleVersion::apply(*it);
SingleVersion::apply(*it, strategy);
}
}
};
@@ -199,21 +209,22 @@ template
>
struct remove_spikes
{
static inline void apply(Geometry&)
template <typename SideStrategy>
static inline void apply(Geometry&, SideStrategy const&)
{}
};
template <typename Ring>
struct remove_spikes<Ring, ring_tag>
: detail::remove_spikes::range_remove_spikes<Ring>
: detail::remove_spikes::range_remove_spikes
{};
template <typename Polygon>
struct remove_spikes<Polygon, polygon_tag>
: detail::remove_spikes::polygon_remove_spikes<Polygon>
: detail::remove_spikes::polygon_remove_spikes
{};
@@ -221,11 +232,7 @@ template <typename MultiPolygon>
struct remove_spikes<MultiPolygon, multi_polygon_tag>
: detail::remove_spikes::multi_remove_spikes
<
MultiPolygon,
detail::remove_spikes::polygon_remove_spikes
<
typename boost::range_value<MultiPolygon>::type
>
>
{};
@@ -239,28 +246,46 @@ namespace resolve_variant {
template <typename Geometry>
struct remove_spikes
{
static void apply(Geometry& geometry)
template <typename Strategy>
static void apply(Geometry& geometry, Strategy const& strategy)
{
concepts::check<Geometry>();
dispatch::remove_spikes<Geometry>::apply(geometry);
dispatch::remove_spikes<Geometry>::apply(geometry, strategy);
}
static void apply(Geometry& geometry, geometry::default_strategy const&)
{
typedef typename strategy::side::services::default_strategy
<
typename cs_tag<Geometry>::type
>::type side_strategy;
apply(geometry, side_strategy());
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct remove_spikes<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
{
template <typename Strategy>
struct visitor: boost::static_visitor<void>
{
Strategy const& m_strategy;
visitor(Strategy const& strategy) : m_strategy(strategy) {}
template <typename Geometry>
void operator()(Geometry& geometry) const
{
remove_spikes<Geometry>::apply(geometry);
remove_spikes<Geometry>::apply(geometry, m_strategy);
}
};
static inline void apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry)
template <typename Strategy>
static inline void apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry,
Strategy const& strategy)
{
boost::apply_visitor(visitor(), geometry);
boost::apply_visitor(visitor<Strategy>(strategy), geometry);
}
};
@@ -275,7 +300,20 @@ struct remove_spikes<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
template <typename Geometry>
inline void remove_spikes(Geometry& geometry)
{
resolve_variant::remove_spikes<Geometry>::apply(geometry);
resolve_variant::remove_spikes<Geometry>::apply(geometry, geometry::default_strategy());
}
/*!
\ingroup remove_spikes
\tparam Geometry geometry type
\tparam Strategy side strategy type
\param geometry the geometry to make remove_spikes
\param strategy the side strategy used by the algorithm
*/
template <typename Geometry, typename Strategy>
inline void remove_spikes(Geometry& geometry, Strategy const& strategy)
{
resolve_variant::remove_spikes<Geometry>::apply(geometry, strategy);
}

View File

@@ -110,50 +110,41 @@ public :
}
};
struct dissolve_overlay_visitor
{
public :
void print(char const* /*header*/)
{
}
template <typename Turns>
void print(char const* /*header*/, Turns const& /*turns*/, int /*turn_index*/)
{
}
template <typename Turns>
void print(char const* /*header*/, Turns const& /*turns*/, int /*turn_index*/, int /*op_index*/)
{
}
template <typename Turns>
void visit_turns(int , Turns const& ) {}
template <typename Clusters, typename Turns>
void visit_clusters(Clusters const& , Turns const& ) {}
template <typename Turns, typename Turn, typename Operation>
void visit_traverse(Turns const& /*turns*/, Turn const& /*turn*/, Operation const& /*op*/, const char* /*header*/)
{
}
template <typename Turns, typename Turn, typename Operation>
void visit_traverse_reject(Turns const& , Turn const& , Operation const& ,
detail::overlay::traverse_error_type )
{}
};
template <typename Geometry, typename GeometryOut>
struct dissolve_ring_or_polygon
{
template <typename RescalePolicy, typename OutputIterator, typename Strategy>
template <typename Turns>
static inline void clear(Turns& turns)
{
typedef typename boost::range_value<Turns>::type turn_type;
for (typename boost::range_iterator<Turns>::type
it = boost::begin(turns);
it != boost::end(turns);
++it)
{
turn_type& turn = *it;
turn.discarded = false;
turn.cluster_id = -1;
turn.has_colocated_both = false;
turn.switch_source = false;
turn.touch_only = false;
}
clear_visit_info(turns);
}
template
<
typename RescalePolicy, typename OutputIterator,
typename Strategy, typename Visitor
>
static inline OutputIterator apply(Geometry const& geometry,
RescalePolicy const& rescale_policy,
OutputIterator out,
Strategy const& strategy)
Strategy const& strategy,
Visitor& visitor)
{
typedef typename point_type<Geometry>::type point_type;
@@ -169,93 +160,111 @@ struct dissolve_ring_or_polygon
geometry::self_turns
<
detail::overlay::assign_null_policy
>(geometry, strategy, rescale_policy, turns, policy);
>(geometry, strategy, rescale_policy, turns, policy, 0, false);
// The dissolve process is not necessary if there are no turns at all
visitor.visit_turns(1, turns);
if (boost::size(turns) > 0)
{
typedef typename ring_type<Geometry>::type ring_type;
typedef std::vector<ring_type> out_vector;
out_vector rings;
typedef std::map
<
signed_size_type,
detail::overlay::cluster_info
> cluster_type;
cluster_type clusters;
dissolve_overlay_visitor visitor;
// Enrich/traverse the polygons twice: once for union...
typename Strategy::side_strategy_type const
side_strategy = strategy.get_side_strategy();
enrich_intersection_points<false, false, overlay_dissolve>(turns,
clusters, geometry, geometry, rescale_policy,
side_strategy);
detail::overlay::traverse
<
false, false,
Geometry, Geometry,
overlay_dissolve,
backtrack_for_dissolve<Geometry>
>::apply(geometry, geometry,
strategy, rescale_policy,
turns, rings, clusters, visitor);
clear_visit_info(turns);
// ... and for intersection
enrich_intersection_points<false, false, overlay_intersection>(turns,
clusters, geometry, geometry, rescale_policy,
side_strategy);
detail::overlay::traverse
<
false, false,
Geometry, Geometry,
overlay_intersection,
backtrack_for_dissolve<Geometry>
>::apply(geometry, geometry,
strategy, rescale_policy,
turns, rings, clusters, visitor);
std::map<ring_identifier, detail::overlay::ring_turn_info> map;
detail::overlay::get_ring_turn_info<overlay_dissolve>(map, turns, clusters);
typedef detail::overlay::ring_properties<typename geometry::point_type<Geometry>::type> properties;
std::map<ring_identifier, properties> selected;
detail::overlay::select_rings<overlay_dissolve>(geometry, map, selected, strategy);
// Add intersected rings
{
ring_identifier id(2, 0, -1);
for (typename boost::range_iterator<std::vector<ring_type> const>::type
it = boost::begin(rings);
it != boost::end(rings);
++it)
{
selected[id] = properties(*it);
id.multi_index++;
}
}
detail::overlay::assign_parents(geometry, rings, selected, strategy, true);
return detail::overlay::add_rings<GeometryOut>(selected, geometry, rings, out);
}
else
if (boost::size(turns) == 0)
{
// No self-turns, then add original geometry
GeometryOut g;
geometry::convert(geometry, g);
*out++ = g;
return out;
}
typedef typename ring_type<Geometry>::type ring_type;
typedef std::vector<ring_type> out_vector;
out_vector rings;
typedef std::map
<
signed_size_type,
detail::overlay::cluster_info
> cluster_type;
cluster_type clusters;
// Enrich/traverse the polygons twice: first for union...
typename Strategy::side_strategy_type const
side_strategy = strategy.get_side_strategy();
enrich_intersection_points<false, false, overlay_dissolve_union>(turns,
clusters, geometry, geometry, rescale_policy,
side_strategy);
visitor.visit_turns(2, turns);
visitor.visit_clusters(clusters, turns);
std::map<ring_identifier, overlay::ring_turn_info> turn_info_per_ring;
detail::overlay::traverse
<
false, false,
Geometry, Geometry,
overlay_dissolve_union,
backtrack_for_dissolve<Geometry>
>::apply(geometry, geometry,
strategy, rescale_policy,
turns, rings, turn_info_per_ring, clusters, visitor);
visitor.visit_turns(3, turns);
// ... and then for intersection
clear(turns);
enrich_intersection_points<false, false, overlay_dissolve_intersection>(turns,
clusters, geometry, geometry, rescale_policy,
side_strategy);
visitor.visit_turns(4, turns);
detail::overlay::traverse
<
false, false,
Geometry, Geometry,
overlay_dissolve_intersection,
backtrack_for_dissolve<Geometry>
>::apply(geometry, geometry,
strategy, rescale_policy,
turns, rings, turn_info_per_ring, clusters, visitor);
visitor.visit_turns(5, turns);
detail::overlay::get_ring_turn_info<overlay_dissolve_union>(turn_info_per_ring, turns, clusters);
typedef typename geometry::point_type<Geometry>::type point_type;
typedef typename Strategy::template area_strategy
<
point_type
>::type area_strategy_type;
typedef typename area_strategy_type::return_type area_result_type;
typedef detail::overlay::ring_properties<point_type, area_result_type> properties;
std::map<ring_identifier, properties> selected;
detail::overlay::select_rings<overlay_dissolve_union>(geometry, turn_info_per_ring, selected, strategy);
// Add intersected rings
{
area_strategy_type const area_strategy = strategy.template get_area_strategy<point_type>();
ring_identifier id(2, 0, -1);
for (typename boost::range_iterator<std::vector<ring_type> const>::type
it = boost::begin(rings);
it != boost::end(rings);
++it)
{
selected[id] = properties(*it, area_strategy);
id.multi_index++;
}
}
// Assign parents, checking orientation and discarding negative
// children with negative parents
detail::overlay::assign_parents(geometry, rings, selected,
strategy, true, true);
return detail::overlay::add_rings<GeometryOut>(selected, geometry, rings, out);
}
};
@@ -335,13 +344,15 @@ inline OutputIterator dissolve_inserter(Geometry const& geometry,
rescale_policy_type robust_policy
= geometry::get_rescale_policy<rescale_policy_type>(geometry);
detail::overlay::overlay_null_visitor visitor;
return dispatch::dissolve
<
typename tag<Geometry>::type,
typename tag<GeometryOut>::type,
Geometry,
GeometryOut
>::apply(geometry, robust_policy, out, strategy);
>::apply(geometry, robust_policy, out, strategy, visitor);
}
/*!
@@ -388,6 +399,8 @@ inline void dissolve(Geometry const& geometry, Collection& output_collection, St
concepts::check<geometry_out>();
detail::overlay::overlay_null_visitor visitor;
dispatch::dissolve
<
typename tag<Geometry>::type,
@@ -396,7 +409,7 @@ inline void dissolve(Geometry const& geometry, Collection& output_collection, St
geometry_out
>::apply(geometry, detail::no_rescale_policy(),
std::back_inserter(output_collection),
strategy);
strategy, visitor);
}
template

View File

@@ -38,9 +38,14 @@ namespace detail { namespace dissolve
template <typename Multi, typename GeometryOut>
struct dissolve_multi
{
template <typename RescalePolicy, typename OutputIterator, typename Strategy>
static inline OutputIterator apply(Multi const& multi, RescalePolicy const& rescale_policy,
OutputIterator out, Strategy const& strategy)
template
<
typename RescalePolicy, typename OutputIterator,
typename Strategy, typename Visitor
>
static inline OutputIterator apply(Multi const& multi,
RescalePolicy const& rescale_policy, OutputIterator out,
Strategy const& strategy, Visitor& visitor)
{
typedef typename boost::range_value<Multi>::type polygon_type;
typedef typename boost::range_iterator<Multi const>::type iterator_type;
@@ -55,7 +60,8 @@ struct dissolve_multi
<
polygon_type,
GeometryOut
>::apply(*it, rescale_policy, std::back_inserter(step1), strategy);
>::apply(*it, rescale_policy, std::back_inserter(step1),
strategy, visitor);
}
// Step 2: remove mutual overlap

View File

@@ -5,6 +5,11 @@
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland.
// 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.
@@ -17,6 +22,7 @@
#include <cstddef>
#include <functional>
#include <boost/numeric/conversion/cast.hpp>
@@ -26,9 +32,6 @@
#include <boost/geometry/util/select_coordinate_type.hpp>
#include <boost/geometry/strategies/compare.hpp>
#include <boost/geometry/policies/compare.hpp>
namespace boost { namespace geometry
{
@@ -40,7 +43,6 @@ namespace detail { namespace expand
template
<
typename StrategyLess, typename StrategyGreater,
std::size_t Dimension, std::size_t DimensionCount
>
struct nsphere_loop
@@ -48,20 +50,10 @@ struct nsphere_loop
template <typename Box, typename NSphere>
static inline void apply(Box& box, NSphere const& source)
{
typedef typename strategy::compare::detail::select_strategy
<
StrategyLess, 1, NSphere, Dimension
>::type less_type;
typedef typename strategy::compare::detail::select_strategy
<
StrategyGreater, -1, NSphere, Dimension
>::type greater_type;
typedef typename select_coordinate_type<NSphere, Box>::type coordinate_type;
less_type less;
greater_type greater;
std::less<coordinate_type> const less;
std::greater<coordinate_type> const greater;
coordinate_type const min_coord = get<Dimension>(source) - get_radius<0>(source);
coordinate_type const max_coord = get<Dimension>(source) + get_radius<0>(source);
@@ -78,7 +70,6 @@ struct nsphere_loop
nsphere_loop
<
StrategyLess, StrategyGreater,
Dimension + 1, DimensionCount
>::apply(box, source);
}
@@ -87,12 +78,10 @@ struct nsphere_loop
template
<
typename StrategyLess, typename StrategyGreater,
std::size_t DimensionCount
>
struct nsphere_loop
<
StrategyLess, StrategyGreater,
DimensionCount, DimensionCount
>
{
@@ -112,13 +101,11 @@ namespace dispatch
// Box + Nsphere -> new box containing also nsphere
template
<
typename BoxOut, typename NSphere,
typename StrategyLess, typename StrategyGreater
typename BoxOut, typename NSphere
>
struct expand<BoxOut, NSphere, StrategyLess, StrategyGreater, box_tag, nsphere_tag>
struct expand<BoxOut, NSphere, box_tag, nsphere_tag>
: detail::expand::nsphere_loop
<
StrategyLess, StrategyGreater,
0, dimension<NSphere>::type::value
>
{};

View File

@@ -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

View File

@@ -0,0 +1,375 @@
// Boost.Geometry
// 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_FORMULAS_CROSS_TRACK_GEO_HPP
#define BOOST_GEOMETRY_FORMULAS_CROSS_TRACK_GEO_HPP
#include <boost/geometry/formulas/result_direct.hpp>
#include <boost/geometry/formulas/mean_radius.hpp>
#ifndef BOOST_GEOMETRY_DETAIL_POINT_SEGMENT_DISTANCE_MAX_STEPS
#define BOOST_GEOMETRY_DETAIL_POINT_SEGMENT_DISTANCE_MAX_STEPS 100
#endif
/*!
\brief Algorithm to compute the distance between a segment and a point using
direct and inverse geodesic problems as subroutines. The algorithm
approximates the distance by an iterative Newton method.
\see C.F.F.Karney - Geodesics on an ellipsoid of revolution,
https://arxiv.org/abs/1102.1215
*/
namespace boost { namespace geometry { namespace formula
{
template
<
typename CT,
typename Units,
template <typename, bool, bool, bool, bool ,bool> class Inverse,
template <typename, bool, bool, bool, bool> class Direct,
bool EnableClosestPoint = false
>
class distance_point_segment{
public:
typedef Inverse<CT, true, false, false, true, true> inverse_distance_quantities_type;
typedef Inverse<CT, true, false, false, false, false> inverse_distance_type;
typedef Inverse<CT, false, true, false, false, false> inverse_azimuth_type;
typedef Inverse<CT, false, true, true, false, false> inverse_azimuth_reverse_type;
typedef Direct<CT, true, false, false, false> direct_distance_type;
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;
};
result_distance_point_segment
static inline non_iterative_case(CT lon, CT lat, CT distance)
{
result_distance_point_segment result;
result.distance = distance;
if (EnableClosestPoint)
{
result.closest_point_lon = lon;
result.closest_point_lat = lat;
}
return result;
}
template <typename Spheroid>
result_distance_point_segment
static inline non_iterative_case(CT lon1, CT lat1, //p1
CT lon2, CT lat2, //p2
Spheroid const& spheroid)
{
CT distance = inverse_distance_quantities_type::apply(lon1, lat1,
lon2, lat2,
spheroid).distance;
return non_iterative_case(lon1, lat1, distance);
}
template <typename T>
T static inline normalize(T 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 Spheroid>
result_distance_point_segment
static inline apply(CT lon1, CT lat1, //p1
CT lon2, CT lat2, //p2
CT lon3, CT lat3, //query point p3
Spheroid const& spheroid)
{
CT const earth_radius = geometry::formula::mean_radius<CT>(spheroid);
result_distance_point_segment result;
// Constants
CT const f = 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
//TODO: use the meridian distance when it'll be available
if (math::equals(lat1, c0) && math::equals(lat2, c0))
{
#ifdef BOOST_GEOMETRY_DISTANCE_POINT_SEGMENT_DEBUG
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);
}
CT d1 = inverse_distance_type::apply(lon1, lat1,
lon3, lat3, spheroid).distance;
CT d3 = inverse_distance_type::apply(lon1, lat1,
lon2, lat2, spheroid).distance;
if (geometry::math::equals(d3, c0))
{
return non_iterative_case(lon1, lat2, d1);
}
CT d2 = inverse_distance_type::apply(lon2, lat2,
lon3, lat3, spheroid).distance;
// 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_DISTANCE_POINT_SEGMENT_DEBUG
std::cout << "point on segment" << std::endl;
#endif
return non_iterative_case(lon3, lat3, c0);
}
CT projection1 = cos( a312 ) * d1 / d3;
#ifdef BOOST_GEOMETRY_DISTANCE_POINT_SEGMENT_DEBUG
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_DISTANCE_POINT_SEGMENT_DEBUG
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_DISTANCE_POINT_SEGMENT_DEBUG
std::cout << "a21=" << a21 * math::r2d<CT>() << std::endl;
std::cout << "a23=" << a13 * 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_DISTANCE_POINT_SEGMENT_DEBUG
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_DISTANCE_POINT_SEGMENT_DEBUG
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_DISTANCE_POINT_SEGMENT_DEBUG
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_DISTANCE_POINT_SEGMENT_DEBUG
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_DISTANCE_POINT_SEGMENT_DEBUG
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;
}
};
}}} // namespace boost::geometry::formula
#endif // BOOST_GEOMETRY_FORMULAS_CROSS_TRACK_GEO_HPP

View File

@@ -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);

View File

@@ -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

View File

@@ -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

View File

@@ -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>
@@ -52,6 +55,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;
};

View File

@@ -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);
}
};
@@ -473,8 +497,12 @@ class wkt_manipulator
{
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 = ! boost::is_same<typename tag<Geometry>::type, ring_tag>::value)
: m_geometry(g)
, m_force_closure(force_closure)
{}
template <typename Char, typename Traits>
@@ -482,13 +510,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;
};
/*!

View File

@@ -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

View File

@@ -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);
}
};

View File

@@ -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
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
typedef typename coordinate_system<Point>::type cs_t;
typedef math::detail::constants_on_spheroid
template
<
typename Point,
typename PointOfSegment,
typename CalculationType,
typename CSTag = typename tag_cast
<
typename cs_tag<Point>::type,
spherical_tag
>::type
>
struct winding_base_type
{
BOOST_MPL_ASSERT_MSG(false,
NOT_IMPLEMENTED_FOR_THIS_COORDINATE_SYSTEM,
(CSTag));
};
template <typename Point, typename PointOfSegment, typename CalculationType>
struct winding_base_type<Point, PointOfSegment, CalculationType, cartesian_tag>
{
typedef within::cartesian_winding<Point, PointOfSegment, CalculationType> type;
};
template <typename Point, typename PointOfSegment, typename CalculationType>
struct winding_base_type<Point, PointOfSegment, CalculationType, spherical_tag>
{
typedef within::detail::spherical_winding_base
<
CalculationType,
typename cs_t::units
> constants;
static inline CalculationType apply()
{
return constants::half_period() / CalculationType(180);
}
Point,
PointOfSegment,
typename strategy::side::services::default_strategy
<
typename cs_tag<Point>::type
>::type,
CalculationType
> type;
};
// 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
{
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>
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) ;
}
};
template <typename Point,
typename CalculationType,
typename CSTag = typename cs_tag<Point>::type>
struct winding_check_touch
{
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;
}
};
// 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
{
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
// 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
{
typedef typename select_calculation_type
: public 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
{
typedef typename within::detail::winding_base_type
<
Point, PointOfSegment, CalculationType
>::type base_t;
public:
typedef typename SideStrategy::envelope_strategy_type envelope_strategy_type;
winding() {}
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();
}
winding()
template <typename Model>
explicit winding(Model const& model)
: base_t(model)
{}
explicit winding(SideStrategy const& side_strategy)
: m_side_strategy(side_strategy)
{}
// 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

View File

@@ -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;
};

Some files were not shown because too many files have changed in this diff Show More