Merge branch 'develop' of https://github.com/boostorg/geometry into feature/is_simple

This commit is contained in:
Menelaos Karavelas
2014-04-28 18:11:38 +03:00
168 changed files with 8167 additions and 5096 deletions

View File

@@ -21,6 +21,13 @@ def run_command(command):
if os.system(command) != 0:
raise Exception("Error running %s" % command)
def remove_all_files(dir):
if os.path.exists(dir):
for f in os.listdir(dir):
os.remove(dir+f)
remove_all_files("xml/")
run_command("doxygen Doxyfile")
run_command(cmd % ("classboost_1_1geometry_1_1index_1_1rtree", "rtree"))
run_command(cmd % ("group__rtree__functions", "rtree_functions"))

View File

@@ -17,8 +17,10 @@ exe interprocess : interprocess.cpp /boost/thread//boost_thread
:
<toolset>acc:<linkflags>-lrt
<toolset>acc-pa_risc:<linkflags>-lrt
<toolset>gcc-mingw:<linkflags>"-lole32 -loleaut32 -lpsapi -ladvapi32"
<host-os>hpux,<toolset>gcc:<linkflags>"-Wl,+as,mpas"
# <toolset>gcc-mingw:<linkflags>"-lole32 -loleaut32 -lpsapi -ladvapi32"
<toolset>gcc,<target-os>windows:<linkflags>"-lole32 -loleaut32 -lpsapi -ladvapi32"
<host-os>windows,<toolset>clang:<linkflags>"-lole32 -loleaut32 -lpsapi -ladvapi32"
:
<threading>multi
: # requirements

View File

@@ -40,9 +40,14 @@ def run_command(command):
if os.system(command) != 0:
raise Exception("Error running %s" % command)
def remove_all_files(dir):
if os.path.exists(dir):
for f in os.listdir(dir):
os.remove(dir+f)
def call_doxygen():
os.chdir("doxy");
run_command("rm -f doxygen_output/xml/*.xml")
os.chdir("doxy")
remove_all_files("doxygen_output/xml/")
run_command(doxygen_cmd)
os.chdir("..")

View File

@@ -1,7 +1,12 @@
[/============================================================================
Boost.Geometry (aka GGL, Generic Geometry Library)
Copyright (c) 2011-2012 Barend Gehrels, Amsterdam, the Netherlands.
Copyright (c) 2011-2014 Barend Gehrels, Amsterdam, the Netherlands.
This file was modified by Oracle on 2014.
Modifications copyright (c) 2014, Oracle and/or its affiliates.
Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
Use, modification and distribution is subject to the Boost Software License,
Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -14,6 +19,8 @@
[[__2dim__][All combinations of: box, ring, polygon, multi_polygon]]
[[__1dim__ / __2dim__][A combinations of a (multi) linestring with a (multi) polygon
results in a collection of linestrings]]
[[__1dim__][All combinations of: linestring, multi_linestring; results in a collection of linestrings]]
[[__0dim__][All combinations of: point, multi_point; results in a collection of points]]
[[__other__][__nyiversion__]]
[[__sph__][__nyiversion__]]
[[Three dimensional][__nyiversion__]]

View File

@@ -27,11 +27,15 @@
* [@https://svn.boost.org/trac/boost/ticket/9245 9245] Check for process errors in make_qbk.py
* [@https://svn.boost.org/trac/boost/ticket/9081 9081] Booleans create self-intersecting polygons from non-self-intersecting polygons
* [@https://svn.boost.org/trac/boost/ticket/8310 8310] Wrong results with overlapping polygons (fixed using point_on_surface for disjoint)
* [@https://svn.boost.org/trac/boost/ticket/9871 9871] Remove spike in polygon with only a spike
[*Bugfixes]
* intersects(polygon) could return a self-intersection-point for its closing point, fixed
[*Solved tickets]
* [@https://svn.boost.org/trac/boost/ticket/9563 9563] (Sym)difference not successful, fixed by rescaling to robust type
[/=================]
[heading Boost 1.55]

View File

@@ -281,13 +281,18 @@ void test_all()
test_one<multi_polygon_type, buf::join_round, buf::end_skip, polygon_type>("rt_d", rt_d, 18.8726, 0.3);
test_one<multi_polygon_type, buf::join_miter, buf::end_skip, polygon_type>("rt_d", rt_d, 19.8823, 0.3);
test_one<multi_polygon_type, buf::join_round, buf::end_skip, polygon_type>("rt_e", rt_e, 14.1866, 0.3);
#if ! defined(BOOST_GEOMETRY_RESCALE_TO_ROBUST)
test_one<multi_polygon_type, buf::join_miter, buf::end_skip, polygon_type>("rt_e", rt_e, 15.1198, 0.3);
// This does not add anything: test_one<multi_polygon_type, buf::join_round, buf::end_skip, polygon_type>("rt_f", rt_f, 4.28937, 0.3);
test_one<multi_polygon_type, buf::join_miter, buf::end_skip, polygon_type>("rt_f", rt_f, 4.60853, 0.3);
#endif
test_one<multi_polygon_type, buf::join_round, buf::end_skip, polygon_type>("rt_g1", rt_g1, 24.719, 1.0);
#if ! defined(BOOST_GEOMETRY_RESCALE_TO_ROBUST)
test_one<multi_polygon_type, buf::join_miter, buf::end_skip, polygon_type>("rt_g1", rt_g1, 30.3137, 1.0);
test_one<multi_polygon_type, buf::join_miter, buf::end_skip, polygon_type>("rt_g2", rt_g2, 18.5711, 1.0);
#endif
test_one<multi_polygon_type, buf::join_miter, buf::end_skip, polygon_type>("rt_g3", rt_g3, 16.5711, 1.0);
test_one<multi_polygon_type, buf::join_round, buf::end_skip, polygon_type>("rt_h", rt_h, 47.6012, 1.0);
@@ -299,13 +304,17 @@ void test_all()
test_one<multi_polygon_type, buf::join_round, buf::end_skip, polygon_type>("rt_k", rt_k, 42.0092, 1.0);
test_one<multi_polygon_type, buf::join_miter, buf::end_skip, polygon_type>("rt_k", rt_k, 48.0563, 1.0);
// This does not add anything: test_one<multi_polygon_type, buf::join_round, buf::end_skip, polygon_type>("rt_l", rt_l, 14.1074, 1.0);
#if ! defined(BOOST_GEOMETRY_RESCALE_TO_ROBUST)
test_one<multi_polygon_type, buf::join_miter, buf::end_skip, polygon_type>("rt_l", rt_l, 19.3995, 1.0);
#endif
test_one<multi_polygon_type, buf::join_round, buf::end_skip, polygon_type>("rt_m1", rt_m1, 14.1074, 1.0);
#if ! defined(BOOST_GEOMETRY_RESCALE_TO_ROBUST)
test_one<multi_polygon_type, buf::join_miter, buf::end_skip, polygon_type>("rt_m1", rt_m1, 19.4853, 1.0);
test_one<multi_polygon_type, buf::join_miter, buf::end_skip, polygon_type>("rt_m2", rt_m2, 21.4853, 1.0);
// This does not add anything: test_one<multi_polygon_type, buf::join_round, buf::end_skip, polygon_type>("rt_n", rt_n, 14.1074, 1.0);
test_one<multi_polygon_type, buf::join_miter, buf::end_skip, polygon_type>("rt_n", rt_n, 18.4853, 1.0);
#endif
test_one<multi_polygon_type, buf::join_round, buf::end_skip, polygon_type>("rt_o1", rt_o1, 17.536, 1.0);
test_one<multi_polygon_type, buf::join_miter, buf::end_skip, polygon_type>("rt_o1", rt_o1, 20.9142, 1.0);
@@ -323,7 +332,10 @@ void test_all()
test_one<multi_polygon_type, buf::join_miter, buf::end_skip, polygon_type>("rt_p7", rt_p7, 26.2279, 1.0);
test_one<multi_polygon_type, buf::join_miter, buf::end_skip, polygon_type>("rt_p8", rt_p8, 29.0563, 1.0);
test_one<multi_polygon_type, buf::join_miter, buf::end_skip, polygon_type>("rt_p9", rt_p9, 26.1421, 1.0);
#if ! defined(BOOST_GEOMETRY_RESCALE_TO_ROBUST)
test_one<multi_polygon_type, buf::join_miter, buf::end_skip, polygon_type>("rt_p10", rt_p10, 23.3995, 1.0);
#endif
test_one<multi_polygon_type, buf::join_miter, buf::end_skip, polygon_type>("rt_p11", rt_p11, 28.7426, 1.0);
test_one<multi_polygon_type, buf::join_miter, buf::end_skip, polygon_type>("rt_p12", rt_p12, 22.5711, 1.0);
test_one<multi_polygon_type, buf::join_miter, buf::end_skip, polygon_type>("rt_p13", rt_p13, 19.9142, 1.0);
@@ -340,10 +352,14 @@ void test_all()
test_one<multi_polygon_type, buf::join_miter, buf::end_skip, polygon_type>("rt_q1", rt_q1, 27, 1.0);
test_one<multi_polygon_type, buf::join_miter, buf::end_skip, polygon_type>("rt_q2", rt_q2, 26.4853, 1.0);
#if ! defined(BOOST_GEOMETRY_RESCALE_TO_ROBUST)
test_one<multi_polygon_type, buf::join_miter, buf::end_skip, polygon_type>("rt_r", rt_r, 21.0761, 1.0);
#endif
test_one<multi_polygon_type, buf::join_miter, buf::end_skip, polygon_type>("rt_s1", rt_s1, 20.4853, 1.0);
test_one<multi_polygon_type, buf::join_miter, buf::end_skip, polygon_type>("rt_s2", rt_s2, 24.6495, 1.0);
#if ! defined(BOOST_GEOMETRY_RESCALE_TO_ROBUST)
test_one<multi_polygon_type, buf::join_miter, buf::end_skip, polygon_type>("rt_t", rt_t, 15.6569, 1.0);
#endif
}

View File

@@ -138,9 +138,13 @@ void test_all()
test_one<polygon_type, buf::join_round, buf::end_skip, polygon_type>("tipped_aitch9", tipped_aitch, 76.6457, 0.9);
test_one<polygon_type, buf::join_round, buf::end_skip, polygon_type>("tipped_aitch13", tipped_aitch, 90.641, 1.3);
#if ! defined(BOOST_GEOMETRY_RESCALE_TO_ROBUST)
test_one<polygon_type, buf::join_miter, buf::end_skip, polygon_type>("snake4", snake, 64.44, 0.4);
#endif
test_one<polygon_type, buf::join_miter, buf::end_skip, polygon_type>("snake5", snake, 72, 0.5);
#if ! defined(BOOST_GEOMETRY_RESCALE_TO_ROBUST)
test_one<polygon_type, buf::join_miter, buf::end_skip, polygon_type>("snake6", snake, 75.44, 0.6);
#endif
test_one<polygon_type, buf::join_miter, buf::end_skip, polygon_type>("snake16", snake, 114.24, 1.6);
test_one<polygon_type, buf::join_miter, buf::end_skip, polygon_type>("funnelgate2", funnelgate, 120.982, 2);
@@ -347,4 +351,4 @@ select
from bowl
*/
*/

View File

@@ -53,12 +53,14 @@
#if defined(TEST_WITH_SVG)
#include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp>
template <typename Geometry, typename Mapper>
void post_map(Geometry const& geometry, Mapper& mapper)
template <typename Geometry, typename Mapper, typename RescalePolicy>
void post_map(Geometry const& geometry, Mapper& mapper, RescalePolicy const& rescale_policy)
{
typedef typename bg::point_type<Geometry>::type point_type;
typedef bg::detail::overlay::turn_info
<
typename bg::point_type<Geometry>::type
point_type,
typename bg::segment_ratio_type<point_type, RescalePolicy>::type
> turn_info;
std::vector<turn_info> turns;
@@ -67,7 +69,7 @@ void post_map(Geometry const& geometry, Mapper& mapper)
bg::self_turns
<
bg::detail::overlay::assign_null_policy
>(geometry, turns, policy);
>(geometry, rescale_policy, turns, policy);
BOOST_FOREACH(turn_info const& turn, turns)
{
@@ -218,12 +220,20 @@ void test_buffer(std::string const& caseid, Geometry const& geometry,
>
distance_strategy(distance_left, distance_right);
typedef typename bg::point_type<Geometry>::type point_type;
typedef typename bg::rescale_policy_type<point_type>::type
rescale_policy_type;
rescale_policy_type rescale_policy
= bg::get_rescale_policy<rescale_policy_type>(geometry);
std::vector<GeometryOut> buffered;
bg::buffer_inserter<GeometryOut>(geometry, std::back_inserter(buffered),
distance_strategy,
join_strategy,
end_strategy
end_strategy,
rescale_policy
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
, mapper
#endif
@@ -299,7 +309,7 @@ void test_buffer(std::string const& caseid, Geometry const& geometry,
{
mapper.map(polygon, "opacity:0.4;fill:rgb(255,255,128);stroke:rgb(0,0,0);stroke-width:3");
//mapper.map(polygon, "opacity:0.2;fill:none;stroke:rgb(255,0,0);stroke-width:3");
post_map(polygon, mapper);
post_map(polygon, mapper, rescale_policy);
}
#endif
}

View File

@@ -0,0 +1,64 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2014 Bruno Lalande, Paris, France.
// Copyright (c) 2014 Mateusz Loskot, London, UK.
// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_GET_MAX_SIZE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_GET_MAX_SIZE_HPP
#include <cstddef>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/util/math.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
template <typename Box, std::size_t Dimension>
struct get_max_size_box
{
static inline typename coordinate_type<Box>::type apply(Box const& box)
{
typename coordinate_type<Box>::type s
= geometry::math::abs(geometry::get<1, Dimension>(box) - geometry::get<0, Dimension>(box));
return (std::max)(s, get_max_size_box<Box, Dimension - 1>::apply(box));
}
};
template <typename Box>
struct get_max_size_box<Box, 0>
{
static inline typename coordinate_type<Box>::type apply(Box const& box)
{
return geometry::math::abs(geometry::get<1, 0>(box) - geometry::get<0, 0>(box));
}
};
// This might be implemented later on for other geometries too.
// Not dispatched yet.
template <typename Box>
inline typename coordinate_type<Box>::type get_max_size(Box const& box)
{
return get_max_size_box<Box, dimension<Box>::value - 1>::apply(box);
}
} // namespace detail
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_GET_MAX_SIZE_HPP

View File

@@ -16,7 +16,10 @@
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
#include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp>
#include <boost/geometry/algorithms/detail/rescale.hpp>
#include <boost/geometry/policies/robustness/robust_point_type.hpp>
#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
#include <boost/geometry/policies/robustness/get_rescale_policy.hpp>
#include <boost/geometry/multi/algorithms/detail/overlay/self_turn_points.hpp>
@@ -57,15 +60,19 @@ namespace detail { namespace overlay
{
template <typename Geometry, typename RescalePolicy>
inline bool has_self_intersections(Geometry const& geometry, RescalePolicy const& rescale_policy)
template <typename Geometry, typename RobustPolicy>
inline bool has_self_intersections(Geometry const& geometry, RobustPolicy const& robust_policy)
{
typedef typename point_type<Geometry>::type point_type;
typedef detail::overlay::turn_info<point_type> turn_info;
typedef turn_info
<
point_type,
typename segment_ratio_type<point_type, RobustPolicy>::type
> turn_info;
std::deque<turn_info> turns;
detail::disjoint::disjoint_interrupt_policy policy;
geometry::self_turns<detail::overlay::assign_null_policy>(geometry, rescale_policy, turns, policy);
geometry::self_turns<detail::overlay::assign_null_policy>(geometry, robust_policy, turns, policy);
#ifdef BOOST_GEOMETRY_DEBUG_HAS_SELF_INTERSECTIONS
bool first = true;
@@ -115,7 +122,14 @@ inline bool has_self_intersections(Geometry const& geometry, RescalePolicy const
template <typename Geometry>
inline bool has_self_intersections(Geometry const& geometry)
{
return has_self_intersections(geometry, detail::no_rescale_policy());
typedef typename geometry::point_type<Geometry>::type point_type;
typedef typename geometry::rescale_policy_type<point_type>::type
rescale_policy_type;
rescale_policy_type robust_policy
= geometry::get_rescale_policy<rescale_policy_type>(geometry);
return has_self_intersections(geometry, robust_policy);
}

View File

@@ -0,0 +1,128 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2011-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_SIDE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_SIDE_HPP
#include <boost/geometry/algorithms/detail/recalculate.hpp>
#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp>
#include <boost/geometry/geometries/segment.hpp>
#include <boost/geometry/strategies/intersection_result.hpp>
#include <boost/geometry/strategies/side.hpp>
#include <boost/geometry/strategies/cartesian/cart_intersect.hpp>
#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
namespace boost { namespace geometry
{
namespace detail { namespace intersection_side
{
//! Calculates the side (left=1,right=-1,collinear=0) of the intersection point
//! of p/q (if any) with respect to segment s.
//! This is not done by calculating IP p/q and calling side, because that is
//! (even if robust_policy is used) not robust: the IP can be rounded off.
//! So it is done by investigating the sides of the segments, and calculating
//! the segment_ratios of the IP and check which side it is.
//! Return value is conform geometry::side
//! Currently all points are of same type
//! Even if there is no IP at all, a side is returned. IP is not calculated on
//! itself
template <typename Point, typename RobustPolicy>
inline int intersection_side(Point const& pi, Point const& pj,
Point const& qi, Point const& qj,
Point const& si, Point const& sj,
RobustPolicy const& robust_policy)
{
typedef typename geometry::robust_point_type
<
Point,
RobustPolicy
>::type robust_point_type;
typedef typename geometry::segment_ratio_type
<
Point,
RobustPolicy
>::type segment_ratio_type;
robust_point_type pi_rob, pj_rob, qi_rob, qj_rob, si_rob, sj_rob;
geometry::recalculate(pi_rob, pi, robust_policy);
geometry::recalculate(pj_rob, pj, robust_policy);
geometry::recalculate(qi_rob, qi, robust_policy);
geometry::recalculate(qj_rob, qj, robust_policy);
geometry::recalculate(si_rob, si, robust_policy);
geometry::recalculate(sj_rob, sj, robust_policy);
typedef typename geometry::strategy::side::services::default_strategy
<
typename geometry::cs_tag<robust_point_type>::type
>::type side_strategy;
int const side_pi = side_strategy::apply(pi_rob, si_rob, sj_rob);
int const side_pj = side_strategy::apply(pj_rob, si_rob, sj_rob);
if (side_pi == side_pj)
{
return side_pi;
}
int const side_qi = side_strategy::apply(qi_rob, si_rob, sj_rob);
int const side_qj = side_strategy::apply(qj_rob, si_rob, sj_rob);
if (side_qi == side_qj)
{
// Same here, see comment above
return side_qi;
}
typedef model::referring_segment<const Point> segment_type;
segment_type p(pi, pj);
segment_type q(qi, qj);
segment_type s(si, sj);
// No segment lies on the left or right or completely collinear
// Relate segments p // q and p // s, don't calculate IP's but just return
// the ratios. Both ratios called "robust_ra" are measured on p and can be
// related.
fraction_type<segment_ratio_type> ratio_p_wrt_q
= strategy::intersection::relate_cartesian_segments
<
policies::relate::segments_intersection_ratios
<
fraction_type<segment_ratio_type>
>
>::apply(p, q, robust_policy, pi_rob, pj_rob, qi_rob, qj_rob);
fraction_type<segment_ratio_type> ratio_p_wrt_s
= strategy::intersection::relate_cartesian_segments
<
policies::relate::segments_intersection_ratios
<
fraction_type<segment_ratio_type>
>
>::apply(p, s, robust_policy, pi_rob, pj_rob, si_rob, sj_rob);
return
// Closer to the segment start point of p -> side of pi
ratio_p_wrt_q.robust_ra < ratio_p_wrt_s.robust_ra ? side_pi
// Ratios are equal, IP must be exactly on the segment
: ratio_p_wrt_q.robust_ra == ratio_p_wrt_s.robust_ra ? 0
// ratio p wrt q is larger than ratio p wrt s
// So: close to the segment end point of p -> side of pj
: side_pj;
}
}} // namespace detail::intersection_side
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_SIDE_HPP

View File

@@ -24,35 +24,118 @@ namespace boost { namespace geometry
namespace detail { namespace overlay
{
template <typename Range, typename Point>
inline void append_no_dups_or_spikes(Range& range, Point const& point)
// TODO: move this / rename this
template <typename Point1, typename Point2, typename RobustPolicy>
inline bool points_equal_or_close(Point1 const& point1,
Point2 const& point2,
RobustPolicy const& robust_policy)
{
if (detail::equals::equals_point_point(point1, point2))
{
return true;
}
if (! RobustPolicy::enabled)
{
return false;
}
// Try using specified robust policy
typedef typename geometry::robust_point_type
<
Point1,
RobustPolicy
>::type robust_point_type;
robust_point_type point1_rob, point2_rob;
geometry::recalculate(point1_rob, point1, robust_policy);
geometry::recalculate(point2_rob, point2, robust_policy);
return detail::equals::equals_point_point(point1_rob, point2_rob);
}
template <typename Range, typename Point, typename RobustPolicy>
inline void append_no_dups_or_spikes(Range& range, Point const& point,
RobustPolicy const& robust_policy)
{
#ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION
std::cout << " add: ("
<< geometry::get<0>(point) << ", " << geometry::get<1>(point) << ")"
<< std::endl;
#endif
// The code below thies condition checks all spikes/dups
// for geometries >= 3 points.
// So we have to check the first potential duplicate differently
if (boost::size(range) == 1
&& points_equal_or_close(*(boost::begin(range)), point, robust_policy))
{
return;
}
traits::push_back<Range>::apply(range, point);
// If a point is equal, or forming a spike, remove the pen-ultimate point because this one caused the spike.
// If so, the now-new-pen-ultimate point can again cause a spike (possibly at a corner). So keep doing this.
// Besides spikes it will also avoid duplicates.
// If a point is equal, or forming a spike, remove the pen-ultimate point
// because this one caused the spike.
// If so, the now-new-pen-ultimate point can again cause a spike
// (possibly at a corner). So keep doing this.
// Besides spikes it will also avoid adding duplicates.
while(boost::size(range) >= 3
&& point_is_spike_or_equal(point, *(boost::end(range) - 3), *(boost::end(range) - 2)))
&& point_is_spike_or_equal(point,
*(boost::end(range) - 3),
*(boost::end(range) - 2),
robust_policy))
{
// Use the Concept/traits, so resize and append again
traits::resize<Range>::apply(range, boost::size(range) - 2);
traits::push_back<Range>::apply(range, point);
}
}
// There might still be one duplicate not catched by the condition above
if (boost::size(range) == 2
&& geometry::detail::equals::equals_point_point(*boost::begin(range), point))
template <typename Range, typename RobustPolicy>
inline void clean_closing_dups_and_spikes(Range& range,
RobustPolicy const& robust_policy)
{
int const minsize
= core_detail::closure::minimum_ring_size
<
geometry::closure<Range>::value
>::value;
if (boost::size(range) <= minsize)
{
traits::clear<Range>::apply(range);
traits::push_back<Range>::apply(range, point);
return;
}
typedef typename boost::range_iterator<Range>::type iterator_type;
const bool closed = geometry::closure<Range>::value == geometry::closed;
bool found = false;
do
{
found = false;
iterator_type first = boost::begin(range);
iterator_type second = first + 1;
iterator_type ultimate = boost::end(range) - 1;
if (closed)
{
ultimate--;
}
// Check if closing point is a spike (this is so if the second point is
// considered as a spike w.r.t. the last segment)
if (point_is_spike_or_equal(*second, *ultimate, *first, robust_policy))
{
range.erase(first);
if (closed)
{
// Remove closing last point
traits::resize<Range>::apply(range, boost::size(range) - 1);
// Add new closing point
traits::push_back<Range>::apply(range, *boost::begin(range));
}
found = true;
}
} while(found && boost::size(range) > minsize);
}

View File

@@ -79,14 +79,14 @@ class backtrack_check_self_intersections
public :
typedef state state_type;
template <typename Operation, typename Rings, typename Turns, typename RescalePolicy>
template <typename Operation, typename Rings, typename Ring, typename Turns, typename RobustPolicy>
static inline void apply(std::size_t size_at_start,
Rings& rings, typename boost::range_value<Rings>::type& ring,
Rings& rings, Ring& ring,
Turns& turns, Operation& operation,
std::string const& ,
Geometry1 const& geometry1,
Geometry2 const& geometry2,
RescalePolicy const& rescale_policy,
RobustPolicy const& robust_policy,
state_type& state
)
{
@@ -96,8 +96,8 @@ public :
if (! state.m_checked)
{
state.m_checked = true;
has_self_intersections(geometry1, rescale_policy);
has_self_intersections(geometry2, rescale_policy);
has_self_intersections(geometry1, robust_policy);
has_self_intersections(geometry2, robust_policy);
}
// Make bad output clean

View File

@@ -1,64 +0,0 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CALCULATE_DISTANCE_POLICY_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CALCULATE_DISTANCE_POLICY_HPP
#include <boost/geometry/algorithms/comparable_distance.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace overlay
{
/*!
\brief Policy calculating distance
\details get_turn_info has an optional policy to get some
extra information.
This policy calculates the distance (using default distance strategy)
*/
struct calculate_distance_policy
{
static bool const include_no_turn = false;
static bool const include_degenerate = false;
static bool const include_opposite = false;
template
<
typename Info,
typename Point1,
typename Point2,
typename IntersectionInfo,
typename DirInfo
>
static inline void apply(Info& info, Point1 const& p1, Point2 const& p2,
IntersectionInfo const&, DirInfo const&)
{
info.operations[0].enriched.distance
= geometry::comparable_distance(info.point, p1);
info.operations[1].enriched.distance
= geometry::comparable_distance(info.point, p2);
}
};
}} // namespace detail::overlay
#endif //DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CALCULATE_DISTANCE_POLICY_HPP

View File

@@ -22,6 +22,7 @@
#include <boost/geometry/core/ring_type.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/iterators/ever_circling_iterator.hpp>
#include <boost/geometry/views/closeable_view.hpp>
@@ -38,34 +39,37 @@ namespace detail { namespace copy_segments
{
template
<
typename Ring,
bool Reverse,
typename SegmentIdentifier,
typename RangeOut
>
template<bool Reverse>
struct copy_segments_ring
{
typedef typename closeable_view
template
<
typename Ring,
typename SegmentIdentifier,
typename RobustPolicy,
typename RangeOut
>
static inline void apply(Ring const& ring,
SegmentIdentifier const& seg_id, int to_index,
RobustPolicy const& robust_policy,
RangeOut& current_output)
{
typedef typename closeable_view
<
Ring const,
closure<Ring>::value
>::type cview_type;
typedef typename reversible_view
typedef typename reversible_view
<
cview_type const,
Reverse ? iterate_reverse : iterate_forward
>::type rview_type;
typedef typename boost::range_iterator<rview_type const>::type iterator;
typedef geometry::ever_circling_iterator<iterator> ec_iterator;
typedef typename boost::range_iterator<rview_type const>::type iterator;
typedef geometry::ever_circling_iterator<iterator> ec_iterator;
static inline void apply(Ring const& ring,
SegmentIdentifier const& seg_id, int to_index,
RangeOut& current_output)
{
cview_type cview(ring);
rview_type view(cview);
@@ -93,27 +97,27 @@ struct copy_segments_ring
for (size_type i = 0; i < count; ++i, ++it)
{
detail::overlay::append_no_dups_or_spikes(current_output, *it);
detail::overlay::append_no_dups_or_spikes(current_output, *it, robust_policy);
}
}
};
template
<
typename LineString,
bool Reverse,
typename SegmentIdentifier,
typename RangeOut
>
template<bool Reverse>
struct copy_segments_linestring
{
typedef typename boost::range_iterator<LineString const>::type iterator;
template
<
typename LineString,
typename SegmentIdentifier,
typename RobustPolicy,
typename RangeOut
>
static inline void apply(LineString const& ls,
SegmentIdentifier const& seg_id, int to_index,
RobustPolicy const& robust_policy,
RangeOut& current_output)
{
typedef typename boost::range_iterator<LineString const>::type iterator;
int const from_index = seg_id.segment_index + 1;
// Sanity check
@@ -129,54 +133,54 @@ struct copy_segments_linestring
for (size_type i = 0; i < count; ++i, ++it)
{
detail::overlay::append_no_dups_or_spikes(current_output, *it);
detail::overlay::append_no_dups_or_spikes(current_output, *it,
robust_policy);
}
}
};
template
<
typename Polygon,
bool Reverse,
typename SegmentIdentifier,
typename RangeOut
>
template<bool Reverse>
struct copy_segments_polygon
{
template
<
typename Polygon,
typename SegmentIdentifier,
typename RobustPolicy,
typename RangeOut
>
static inline void apply(Polygon const& polygon,
SegmentIdentifier const& seg_id, int to_index,
RobustPolicy const& robust_policy,
RangeOut& current_output)
{
// Call ring-version with the right ring
copy_segments_ring
<
typename geometry::ring_type<Polygon>::type,
Reverse,
SegmentIdentifier,
RangeOut
>::apply
(
seg_id.ring_index < 0
? geometry::exterior_ring(polygon)
: geometry::interior_rings(polygon)[seg_id.ring_index],
seg_id, to_index,
current_output
);
copy_segments_ring<Reverse>::apply
(
seg_id.ring_index < 0
? geometry::exterior_ring(polygon)
: geometry::interior_rings(polygon)[seg_id.ring_index],
seg_id, to_index,
robust_policy,
current_output
);
}
};
template
<
typename Box,
bool Reverse,
typename SegmentIdentifier,
typename RangeOut
>
template<bool Reverse>
struct copy_segments_box
{
template
<
typename Box,
typename SegmentIdentifier,
typename RobustPolicy,
typename RangeOut
>
static inline void apply(Box const& box,
SegmentIdentifier const& seg_id, int to_index,
RobustPolicy const& robust_policy,
RangeOut& current_output)
{
int index = seg_id.segment_index + 1;
@@ -195,7 +199,8 @@ struct copy_segments_box
// (see comments in ring-version)
for (int i = 0; i < count; i++, index++)
{
detail::overlay::append_no_dups_or_spikes(current_output, bp[index % 5]);
detail::overlay::append_no_dups_or_spikes(current_output,
bp[index % 5], robust_policy);
}
}
@@ -213,80 +218,33 @@ namespace dispatch
template
<
typename Tag,
typename GeometryIn,
bool Reverse,
typename SegmentIdentifier,
typename RangeOut
bool Reverse
>
struct copy_segments
{
BOOST_MPL_ASSERT_MSG
(
false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
, (types<GeometryIn>)
);
};
template
<
typename Ring,
bool Reverse,
typename SegmentIdentifier,
typename RangeOut
>
struct copy_segments<ring_tag, Ring, Reverse, SegmentIdentifier, RangeOut>
: detail::copy_segments::copy_segments_ring
<
Ring, Reverse, SegmentIdentifier, RangeOut
>
struct copy_segments : not_implemented<Tag>
{};
template
<
typename LineString,
bool Reverse,
typename SegmentIdentifier,
typename RangeOut
>
struct copy_segments<linestring_tag, LineString, Reverse, SegmentIdentifier, RangeOut>
: detail::copy_segments::copy_segments_linestring
<
LineString, Reverse, SegmentIdentifier, RangeOut
>
{};
template
<
typename Polygon,
bool Reverse,
typename SegmentIdentifier,
typename RangeOut
>
struct copy_segments<polygon_tag, Polygon, Reverse, SegmentIdentifier, RangeOut>
: detail::copy_segments::copy_segments_polygon
<
Polygon, Reverse, SegmentIdentifier, RangeOut
>
template<bool Reverse>
struct copy_segments<ring_tag, Reverse>
: detail::copy_segments::copy_segments_ring<Reverse>
{};
template
<
typename Box,
bool Reverse,
typename SegmentIdentifier,
typename RangeOut
>
struct copy_segments<box_tag, Box, Reverse, SegmentIdentifier, RangeOut>
: detail::copy_segments::copy_segments_box
<
Box, Reverse, SegmentIdentifier, RangeOut
>
template<bool Reverse>
struct copy_segments<linestring_tag, Reverse>
: detail::copy_segments::copy_segments_linestring<Reverse>
{};
template<bool Reverse>
struct copy_segments<polygon_tag, Reverse>
: detail::copy_segments::copy_segments_polygon<Reverse>
{};
template<bool Reverse>
struct copy_segments<box_tag, Reverse>
: detail::copy_segments::copy_segments_box<Reverse>
{};
} // namespace dispatch
@@ -303,10 +261,12 @@ template
bool Reverse,
typename Geometry,
typename SegmentIdentifier,
typename RobustPolicy,
typename RangeOut
>
inline void copy_segments(Geometry const& geometry,
SegmentIdentifier const& seg_id, int to_index,
RobustPolicy const& robust_policy,
RangeOut& range_out)
{
concept::check<Geometry const>();
@@ -314,11 +274,8 @@ inline void copy_segments(Geometry const& geometry,
dispatch::copy_segments
<
typename tag<Geometry>::type,
Geometry,
Reverse,
SegmentIdentifier,
RangeOut
>::apply(geometry, seg_id, to_index, range_out);
Reverse
>::apply(geometry, seg_id, to_index, robust_policy, range_out);
}

View File

@@ -30,6 +30,7 @@
#include <boost/geometry/algorithms/detail/overlay/get_relative_order.hpp>
#include <boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp>
#include <boost/geometry/algorithms/detail/zoom_to_robust.hpp>
#include <boost/geometry/policies/robustness/robust_type.hpp>
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
# include <boost/geometry/algorithms/detail/overlay/check_enrich.hpp>
#endif
@@ -79,9 +80,9 @@ template
bool Reverse1, bool Reverse2,
typename Strategy
>
struct sort_on_segment_and_distance
struct sort_on_segment_and_ratio
{
inline sort_on_segment_and_distance(TurnPoints const& turn_points
inline sort_on_segment_and_ratio(TurnPoints const& turn_points
, Geometry1 const& geometry1
, Geometry2 const& geometry2
, Strategy const& strategy
@@ -104,7 +105,7 @@ private :
typedef model::point
<
typename geometry::robust_type
typename detail::robust_type
<
typename select_coordinate_type<Geometry1, Geometry2>::type
>::type,
@@ -128,7 +129,7 @@ private :
geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
right.subject.other_id,
si, sj);
geometry::zoom_to_robust(pi, pj, ri, rj, si, sj,
detail::zoom_to_robust(pi, pj, ri, rj, si, sj,
pi_rob, pj_rob, ri_rob, rj_rob, si_rob, sj_rob);
}
@@ -157,9 +158,7 @@ public :
if (sl == sr)
{
// Both left and right are located on the SAME segment.
typedef typename geometry::coordinate_type<Geometry1>::type coordinate_type;
coordinate_type diff = geometry::math::abs(left.subject.enriched.distance - right.subject.enriched.distance);
if (diff < geometry::math::relaxed_epsilon<coordinate_type>(10))
if (left.subject.fraction == right.subject.fraction)
{
// First check "real" intersection (crosses)
// -> distance zero due to precision, solve it by sorting
@@ -173,13 +172,12 @@ public :
// Indicate that this is necessary.
*m_clustered = true;
return left.subject.enriched.distance < right.subject.enriched.distance;
return left.subject.fraction < right.subject.fraction;
}
}
return sl == sr
? left.subject.enriched.distance < right.subject.enriched.distance
? left.subject.fraction < right.subject.fraction
: sl < sr;
}
};
@@ -217,14 +215,14 @@ template
typename Container,
typename TurnPoints,
typename Geometry1, typename Geometry2,
typename RescalePolicy,
typename RobustPolicy,
typename Strategy
>
inline void enrich_sort(Container& operations,
TurnPoints& turn_points,
operation_type for_operation,
Geometry1 const& geometry1, Geometry2 const& geometry2,
RescalePolicy const& rescale_policy,
RobustPolicy const& robust_policy,
Strategy const& strategy)
{
typedef typename IndexType::type operations_type;
@@ -232,7 +230,7 @@ inline void enrich_sort(Container& operations,
bool clustered = false;
std::sort(boost::begin(operations),
boost::end(operations),
sort_on_segment_and_distance
sort_on_segment_and_ratio
<
TurnPoints,
IndexType,
@@ -262,8 +260,7 @@ inline void enrich_sort(Container& operations,
if (prev_op.seg_id == op.seg_id
&& (turn_points[prev->index].method != method_crosses
|| turn_points[it->index].method != method_crosses)
&& geometry::math::equals(prev_op.enriched.distance,
op.enriched.distance))
&& prev_op.fraction == op.fraction)
{
if (begin_cluster == boost::end(operations))
{
@@ -273,14 +270,14 @@ inline void enrich_sort(Container& operations,
else if (begin_cluster != boost::end(operations))
{
handle_cluster<IndexType, Reverse1, Reverse2>(begin_cluster, it, turn_points,
for_operation, geometry1, geometry2, rescale_policy, strategy);
for_operation, geometry1, geometry2, robust_policy, strategy);
begin_cluster = boost::end(operations);
}
}
if (begin_cluster != boost::end(operations))
{
handle_cluster<IndexType, Reverse1, Reverse2>(begin_cluster, it, turn_points,
for_operation, geometry1, geometry2, rescale_policy, strategy);
for_operation, geometry1, geometry2, robust_policy, strategy);
}
}
@@ -370,7 +367,7 @@ inline void enrich_assign(Container& operations,
std::cout << it->index
<< " meth: " << method_char(turn_points[it->index].method)
<< " seg: " << op.seg_id
<< " dst: " << boost::numeric_cast<double>(op.enriched.distance)
<< " dst: " << op.fraction // needs define
<< " op: " << operation_char(turn_points[it->index].operations[0].operation)
<< operation_char(turn_points[it->index].operations[1].operation)
<< " dsc: " << (turn_points[it->index].discarded ? "T" : "F")
@@ -453,13 +450,13 @@ template
bool Reverse1, bool Reverse2,
typename TurnPoints,
typename Geometry1, typename Geometry2,
typename RescalePolicy,
typename RobustPolicy,
typename Strategy
>
inline void enrich_intersection_points(TurnPoints& turn_points,
detail::overlay::operation_type for_operation,
Geometry1 const& geometry1, Geometry2 const& geometry2,
RescalePolicy const& rescale_policy,
RobustPolicy const& robust_policy,
Strategy const& strategy)
{
typedef typename boost::range_value<TurnPoints>::type turn_point_type;
@@ -514,7 +511,7 @@ inline void enrich_intersection_points(TurnPoints& turn_points,
<< mit->first << std::endl;
#endif
detail::overlay::enrich_sort<indexed_turn_operation, Reverse1, Reverse2>(mit->second, turn_points, for_operation,
geometry1, geometry2, rescale_policy, strategy);
geometry1, geometry2, robust_policy, strategy);
}
for (typename mapped_vector_type::iterator mit

View File

@@ -10,9 +10,6 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ENRICHMENT_INFO_HPP
#include <boost/geometry/strategies/distance.hpp>
namespace boost { namespace geometry
{
@@ -31,24 +28,10 @@ namespace detail { namespace overlay
template<typename P>
struct enrichment_info
{
typedef typename strategy::distance::services::return_type
<
typename strategy::distance::services::comparable_type
<
typename strategy::distance::services::default_strategy
<
point_tag,
P
>::type
>::type,
P, P
>::type distance_type;
inline enrichment_info()
: travels_to_vertex_index(-1)
, travels_to_ip_index(-1)
, next_ip_index(-1)
, distance(distance_type())
{}
// vertex to which is free travel after this IP,
@@ -61,8 +44,6 @@ struct enrichment_info
// index of next IP on this segment, -1 if there is no one
int next_ip_index;
distance_type distance; // distance-measurement from segment.first to IP
};

View File

@@ -157,15 +157,19 @@ struct action_selector<overlay_intersection>
typename LineStringOut,
typename LineString,
typename Point,
typename Operation
typename Operation,
typename RobustPolicy
>
static inline void enter(LineStringOut& current_piece,
LineString const& ,
segment_identifier& segment_id,
int , Point const& point,
Operation const& operation, OutputIterator& )
Operation const& operation,
RobustPolicy const& ,
OutputIterator& )
{
// On enter, append the intersection point and remember starting point
// TODO: we don't check on spikes for linestrings (?). Consider this.
detail::overlay::append_no_duplicates(current_piece, point);
segment_id = operation.seg_id;
}
@@ -176,17 +180,20 @@ struct action_selector<overlay_intersection>
typename LineStringOut,
typename LineString,
typename Point,
typename Operation
typename Operation,
typename RobustPolicy
>
static inline void leave(LineStringOut& current_piece,
LineString const& linestring,
segment_identifier& segment_id,
int index, Point const& point,
Operation const& , OutputIterator& out)
Operation const& ,
RobustPolicy const& robust_policy,
OutputIterator& out)
{
// On leave, copy all segments from starting point, append the intersection point
// and add the output piece
geometry::copy_segments<false>(linestring, segment_id, index, current_piece);
geometry::copy_segments<false>(linestring, segment_id, index, robust_policy, current_piece);
detail::overlay::append_no_duplicates(current_piece, point);
if (::boost::size(current_piece) > 1)
{
@@ -225,8 +232,15 @@ struct action_selector<overlay_intersection>
return entered;
}
template <typename Point, typename Geometry>
static inline bool included(Point const& point, Geometry const& geometry)
template
<
typename Point,
typename Geometry,
typename RobustPolicy
>
static inline bool included(Point const& point,
Geometry const& geometry,
RobustPolicy const& )
{
return geometry::covered_by(point, geometry);
}
@@ -245,16 +259,19 @@ struct action_selector<overlay_difference>
typename LineStringOut,
typename LineString,
typename Point,
typename Operation
typename Operation,
typename RobustPolicy
>
static inline void enter(LineStringOut& current_piece,
LineString const& linestring,
segment_identifier& segment_id,
int index, Point const& point,
Operation const& operation, OutputIterator& out)
Operation const& operation,
RobustPolicy const& robust_policy,
OutputIterator& out)
{
normal_action::leave(current_piece, linestring, segment_id, index,
point, operation, out);
point, operation, robust_policy, out);
}
template
@@ -263,16 +280,19 @@ struct action_selector<overlay_difference>
typename LineStringOut,
typename LineString,
typename Point,
typename Operation
typename Operation,
typename RobustPolicy
>
static inline void leave(LineStringOut& current_piece,
LineString const& linestring,
segment_identifier& segment_id,
int index, Point const& point,
Operation const& operation, OutputIterator& out)
Operation const& operation,
RobustPolicy const& robust_policy,
OutputIterator& out)
{
normal_action::enter(current_piece, linestring, segment_id, index,
point, operation, out);
point, operation, robust_policy, out);
}
template
@@ -296,10 +316,17 @@ struct action_selector<overlay_difference>
return ! normal_action::is_entered(entered);
}
template <typename Point, typename Geometry>
static inline bool included(Point const& point, Geometry const& geometry)
template
<
typename Point,
typename Geometry,
typename RobustPolicy
>
static inline bool included(Point const& point,
Geometry const& geometry,
RobustPolicy const& robust_policy)
{
return ! normal_action::included(point, geometry);
return ! normal_action::included(point, geometry, robust_policy);
}
};
@@ -349,9 +376,9 @@ class follow
inline bool use_distance(Turn const& left, Turn const& right) const
{
return geometry::math::equals(left.operations[0].enriched.distance, right.operations[0].enriched.distance)
return left.operations[0].fraction == right.operations[0].fraction
? use_operation(left, right)
: left.operations[0].enriched.distance < right.operations[0].enriched.distance
: left.operations[0].fraction < right.operations[0].fraction
;
}
@@ -372,16 +399,30 @@ class follow
public :
template <typename Point, typename Geometry>
static inline bool included(Point const& point, Geometry const& geometry)
template
<
typename Point,
typename Geometry,
typename RobustPolicy
>
static inline bool included(Point const& point,
Geometry const& geometry,
RobustPolicy const& robust_policy)
{
return following::action_selector<OverlayType>::included(point, geometry);
return following::action_selector<OverlayType>::included(point, geometry, robust_policy);
}
template<typename Turns, typename OutputIterator>
template
<
typename Turns,
typename OutputIterator,
typename RobustPolicy
>
static inline OutputIterator apply(LineString const& linestring, Polygon const& polygon,
detail::overlay::operation_type , // TODO: this parameter might be redundant
Turns& turns, OutputIterator out)
Turns& turns,
RobustPolicy const& robust_policy,
OutputIterator out)
{
typedef typename boost::range_iterator<Turns>::type turn_iterator;
typedef typename boost::range_value<Turns>::type turn_type;
@@ -423,14 +464,20 @@ public :
debug_traverse(*it, *iit, "-> Entering");
entered = true;
action::enter(current_piece, linestring, current_segment_id, iit->seg_id.segment_index, it->point, *iit, out);
action::enter(current_piece, linestring, current_segment_id,
iit->seg_id.segment_index, it->point, *iit,
robust_policy,
out);
}
else if (following::is_leaving(*it, *iit, entered, first, linestring, polygon))
{
debug_traverse(*it, *iit, "-> Leaving");
entered = false;
action::leave(current_piece, linestring, current_segment_id, iit->seg_id.segment_index, it->point, *iit, out);
action::leave(current_piece, linestring, current_segment_id,
iit->seg_id.segment_index, it->point, *iit,
robust_policy,
out);
}
first = false;
}
@@ -439,6 +486,7 @@ public :
{
geometry::copy_segments<false>(linestring, current_segment_id,
boost::size(linestring) - 1,
robust_policy,
current_piece);
}

View File

@@ -11,6 +11,7 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_LINEAR_LINEAR_HPP
#include <cstddef>
#include <algorithm>
#include <iterator>
#include <boost/assert.hpp>
@@ -123,7 +124,7 @@ static inline bool is_isolated_point(Turn const& turn,
return false;
}
if ( turn.method == method_collinear )
if ( turn.method == method_none )
{
BOOST_ASSERT( operation.operation == operation_continue );
return true;
@@ -184,13 +185,16 @@ protected:
static inline OutputIterator
process_turn(TurnIterator it,
TurnOperationIterator op_it,
bool& first, bool& entered,
bool& entered,
std::size_t& enter_count,
Linestring const& linestring,
LinestringOut& current_piece,
SegmentIdentifier& current_segment_id,
OutputIterator oit)
{
// We don't rescale linear/linear
detail::no_rescale_policy robust_policy;
if ( is_entering(*it, *op_it) )
{
#ifdef GEOMETRY_TEST_DEBUG
@@ -203,7 +207,7 @@ protected:
action::enter(current_piece, linestring,
current_segment_id,
op_it->seg_id.segment_index,
it->point, *op_it, oit);
it->point, *op_it, robust_policy, oit);
}
++enter_count;
}
@@ -220,7 +224,7 @@ protected:
action::leave(current_piece, linestring,
current_segment_id,
op_it->seg_id.segment_index,
it->point, *op_it, oit);
it->point, *op_it, robust_policy, oit);
}
}
else if ( FollowIsolatedPoints
@@ -244,7 +248,6 @@ protected:
entered = true;
}
first = false;
return oit;
}
@@ -262,9 +265,13 @@ protected:
{
if ( action::is_entered(entered) )
{
// We don't rescale linear/linear
detail::no_rescale_policy robust_policy;
geometry::copy_segments<false>(linestring,
current_segment_id,
boost::size(linestring) - 1,
robust_policy,
current_piece);
}
@@ -281,17 +288,9 @@ public:
template <typename TurnIterator, typename OutputIterator>
static inline OutputIterator
apply(Linestring const& linestring, Linear const& linear,
TurnIterator start, TurnIterator beyond,
TurnIterator first, TurnIterator beyond,
OutputIterator oit)
{
typedef typename boost::range_iterator
<
typename std::iterator_traits
<
TurnIterator
>::value_type::container_type const
>::type turn_operation_iterator;
// Iterate through all intersection points (they are
// ordered along the each line)
@@ -299,15 +298,12 @@ public:
geometry::segment_identifier current_segment_id(0, -1, -1, -1);
bool entered = false;
bool first = true;
std::size_t enter_count = 0;
for (TurnIterator it = start; it != beyond; ++it)
for (TurnIterator it = first; it != beyond; ++it)
{
turn_operation_iterator op_it = boost::begin(it->operations);
oit = process_turn(it, op_it,
first, entered, enter_count,
oit = process_turn(it, boost::begin(it->operations),
entered, enter_count,
linestring,
current_piece, current_segment_id,
oit);
@@ -365,8 +361,7 @@ protected:
struct copy_linestrings_in_range
{
static inline OutputIt
apply(linestring_iterator begin, linestring_iterator beyond,
OutputIt oit)
apply(linestring_iterator, linestring_iterator, OutputIt oit)
{
return oit;
}
@@ -376,10 +371,10 @@ protected:
struct copy_linestrings_in_range<OutputIt, overlay_difference>
{
static inline OutputIt
apply(linestring_iterator begin, linestring_iterator beyond,
apply(linestring_iterator first, linestring_iterator beyond,
OutputIt oit)
{
for (linestring_iterator ls_it = begin; ls_it != beyond; ++ls_it)
for (linestring_iterator ls_it = first; ls_it != beyond; ++ls_it)
{
LinestringOut line_out;
geometry::convert(*ls_it, line_out);
@@ -389,68 +384,80 @@ protected:
}
};
template <typename TurnIterator>
static inline int get_multi_index(TurnIterator it)
{
return boost::begin(it->operations)->seg_id.multi_index;
}
class has_other_multi_id
{
private:
int m_multi_id;
public:
has_other_multi_id(int multi_id)
: m_multi_id(multi_id) {}
template <typename Turn>
bool operator()(Turn const& turn) const
{
return boost::begin(turn.operations)->seg_id.multi_index
!= m_multi_id;
}
};
public:
template <typename TurnIterator, typename OutputIterator>
static inline OutputIterator
apply(MultiLinestring const& multilinestring, Linear const& linear,
TurnIterator start, TurnIterator beyond,
TurnIterator first, TurnIterator beyond,
OutputIterator oit)
{
BOOST_ASSERT( start != beyond );
BOOST_ASSERT( first != beyond );
typedef copy_linestrings_in_range
<
OutputIterator, OverlayType
> copy_linestrings;
linestring_iterator ls_begin = boost::begin(multilinestring);
linestring_iterator ls_end = boost::end(multilinestring);
linestring_iterator ls_first = boost::begin(multilinestring);
linestring_iterator ls_beyond = boost::end(multilinestring);
// Iterate through all intersection points (they are
// ordered along the each line)
// ordered along the each linestring)
int current_multi_id =
boost::begin(start->operations)->seg_id.multi_index;
int current_multi_id = get_multi_index(first);
oit = copy_linestrings::apply(ls_begin,
ls_begin + current_multi_id,
oit = copy_linestrings::apply(ls_first,
ls_first + current_multi_id,
oit);
TurnIterator turns_begin = start, turns_end;
TurnIterator per_ls_next = first;
do {
// find last turn with this multi-index
turns_end = turns_begin;
++turns_end;
while ( turns_end != beyond )
{
if ( boost::begin(turns_end->operations)->seg_id.multi_index
!= current_multi_id )
{
break;
}
++turns_end;
}
TurnIterator per_ls_current = per_ls_next;
oit = Base::apply(*(boost::begin(multilinestring)
+ current_multi_id),
linear, turns_begin, turns_end, oit);
// find turn with different multi-index
per_ls_next = std::find_if(per_ls_current, beyond,
has_other_multi_id(current_multi_id));
int new_multi_id(0);
linestring_iterator ls_beyond_last = ls_end;
if ( turns_end != beyond )
oit = Base::apply(*(ls_first + current_multi_id),
linear, per_ls_current, per_ls_next, oit);
int next_multi_id(-1);
linestring_iterator ls_next = ls_beyond;
if ( per_ls_next != beyond )
{
new_multi_id =
boost::begin(turns_end->operations)->seg_id.multi_index;
ls_beyond_last = ls_begin + new_multi_id;
next_multi_id = get_multi_index(per_ls_next);
ls_next = ls_first + next_multi_id;
}
oit = copy_linestrings::apply(ls_begin + current_multi_id + 1,
ls_beyond_last,
oit = copy_linestrings::apply(ls_first + current_multi_id + 1,
ls_next,
oit);
current_multi_id = new_multi_id;
turns_begin = turns_end;
current_multi_id = next_multi_id;
}
while ( turns_end != beyond );
while ( per_ls_next != beyond );
return oit;
}

View File

@@ -14,10 +14,10 @@
#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
#include <boost/geometry/algorithms/detail/rescale.hpp>
#include <boost/geometry/geometries/segment.hpp>
#include <boost/geometry/policies/robustness/robust_point_type.hpp>
namespace boost { namespace geometry
{
@@ -36,35 +36,45 @@ template
>
struct get_turn_without_info
{
typedef strategy_intersection
<
typename cs_tag<typename TurnInfo::point_type>::type,
Point1,
Point2,
typename TurnInfo::point_type
> si;
typedef typename si::segment_intersection_strategy_type strategy;
template <typename RescalePolicy, typename OutputIterator>
template <typename RobustPolicy, typename OutputIterator>
static inline OutputIterator apply(
Point1 const& pi, Point1 const& pj, Point1 const& pk,
Point2 const& qi, Point2 const& qj, Point2 const& qk,
bool /*is_p_first*/, bool /*is_p_last*/,
bool /*is_q_first*/, bool /*is_q_last*/,
TurnInfo const& ,
RescalePolicy const& rescale_policy,
RobustPolicy const& robust_policy,
OutputIterator out)
{
typedef strategy_intersection
<
typename cs_tag<typename TurnInfo::point_type>::type,
Point1,
Point2,
typename TurnInfo::point_type,
RobustPolicy
> si;
typedef typename si::segment_intersection_strategy_type strategy;
typedef model::referring_segment<Point1 const> segment_type1;
typedef model::referring_segment<Point1 const> segment_type2;
segment_type1 p1(pi, pj), p2(pj, pk);
segment_type2 q1(qi, qj), q2(qj, qk);
segment_type1 p1(pi, pj);
segment_type2 q1(qi, qj);
//
typename strategy::return_type result = strategy::apply(p1, q1);
typedef typename geometry::robust_point_type
<
Point1, RobustPolicy
>::type robust_point_type;
robust_point_type pi_rob, pj_rob, qi_rob, qj_rob;
geometry::recalculate(pi_rob, pi, robust_policy);
geometry::recalculate(pj_rob, pj, robust_policy);
geometry::recalculate(qi_rob, qi, robust_policy);
geometry::recalculate(qj_rob, qj, robust_policy);
typename strategy::return_type result
= strategy::apply(p1, q1, robust_policy,
pi_rob, pj_rob, qi_rob, qj_rob);
for (std::size_t i = 0; i < result.template get<0>().count; i++)
{
@@ -88,10 +98,12 @@ template
<
typename Geometry1,
typename Geometry2,
typename RobustPolicy,
typename Turns
>
inline void get_intersection_points(Geometry1 const& geometry1,
Geometry2 const& geometry2,
RobustPolicy const& robust_policy,
Turns& turns)
{
concept::check_concepts_and_equal_dimensions<Geometry1 const, Geometry2 const>();
@@ -108,7 +120,8 @@ inline void get_intersection_points(Geometry1 const& geometry1,
typename cs_tag<Geometry1>::type,
Geometry1,
Geometry2,
typename boost::range_value<Turns>::type
typename point_type<Geometry1>::type, // TODO from both
RobustPolicy
>::segment_intersection_strategy_type segment_intersection_strategy_type;
detail::get_turns::no_interrupt_policy interrupt_policy;
@@ -135,7 +148,7 @@ inline void get_intersection_points(Geometry1 const& geometry1,
>::type::apply(
0, geometry1,
1, geometry2,
detail::no_rescale_policy(),
robust_policy,
turns, interrupt_policy);
}

View File

@@ -36,15 +36,10 @@ namespace detail { namespace overlay
template <typename Point1>
struct get_relative_order
{
typedef strategy_intersection
typedef typename strategy::side::services::default_strategy
<
typename cs_tag<Point1>::type,
Point1,
Point1,
Point1
> si;
typedef typename si::side_strategy_type strategy;
typename cs_tag<Point1>::type
>::type strategy;
template <typename Point>
static inline int value_via_product(Point const& ti, Point const& tj,

View File

@@ -16,9 +16,12 @@
#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
#include <boost/geometry/algorithms/detail/recalculate.hpp>
#include <boost/geometry/geometries/segment.hpp>
#include <boost/geometry/policies/robustness/robust_point_type.hpp>
// Silence warning C4127: conditional expression is constant
#if defined(_MSC_VER)
@@ -57,13 +60,16 @@ public:
namespace detail { namespace overlay
{
template <typename Point1, typename Point2>
template <typename PointP, typename PointQ,
typename Pi = PointP, typename Pj = PointP, typename Pk = PointP,
typename Qi = PointQ, typename Qj = PointQ, typename Qk = PointQ
>
struct side_calculator
{
typedef boost::geometry::strategy::side::side_by_triangle<> side; // todo: get from coordinate system
inline side_calculator(Point1 const& pi, Point1 const& pj, Point1 const& pk,
Point2 const& qi, Point2 const& qj, Point2 const& qk)
inline side_calculator(Pi const& pi, Pj const& pj, Pk const& pk,
Qi const& qi, Qj const& qj, Qk const& qk)
: m_pi(pi), m_pj(pj), m_pk(pk)
, m_qi(qi), m_qj(qj), m_qk(qk)
{}
@@ -76,12 +82,12 @@ struct side_calculator
inline int pk_wrt_q2() const { return side::apply(m_qj, m_qk, m_pk); }
inline int qk_wrt_p2() const { return side::apply(m_pj, m_pk, m_qk); }
Point1 const& m_pi;
Point1 const& m_pj;
Point1 const& m_pk;
Point2 const& m_qi;
Point2 const& m_qj;
Point2 const& m_qk;
Pi const& m_pi;
Pj const& m_pj;
Pk const& m_pk;
Qi const& m_qi;
Qj const& m_qj;
Qk const& m_qk;
};
struct base_turn_handler
@@ -124,6 +130,26 @@ struct base_turn_handler
{
both(ti, condition ? operation_union : operation_intersection);
}
template <typename TurnInfo, typename IntersectionInfo>
static inline void assign_point(TurnInfo& ti,
method_type method,
IntersectionInfo const& info, int index)
{
ti.method = method;
BOOST_ASSERT(index >= 0 && unsigned(index) < info.count); // TODO remove this
geometry::convert(info.intersections[index], ti.point);
ti.operations[0].fraction = info.fractions[index].robust_ra;
ti.operations[1].fraction = info.fractions[index].robust_rb;
}
template <typename IntersectionInfo>
static inline int non_opposite_to_index(IntersectionInfo const& info)
{
return info.fractions[0].robust_rb < info.fractions[1].robust_rb
? 1 : 0;
}
};
@@ -151,8 +177,7 @@ struct touch_interior : public base_turn_handler
DirInfo const& dir_info,
SidePolicy const& side)
{
ti.method = method_touch_interior;
geometry::convert(intersection_info.intersections[0], ti.point);
assign_point(ti, method_touch_interior, intersection_info, 0);
// Both segments of q touch segment p somewhere in its interior
// 1) We know: if q comes from LEFT or RIGHT
@@ -271,8 +296,7 @@ struct touch : public base_turn_handler
DirInfo const& dir_info,
SidePolicy const& side)
{
ti.method = method_touch;
geometry::convert(intersection_info.intersections[0], ti.point);
assign_point(ti, method_touch, intersection_info, 0);
int const side_qi_p1 = dir_info.sides.template get<1, 0>();
int const side_qk_p1 = side.qk_wrt_p1();
@@ -286,13 +310,9 @@ struct touch : public base_turn_handler
int const side_pk_p = side.pk_wrt_p1();
int const side_qk_q = side.qk_wrt_q1();
bool const both_continue = side_pk_p == 0 && side_qk_q == 0;
bool const robustness_issue_in_continue = both_continue && side_pk_q2 != 0;
bool const q_turns_left = side_qk_q == 1;
bool const block_q = side_qk_p1 == 0
&& ! same(side_qi_p1, side_qk_q)
&& ! robustness_issue_in_continue
;
// If Pk at same side as Qi/Qk
@@ -464,13 +484,12 @@ struct equal : public base_turn_handler
Point1 const& , Point1 const& , Point1 const& ,
Point2 const& , Point2 const& , Point2 const& ,
TurnInfo& ti,
IntersectionInfo const& intersection_info,
DirInfo const& ,
IntersectionInfo const& info,
DirInfo const& ,
SidePolicy const& side)
{
ti.method = method_equal;
// Copy the SECOND intersection point
geometry::convert(intersection_info.intersections[1], ti.point);
// Copy the intersection point in TO direction
assign_point(ti, method_equal, info, non_opposite_to_index(info));
int const side_pk_q2 = side.pk_wrt_q2();
int const side_pk_p = side.pk_wrt_p1();
@@ -538,7 +557,7 @@ struct equal_opposite : public base_turn_handler
}
for (unsigned int i = 0; i < intersection_info.count; i++)
{
geometry::convert(intersection_info.intersections[i], tp.point);
assign_point(tp, method_none, intersection_info, i);
AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info);
*out++ = tp;
}
@@ -596,12 +615,12 @@ struct collinear : public base_turn_handler
Point1 const& , Point1 const& , Point1 const& ,
Point2 const& , Point2 const& , Point2 const& ,
TurnInfo& ti,
IntersectionInfo const& intersection_info,
IntersectionInfo const& info,
DirInfo const& dir_info,
SidePolicy const& side)
{
ti.method = method_collinear;
geometry::convert(intersection_info.intersections[1], ti.point);
// Copy the intersection point in TO direction
assign_point(ti, method_collinear, info, non_opposite_to_index(info));
int const arrival = dir_info.arrival[0];
// Should not be 0, this is checked before
@@ -616,9 +635,6 @@ struct collinear : public base_turn_handler
: side_q
;
int const side_pk = side.pk_wrt_q1();
int const side_qk = side.qk_wrt_p1();
// See comments above,
// resulting in a strange sort of mathematic rule here:
// The arrival-info multiplied by the relevant side
@@ -626,15 +642,7 @@ struct collinear : public base_turn_handler
int const product = arrival * side_p_or_q;
// Robustness: side_p is supposed to be equal to side_pk (because p/q are collinear)
// and side_q to side_qk
bool const robustness_issue = side_pk != side_p || side_qk != side_q;
if (robustness_issue)
{
handle_robustness(ti, arrival, side_p, side_q, side_pk, side_qk);
}
else if(product == 0)
if(product == 0)
{
both(ti, operation_continue);
}
@@ -644,37 +652,6 @@ struct collinear : public base_turn_handler
}
}
static inline void handle_robustness(TurnInfo& ti, int arrival,
int side_p, int side_q, int side_pk, int side_qk)
{
// We take the longer one, i.e. if q arrives in p (arrival == -1),
// then p exceeds q and we should take p for a union...
bool use_p_for_union = arrival == -1;
// ... unless one of the sides consistently directs to the other side
int const consistent_side_p = side_p == side_pk ? side_p : 0;
int const consistent_side_q = side_q == side_qk ? side_q : 0;
if (arrival == -1 && (consistent_side_p == -1 || consistent_side_q == 1))
{
use_p_for_union = false;
}
if (arrival == 1 && (consistent_side_p == 1 || consistent_side_q == -1))
{
use_p_for_union = true;
}
//std::cout << "ROBUSTNESS -> Collinear "
// << " arr: " << arrival
// << " dir: " << side_p << " " << side_q
// << " rev: " << side_pk << " " << side_qk
// << " cst: " << cside_p << " " << cside_q
// << std::boolalpha << " " << use_p_for_union
// << std::endl;
ui_else_iu(use_p_for_union, ti);
}
};
template
@@ -716,21 +693,12 @@ private :
typename IntersectionInfo
>
static inline bool set_tp(Point const& , Point const& , Point const& , int side_rk_r,
bool const handle_robustness, Point const& , Point const& , int side_rk_s,
bool const handle_robustness,
Point const& , Point const& , int side_rk_s,
TurnInfo& tp, IntersectionInfo const& intersection_info)
{
if (handle_robustness)
{
// For Robustness: also calculate rk w.r.t. the other line. Because they are collinear opposite, that direction should be the reverse of the first direction.
// If this is not the case, we make it all-collinear, so zero
if (side_rk_r != 0 && side_rk_r != -side_rk_s)
{
#ifdef BOOST_GEOMETRY_DEBUG_ROBUSTNESS
std::cout << "Robustness correction: " << side_rk_r << " / " << side_rk_s << std::endl;
#endif
side_rk_r = 0;
}
}
boost::ignore_unused_variable_warning(handle_robustness);
boost::ignore_unused_variable_warning(side_rk_s);
operation_type blocked = operation_blocked;
switch(side_rk_r)
@@ -768,7 +736,7 @@ private :
// If P arrives within Q, set info on P (which is done above, index=0),
// this turn-info belongs to the second intersection point, index=1
// (see e.g. figure CLO1)
geometry::convert(intersection_info.intersections[1 - Index], tp.point);
assign_point(tp, method_collinear, intersection_info, 1 - Index);
return true;
}
@@ -826,8 +794,6 @@ public:
{
TurnInfo tp = tp_model;
tp.method = method_collinear;
// If P arrives within Q, there is a turn dependent on P
if ( dir_info.arrival[0] == 1
&& is_pk_valid
@@ -862,7 +828,7 @@ public:
}
for (unsigned int i = 0; i < intersection_info.count; i++)
{
geometry::convert(intersection_info.intersections[i], tp.point);
assign_point(tp, method_collinear, intersection_info, i);
AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info);
*out++ = tp;
}
@@ -893,8 +859,7 @@ struct crosses : public base_turn_handler
IntersectionInfo const& intersection_info,
DirInfo const& dir_info)
{
ti.method = method_crosses;
geometry::convert(intersection_info.intersections[0], ti.point);
assign_point(ti, method_crosses, intersection_info, 0);
// In all casees:
// If Q crosses P from left to right
@@ -908,14 +873,12 @@ struct crosses : public base_turn_handler
}
};
template<typename TurnInfo>
struct only_convert
struct only_convert : public base_turn_handler
{
template<typename IntersectionInfo>
template<typename TurnInfo, typename IntersectionInfo>
static inline void apply(TurnInfo& ti, IntersectionInfo const& intersection_info)
{
ti.method = method_collinear;
geometry::convert(intersection_info.intersections[0], ti.point);
assign_point(ti, method_none, intersection_info, 0); // was collinear
ti.operations[0].operation = operation_continue;
ti.operations[1].operation = operation_continue;
}
@@ -972,7 +935,7 @@ struct get_turn_info
typename Point1,
typename Point2,
typename TurnInfo,
typename RescalePolicy,
typename RobustPolicy,
typename OutputIterator
>
static inline OutputIterator apply(
@@ -981,27 +944,42 @@ struct get_turn_info
bool /*is_p_first*/, bool /*is_p_last*/,
bool /*is_q_first*/, bool /*is_q_last*/,
TurnInfo const& tp_model,
RescalePolicy const& , // TODO: this will be used. rescale_policy,
RobustPolicy const& robust_policy,
OutputIterator out)
{
typedef typename geometry::robust_point_type
<
Point1, RobustPolicy
>::type robust_point_type;
robust_point_type pi_rob, pj_rob, pk_rob, qi_rob, qj_rob, qk_rob;
geometry::recalculate(pi_rob, pi, robust_policy);
geometry::recalculate(pj_rob, pj, robust_policy);
geometry::recalculate(pk_rob, pk, robust_policy);
geometry::recalculate(qi_rob, qi, robust_policy);
geometry::recalculate(qj_rob, qj, robust_policy);
geometry::recalculate(qk_rob, qk, robust_policy);
typedef model::referring_segment<Point1 const> segment_type1;
typedef model::referring_segment<Point2 const> segment_type2;
segment_type1 p1(pi, pj), p2(pj, pk);
segment_type2 q1(qi, qj), q2(qj, qk);
segment_type1 p1(pi, pj);
segment_type2 q1(qi, qj);
side_calculator<Point1, Point2> side_calc(pi, pj, pk, qi, qj, qk);
side_calculator<robust_point_type, robust_point_type> side_calc(pi_rob, pj_rob, pk_rob, qi_rob, qj_rob, qk_rob);
typedef strategy_intersection
<
typename cs_tag<typename TurnInfo::point_type>::type,
Point1,
Point2,
typename TurnInfo::point_type
typename TurnInfo::point_type,
RobustPolicy
> si;
typedef typename si::segment_intersection_strategy_type strategy;
typename strategy::return_type result = strategy::apply(p1, q1);
typename strategy::return_type result = strategy::apply(p1, q1,
robust_policy, pi_rob, pj_rob, qi_rob, qj_rob);
char const method = result.template get<1>().how;
@@ -1017,7 +995,7 @@ struct get_turn_info
if (AssignPolicy::include_no_turn
&& result.template get<0>().count > 0)
{
only_convert<TurnInfo>::apply(tp,
only_convert::apply(tp,
result.template get<0>());
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
*out++ = tp;
@@ -1044,7 +1022,7 @@ struct get_turn_info
else
{
// Swap p/q
side_calculator<Point1, Point2> swapped_side_calc(qi, qj, qk, pi, pj, pk);
side_calculator<Point2, Point1> swapped_side_calc(qi, qj, qk, pi, pj, pk);
policy::template apply<1>(qi, qj, qk, pi, pj, pk,
tp, result.template get<0>(), result.template get<1>(),
swapped_side_calc);
@@ -1132,7 +1110,7 @@ struct get_turn_info
// degenerate points
if (AssignPolicy::include_degenerate)
{
only_convert<TurnInfo>::apply(tp, result.template get<0>());
only_convert::apply(tp, result.template get<0>());
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
*out++ = tp;
}

View File

@@ -21,10 +21,13 @@ namespace boost { namespace geometry {
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace overlay {
// TURN_OPERATION
enum turn_position { position_middle, position_front, position_back };
template <typename SegmentRatio>
struct turn_operation_linear
: public turn_operation
: public turn_operation<SegmentRatio>
{
turn_operation_linear()
: position(position_middle)
@@ -35,6 +38,154 @@ struct turn_operation_linear
bool is_collinear; // valid only for Linear geometry
};
template <typename Point1, typename Point2, typename TurnPoint, typename RobustPolicy>
class intersection_info
{
typedef typename strategy_intersection
<
typename cs_tag<TurnPoint>::type,
Point1,
Point2,
TurnPoint,
RobustPolicy
>::segment_intersection_strategy_type strategy;
public:
typedef model::referring_segment<Point1 const> segment_type1;
typedef model::referring_segment<Point2 const> segment_type2;
typedef side_calculator<Point1, Point2> side_calculator_type;
typedef typename strategy::return_type result_type;
typedef typename boost::tuples::element<0, result_type>::type i_info_type; // intersection_info
typedef typename boost::tuples::element<1, result_type>::type d_info_type; // dir_info
intersection_info(Point1 const& pi, Point1 const& pj, Point1 const& pk,
Point2 const& qi, Point2 const& qj, Point2 const& qk,
RobustPolicy const& robust_policy)
: m_result(strategy::apply(segment_type1(pi, pj),
segment_type2(qi, qj),
robust_policy))
, m_side_calc(pi, pj, pk, qi, qj, qk)
, m_robust_policy(robust_policy)
{}
inline Point1 const& pi() const { return m_side_calc.m_pi; }
inline Point1 const& pj() const { return m_side_calc.m_pj; }
inline Point1 const& pk() const { return m_side_calc.m_pk; }
inline Point2 const& qi() const { return m_side_calc.m_qi; }
inline Point2 const& qj() const { return m_side_calc.m_qj; }
inline Point2 const& qk() const { return m_side_calc.m_qk; }
inline side_calculator_type const& sides() const { return m_side_calc; }
inline result_type const& result() const { return m_result; }
inline i_info_type const& i_info() const { return m_result.template get<0>(); }
inline d_info_type const& d_info() const { return m_result.template get<1>(); }
// TODO: not it's more like is_spike_ip_p
inline bool is_spike_p() const
{
if ( m_side_calc.pk_wrt_p1() == 0 )
{
if ( ! is_ip_j<0>() )
return false;
int const qk_p1 = m_side_calc.qk_wrt_p1();
int const qk_p2 = m_side_calc.qk_wrt_p2();
if ( qk_p1 == -qk_p2 )
{
if ( qk_p1 == 0 )
{
return is_spike_of_collinear(pi(), pj(), pk());
}
return true;
}
}
return false;
}
// TODO: not it's more like is_spike_ip_q
inline bool is_spike_q() const
{
if ( m_side_calc.qk_wrt_q1() == 0 )
{
if ( ! is_ip_j<1>() )
return false;
int const pk_q1 = m_side_calc.pk_wrt_q1();
int const pk_q2 = m_side_calc.pk_wrt_q2();
if ( pk_q1 == -pk_q2 )
{
if ( pk_q1 == 0 )
{
return is_spike_of_collinear(qi(), qj(), qk());
}
return true;
}
}
return false;
}
private:
template <typename Point>
inline bool is_spike_of_collinear(Point const& i, Point const& j, Point const& k) const
{
typedef model::referring_segment<Point const> seg_t;
typedef strategy_intersection
<
typename cs_tag<Point>::type, Point, Point, Point, RobustPolicy
> si;
typedef typename si::segment_intersection_strategy_type strategy;
typename strategy::return_type result
= strategy::apply(seg_t(i, j), seg_t(j, k), m_robust_policy);
return result.template get<0>().count == 2;
}
template <std::size_t OpId>
bool is_ip_j() const
{
int arrival = d_info().arrival[OpId];
bool same_dirs = d_info().dir_a == 0 && d_info().dir_b == 0;
if ( same_dirs )
{
if ( i_info().count == 2 )
{
if ( ! d_info().opposite )
{
return arrival != -1;
}
else
{
return arrival != -1;
}
}
else
{
return arrival == 0;
}
}
else
{
return arrival == 1;
}
}
result_type m_result;
side_calculator_type m_side_calc;
RobustPolicy const& m_robust_policy;
};
// SEGMENT_INTERSECTION RESULT
// C H0 H1 A0 A1 O IP1 IP2
@@ -117,170 +268,99 @@ struct turn_operation_linear
// |--------> 1 0 1 0 1 F u/x (P is vertical)
//
template <typename AssignPolicy, bool EnableFirst, bool EnableLast>
struct get_turn_info_for_endpoint
class linear_intersections
{
BOOST_STATIC_ASSERT(EnableFirst || EnableLast);
template<typename Point1,
typename Point2,
typename TurnInfo,
typename IntersectionResult,
typename OutputIterator
>
static inline bool apply(Point1 const& pi, Point1 const& pj, Point1 const& pk,
Point2 const& qi, Point2 const& qj, Point2 const& qk,
bool is_p_first, bool is_p_last,
bool is_q_first, bool is_q_last,
TurnInfo const& tp_model,
IntersectionResult const& result,
method_type /*method*/,
OutputIterator out)
public:
template <typename Point1, typename Point2, typename IntersectionResult>
linear_intersections(Point1 const& pi,
Point2 const& qi,
IntersectionResult const& result,
bool is_p_last, bool is_q_last)
{
std::size_t ip_count = result.template get<0>().count;
// no intersection points
if ( ip_count == 0 )
return false;
int segment_index0 = tp_model.operations[0].seg_id.segment_index;
int segment_index1 = tp_model.operations[1].seg_id.segment_index;
BOOST_ASSERT(segment_index0 >= 0 && segment_index1 >= 0);
if ( !is_p_first && !is_p_last && !is_q_first && !is_q_last )
return false;
operation_type p_operation0 = operation_none;
operation_type q_operation0 = operation_none;
operation_type p_operation1 = operation_none;
operation_type q_operation1 = operation_none;
bool p0i, p0j, q0i, q0j; // assign false?
bool p1i, p1j, q1i, q1j; // assign false?
bool opposite = result.template get<1>().opposite;
{
int p_how = result.template get<1>().how_a;
int q_how = result.template get<1>().how_b;
int p_arrival = result.template get<1>().arrival[0];
int q_arrival = result.template get<1>().arrival[1];
bool same_dirs = result.template get<1>().dir_a == 0 && result.template get<1>().dir_b == 0;
handle_segment(is_p_first, is_p_last, p_how, p_arrival,
is_q_first, is_q_last, q_how, q_arrival,
opposite, ip_count, same_dirs,
result.template get<0>().intersections[0],
result.template get<0>().intersections[1],
p_operation0, q_operation0, p_operation1, q_operation1,
p0i, p0j, q0i, q0j,
p1i, p1j, q1i, q1j,
pi, pj, pk, qi, qj, qk);
}
bool append0_last
= analyse_segment_and_assign_ip(pi, pj, pk, qi, qj, qk,
result.template get<0>().intersections[0],
is_p_first, is_p_last, is_q_first, is_q_last,
p0i, p0j, q0i, q0j,
p_operation0, q_operation0,
tp_model, result, out);
// NOTE: opposite && ip_count == 1 may be true!
// don't ignore only for collinear opposite
bool result_ignore_ip0 = append0_last && ( ip_count == 1 || !opposite );
if ( p_operation1 == operation_none )
return result_ignore_ip0;
bool append1_last
= analyse_segment_and_assign_ip(pi, pj, pk, qi, qj, qk,
result.template get<0>().intersections[1],
is_p_first, is_p_last, is_q_first, is_q_last,
p1i, p1j, q1i, q1j,
p_operation1, q_operation1,
tp_model, result, out);
// don't ignore only for collinear opposite
bool result_ignore_ip1 = append1_last && !opposite /*&& ip_count == 2*/;
return result_ignore_ip0 || result_ignore_ip1;
}
template<typename Point, typename Point1, typename Point2>
static inline
void handle_segment(bool /*first_a*/, bool last_a, int how_a, int arrival_a,
bool /*first_b*/, bool last_b, int how_b, int arrival_b,
bool opposite, std::size_t ip_count, bool same_dirs/*collinear*/,
Point const& ip0, Point const& /*ip1*/,
operation_type & op0_a, operation_type & op0_b,
operation_type & op1_a, operation_type & op1_b,
bool & i0_a, bool & j0_a, bool & i0_b, bool & j0_b,
bool & i1_a, bool & j1_a, bool & i1_b, bool & j1_b,
Point1 const& pi, Point1 const& /*pj*/, Point1 const& /*pk*/,
Point2 const& qi, Point2 const& /*qj*/, Point2 const& /*qk*/)
{
namespace ov = overlay;
i0_a = false; j0_a = false; i0_b = false; j0_b = false;
i1_a = false; j1_a = false; i1_b = false; j1_b = false;
int arrival_a = result.template get<1>().arrival[0];
int arrival_b = result.template get<1>().arrival[1];
bool same_dirs = result.template get<1>().dir_a == 0
&& result.template get<1>().dir_b == 0;
if ( same_dirs )
{
if ( ip_count == 2 )
if ( result.template get<0>().count == 2 )
{
BOOST_ASSERT( how_a == 0 && how_b == 0 );
if ( !opposite )
if ( ! result.template get<1>().opposite )
{
op0_a = operation_intersection;
op0_b = operation_intersection;
op1_a = arrival_to_union_or_blocked(arrival_a, last_a);
op1_b = arrival_to_union_or_blocked(arrival_b, last_b);
ips[0].p_operation = operation_intersection;
ips[0].q_operation = operation_intersection;
ips[1].p_operation = union_or_blocked_same_dirs(arrival_a, is_p_last);
ips[1].q_operation = union_or_blocked_same_dirs(arrival_b, is_q_last);
i0_a = equals::equals_point_point(pi, ip0);
i0_b = equals::equals_point_point(qi, ip0);
j1_a = arrival_a != -1;
j1_b = arrival_b != -1;
ips[0].is_pi
= equals::equals_point_point(
pi, result.template get<0>().intersections[0]);
ips[0].is_qi
= equals::equals_point_point(
qi, result.template get<0>().intersections[0]);
ips[1].is_pj = arrival_a != -1;
ips[1].is_qj = arrival_b != -1;
}
else
{
op0_a = operation_intersection;
op0_b = arrival_to_union_or_blocked(arrival_b, last_b);
op1_a = arrival_to_union_or_blocked(arrival_a, last_a);
op1_b = operation_intersection;
ips[0].p_operation = operation_intersection;
ips[0].q_operation = union_or_blocked_same_dirs(arrival_b, is_q_last);
ips[1].p_operation = union_or_blocked_same_dirs(arrival_a, is_p_last);
ips[1].q_operation = operation_intersection;
i0_a = arrival_b != 1;
j0_b = arrival_b != -1;
j1_a = arrival_a != -1;
i1_b = arrival_a != 1;
ips[0].is_pi = arrival_b != 1;
ips[0].is_qj = arrival_b != -1;
ips[1].is_pj = arrival_a != -1;
ips[1].is_qi = arrival_a != 1;
}
}
else
{
BOOST_ASSERT(ip_count == 1);
op0_a = arrival_to_union_or_blocked(arrival_a, last_a);
op0_b = arrival_to_union_or_blocked(arrival_b, last_b);
BOOST_ASSERT(result.template get<0>().count == 1);
ips[0].p_operation = union_or_blocked_same_dirs(arrival_a, is_p_last);
ips[0].q_operation = union_or_blocked_same_dirs(arrival_b, is_q_last);
i0_a = how_a == -1;
i0_b = how_b == -1;
j0_a = arrival_a == 0;
j0_b = arrival_b == 0;
ips[0].is_pi = arrival_a == -1;
ips[0].is_qi = arrival_b == -1;
ips[0].is_pj = arrival_a == 0;
ips[0].is_qj = arrival_b == 0;
}
}
else
{
op0_a = how_to_union_or_blocked(how_a, last_a);
op0_b = how_to_union_or_blocked(how_b, last_b);
ips[0].p_operation = union_or_blocked_different_dirs(arrival_a, is_p_last);
ips[0].q_operation = union_or_blocked_different_dirs(arrival_b, is_q_last);
i0_a = how_a == -1;
i0_b = how_b == -1;
j0_a = how_a == 1;
j0_b = how_b == 1;
ips[0].is_pi = arrival_a == -1;
ips[0].is_qi = arrival_b == -1;
ips[0].is_pj = arrival_a == 1;
ips[0].is_qj = arrival_b == 1;
}
}
struct ip_info
{
inline ip_info()
: p_operation(operation_none), q_operation(operation_none)
, is_pi(false), is_pj(false), is_qi(false), is_qj(false)
{}
operation_type p_operation, q_operation;
bool is_pi, is_pj, is_qi, is_qj;
};
template <std::size_t I>
ip_info const& get() const
{
BOOST_STATIC_ASSERT(I < 2);
return ips[I];
}
private:
// only if collinear (same_dirs)
static inline operation_type arrival_to_union_or_blocked(int arrival, bool is_last)
static inline operation_type union_or_blocked_same_dirs(int arrival, bool is_last)
{
if ( arrival == 1 )
return operation_blocked;
@@ -292,75 +372,171 @@ struct get_turn_info_for_endpoint
}
// only if not collinear (!same_dirs)
static inline operation_type how_to_union_or_blocked(int how, bool is_last)
static inline operation_type union_or_blocked_different_dirs(int arrival, bool is_last)
{
if ( how == 1 )
if ( arrival == 1 )
//return operation_blocked;
return is_last ? operation_blocked : operation_union;
else
return operation_union;
}
ip_info ips[2];
};
template <typename AssignPolicy, bool EnableFirst, bool EnableLast>
struct get_turn_info_for_endpoint
{
BOOST_STATIC_ASSERT(EnableFirst || EnableLast);
template<typename Point1,
typename Point2,
typename TurnInfo,
typename IntersectionInfo,
typename OutputIterator
>
static inline bool apply(Point1 const& pi, Point1 const& pj, Point1 const& pk,
Point2 const& qi, Point2 const& qj, Point2 const& qk,
bool is_p_first, bool is_p_last,
bool is_q_first, bool is_q_last,
TurnInfo const& tp_model,
IntersectionInfo const& inters,
method_type /*method*/,
OutputIterator out)
{
std::size_t ip_count = inters.i_info().count;
// no intersection points
if ( ip_count == 0 )
return false;
int segment_index0 = tp_model.operations[0].seg_id.segment_index;
int segment_index1 = tp_model.operations[1].seg_id.segment_index;
BOOST_ASSERT(segment_index0 >= 0 && segment_index1 >= 0);
if ( !is_p_first && !is_p_last && !is_q_first && !is_q_last )
return false;
linear_intersections intersections(pi, qi, inters.result(), is_p_last, is_q_last);
bool append0_last
= analyse_segment_and_assign_ip(pi, pj, pk, qi, qj, qk,
is_p_first, is_p_last, is_q_first, is_q_last,
intersections.template get<0>(),
tp_model, inters, 0, out);
// NOTE: opposite && ip_count == 1 may be true!
bool opposite = inters.d_info().opposite;
// don't ignore only for collinear opposite
bool result_ignore_ip0 = append0_last && ( ip_count == 1 || !opposite );
if ( intersections.template get<1>().p_operation == operation_none )
return result_ignore_ip0;
bool append1_last
= analyse_segment_and_assign_ip(pi, pj, pk, qi, qj, qk,
is_p_first, is_p_last, is_q_first, is_q_last,
intersections.template get<1>(),
tp_model, inters, 1, out);
// don't ignore only for collinear opposite
bool result_ignore_ip1 = append1_last && !opposite /*&& ip_count == 2*/;
return result_ignore_ip0 || result_ignore_ip1;
}
template <typename Point1,
typename Point2,
typename Point,
typename TurnInfo,
typename IntersectionResult,
typename IntersectionInfo,
typename OutputIterator>
static inline
bool analyse_segment_and_assign_ip(Point1 const& pi, Point1 const& pj, Point1 const& pk,
Point2 const& qi, Point2 const& qj, Point2 const& qk,
Point const& ip,
bool is_p_first, bool is_p_last,
bool is_q_first, bool is_q_last,
bool is_pi_ip, bool is_pj_ip,
bool is_qi_ip, bool is_qj_ip,
operation_type p_operation,
operation_type q_operation,
linear_intersections::ip_info const& ip_info,
TurnInfo const& tp_model,
IntersectionResult const& result,
IntersectionInfo const& inters,
int ip_index,
OutputIterator out)
{
#ifdef BOOST_GEOMETRY_DEBUG_GET_TURNS_LINEAR_LINEAR
// may this give false positives for INTs?
BOOST_ASSERT(is_pi_ip == equals::equals_point_point(pi, ip));
BOOST_ASSERT(is_qi_ip == equals::equals_point_point(qi, ip));
BOOST_ASSERT(is_pj_ip == equals::equals_point_point(pj, ip));
BOOST_ASSERT(is_qj_ip == equals::equals_point_point(qj, ip));
typename IntersectionResult::point_type const&
inters_pt = result.template get<0>().intersections[ip_index];
BOOST_ASSERT(ip_info.is_pi == equals::equals_point_point(pi, inters_pt));
BOOST_ASSERT(ip_info.is_qi == equals::equals_point_point(qi, inters_pt));
BOOST_ASSERT(ip_info.is_pj == equals::equals_point_point(pj, inters_pt));
BOOST_ASSERT(ip_info.is_qj == equals::equals_point_point(qj, inters_pt));
#endif
// TODO - calculate first/last only if needed
bool is_p_first_ip = is_p_first && is_pi_ip;
bool is_p_last_ip = is_p_last && is_pj_ip;
bool is_q_first_ip = is_q_first && is_qi_ip;
bool is_q_last_ip = is_q_last && is_qj_ip;
bool is_p_first_ip = is_p_first && ip_info.is_pi;
bool is_p_last_ip = is_p_last && ip_info.is_pj;
bool is_q_first_ip = is_q_first && ip_info.is_qi;
bool is_q_last_ip = is_q_last && ip_info.is_qj;
bool append_first = EnableFirst && (is_p_first_ip || is_q_first_ip);
bool append_last = EnableLast && (is_p_last_ip || is_q_last_ip);
operation_type p_operation = ip_info.p_operation;
operation_type q_operation = ip_info.q_operation;
if ( append_first || append_last )
{
bool handled = handle_internal(pi, pj, pk, qi, qj, qk, ip,
bool handled = handle_internal(pi, pj, pk, qi, qj, qk,
is_p_first_ip, is_p_last_ip,
is_q_first_ip, is_q_last_ip,
is_qi_ip, is_qj_ip,
tp_model, result, p_operation, q_operation);
ip_info.is_qi, ip_info.is_qj,
tp_model, inters.result(), ip_index,
p_operation, q_operation);
if ( !handled )
{
handle_internal(qi, qj, qk, pi, pj, pk, ip,
handle_internal(qi, qj, qk, pi, pj, pk,
is_q_first_ip, is_q_last_ip,
is_p_first_ip, is_p_last_ip,
is_pi_ip, is_pj_ip,
tp_model, result, q_operation, p_operation);
ip_info.is_pi, ip_info.is_pj,
tp_model, inters.result(), ip_index,
q_operation, p_operation);
}
if ( p_operation != operation_none )
{
assign(pi, qi, result, ip,
endpoint_ip_method(is_pi_ip, is_pj_ip, is_qi_ip, is_qj_ip),
p_operation, q_operation,
ip_position(is_p_first_ip, is_p_last_ip),
ip_position(is_q_first_ip, is_q_last_ip),
tp_model, out);
method_type method = endpoint_ip_method(ip_info.is_pi, ip_info.is_pj,
ip_info.is_qi, ip_info.is_qj);
turn_position p_pos = ip_position(is_p_first_ip, is_p_last_ip);
turn_position q_pos = ip_position(is_q_first_ip, is_q_last_ip);
// handle spikes
// P is spike and should be handled
if ( !is_p_last
&& ip_info.is_pj // this check is redundant (also in is_spike_p) but faster
&& inters.i_info().count == 2
&& inters.is_spike_p() )
{
assign(pi, qi, inters.result(), ip_index, method, operation_blocked, q_operation,
p_pos, q_pos, tp_model, out);
assign(pi, qi, inters.result(), ip_index, method, operation_intersection, q_operation,
p_pos, q_pos, tp_model, out);
}
// Q is spike and should be handled
else if ( !is_q_last
&& ip_info.is_qj // this check is redundant (also in is_spike_q) but faster
&& inters.i_info().count == 2
&& inters.is_spike_q() )
{
assign(pi, qi, inters.result(), ip_index, method, p_operation, operation_blocked,
p_pos, q_pos, tp_model, out);
assign(pi, qi, inters.result(), ip_index, method, p_operation, operation_intersection,
p_pos, q_pos, tp_model, out);
}
// no spikes
else
{
assign(pi, qi, inters.result(), ip_index, method, p_operation, q_operation,
p_pos, q_pos, tp_model, out);
}
}
}
@@ -372,21 +548,17 @@ struct get_turn_info_for_endpoint
template<typename Point1,
typename Point2,
typename Point,
typename TurnInfo,
typename IntersectionResult
>
static inline bool handle_internal(Point1 const& i1, Point1 const& j1, Point1 const& /*k1*/,
Point2 const& i2, Point2 const& j2, Point2 const& k2,
Point const& ip,
bool first1, bool last1,
bool first2, bool last2,
bool ip_i2, bool ip_j2,
TurnInfo const& tp_model,
IntersectionResult const& result,
bool first1, bool last1, bool first2, bool last2,
bool ip_i2, bool ip_j2, TurnInfo const& tp_model,
IntersectionResult const& result, int ip_index,
operation_type & op1, operation_type & op2)
{
boost::ignore_unused_variable_warning(ip);
boost::ignore_unused_variable_warning(ip_index);
boost::ignore_unused_variable_warning(tp_model);
if ( !first2 && !last2 )
@@ -395,8 +567,10 @@ struct get_turn_info_for_endpoint
{
#ifdef BOOST_GEOMETRY_DEBUG_GET_TURNS_LINEAR_LINEAR
// may this give false positives for INTs?
BOOST_ASSERT(ip_i2 == equals::equals_point_point(i2, ip));
BOOST_ASSERT(ip_j2 == equals::equals_point_point(j2, ip));
typename IntersectionResult::point_type const&
inters_pt = result.template get<0>().intersections[ip_index];
BOOST_ASSERT(ip_i2 == equals::equals_point_point(i2, inters_pt));
BOOST_ASSERT(ip_j2 == equals::equals_point_point(j2, inters_pt));
#endif
if ( ip_i2 )
{
@@ -407,10 +581,7 @@ struct get_turn_info_for_endpoint
}
else if ( ip_j2 )
{
// NOTE: this conversion may be problematic
Point1 i2_conv;
geometry::convert(i2, i2_conv);
side_calculator<Point1, Point2> side_calc(i2_conv, i1, j1, i2, j2, k2);
side_calculator<Point1, Point2, Point2> side_calc(i2, i1, j1, i2, j2, k2);
std::pair<operation_type, operation_type>
operations = operations_of_equal(side_calc);
@@ -441,8 +612,10 @@ struct get_turn_info_for_endpoint
{
#ifdef BOOST_GEOMETRY_DEBUG_GET_TURNS_LINEAR_LINEAR
// may this give false positives for INTs?
BOOST_ASSERT(ip_i2 == equals::equals_point_point(i2, ip));
BOOST_ASSERT(ip_j2 == equals::equals_point_point(j2, ip));
typename IntersectionResult::point_type const&
inters_pt = result.template get<0>().intersections[ip_index];
BOOST_ASSERT(ip_i2 == equals::equals_point_point(i2, inters_pt));
BOOST_ASSERT(ip_j2 == equals::equals_point_point(j2, inters_pt));
#endif
if ( ip_i2 )
{
@@ -453,11 +626,7 @@ struct get_turn_info_for_endpoint
}
else if ( ip_j2 )
{
// NOTE: this conversion may be problematic
Point1 i2_conv;
geometry::convert(i2, i2_conv);
side_calculator<Point1, Point2> side_calc(i2_conv, j1, i1, i2, j2, k2);
side_calculator<Point1, Point2, Point2> side_calc(i2, j1, i1, i2, j2, k2);
std::pair<operation_type, operation_type>
operations = operations_of_equal(side_calc);
@@ -507,12 +676,11 @@ struct get_turn_info_for_endpoint
template <typename Point1,
typename Point2,
typename IntersectionResult,
typename Point,
typename TurnInfo,
typename OutputIterator>
static inline void assign(Point1 const& pi, Point2 const& qi,
IntersectionResult const& result,
Point const& ip,
int ip_index,
method_type method,
operation_type op0, operation_type op1,
turn_position pos0, turn_position pos1,
@@ -520,8 +688,11 @@ struct get_turn_info_for_endpoint
OutputIterator out)
{
TurnInfo tp = tp_model;
geometry::convert(ip, tp.point);
tp.method = method;
//geometry::convert(ip, tp.point);
//tp.method = method;
base_turn_handler::assign_point(tp, method, result.template get<0>(), ip_index);
tp.operations[0].operation = op0;
tp.operations[1].operation = op1;
tp.operations[0].position = pos0;

View File

@@ -28,12 +28,14 @@ namespace detail { namespace overlay {
template<typename AssignPolicy>
struct get_turn_info_linear_areal
{
static const bool handle_spikes = true;
template
<
typename Point1,
typename Point2,
typename TurnInfo,
typename RescalePolicy,
typename RobustPolicy,
typename OutputIterator
>
static inline OutputIterator apply(
@@ -42,29 +44,13 @@ struct get_turn_info_linear_areal
bool is_p_first, bool is_p_last,
bool is_q_first, bool is_q_last,
TurnInfo const& tp_model,
RescalePolicy const& , // TODO: this will be used. rescale_policy,
RobustPolicy const& robust_policy,
OutputIterator out)
{
typedef model::referring_segment<Point1 const> segment_type1;
typedef model::referring_segment<Point2 const> segment_type2;
segment_type1 p1(pi, pj), p2(pj, pk);
segment_type2 q1(qi, qj), q2(qj, qk);
intersection_info<Point1, Point2, typename TurnInfo::point_type, RobustPolicy>
inters(pi, pj, pk, qi, qj, qk, robust_policy);
side_calculator<Point1, Point2> side_calc(pi, pj, pk, qi, qj, qk);
typedef strategy_intersection
<
typename cs_tag<typename TurnInfo::point_type>::type,
Point1,
Point2,
typename TurnInfo::point_type
> si;
typedef typename si::segment_intersection_strategy_type strategy;
typename strategy::return_type result = strategy::apply(p1, q1);
char const method = result.template get<1>().how;
char const method = inters.d_info().how;
// Copy, to copy possibly extended fields
TurnInfo tp = tp_model;
@@ -78,7 +64,7 @@ struct get_turn_info_linear_areal
get_turn_info_for_endpoint<true, true>(
pi, pj, pk, qi, qj, qk,
is_p_first, is_p_last, is_q_first, is_q_last,
tp_model, result, method_none, out);
tp_model, inters.result(), method_none, out);
break;
case 'd' : // disjoint: never do anything
@@ -89,7 +75,7 @@ struct get_turn_info_linear_areal
if ( get_turn_info_for_endpoint<false, true>(
pi, pj, pk, qi, qj, qk,
is_p_first, is_p_last, is_q_first, is_q_last,
tp_model, result, method_touch_interior, out) )
tp_model, inters.result(), method_touch_interior, out) )
{
// do nothing
}
@@ -101,18 +87,18 @@ struct get_turn_info_linear_areal
> policy;
// If Q (1) arrives (1)
if (result.template get<1>().arrival[1] == 1)
if ( inters.d_info().arrival[1] == 1 )
{
policy::template apply<0>(pi, pj, pk, qi, qj, qk,
tp, result.template get<0>(), result.template get<1>(),
side_calc);
tp, inters.i_info(), inters.d_info(),
inters.sides());
}
else
{
// Swap p/q
side_calculator<Point1, Point2> swapped_side_calc(qi, qj, qk, pi, pj, pk);
side_calculator<Point2, Point1> swapped_side_calc(qi, qj, qk, pi, pj, pk);
policy::template apply<1>(qi, qj, qk, pi, pj, pk,
tp, result.template get<0>(), result.template get<1>(),
tp, inters.i_info(), inters.d_info(),
swapped_side_calc);
}
@@ -121,9 +107,16 @@ struct get_turn_info_linear_areal
tp.operations[0].is_collinear = true;
}
replace_method_and_operations_tm(tp.method, tp.operations[0].operation, tp.operations[1].operation);
replace_method_and_operations_tm(tp.method,
tp.operations[0].operation,
tp.operations[1].operation);
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
// this function assumes that 'u' must be set for a spike
calculate_spike_operation(tp.operations[0].operation,
inters, is_p_last);
AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
*out++ = tp;
}
}
@@ -131,11 +124,11 @@ struct get_turn_info_linear_areal
case 'i' :
{
crosses<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
tp, result.template get<0>(), result.template get<1>());
tp, inters.i_info(), inters.d_info());
replace_operations_i(tp.operations[0].operation, tp.operations[1].operation);
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
*out++ = tp;
}
break;
@@ -145,24 +138,39 @@ struct get_turn_info_linear_areal
if ( get_turn_info_for_endpoint<false, true>(
pi, pj, pk, qi, qj, qk,
is_p_first, is_p_last, is_q_first, is_q_last,
tp_model, result, method_touch, out) )
tp_model, inters.result(), method_touch, out) )
{
// do nothing
}
else
{
touch<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
tp, result.template get<0>(), result.template get<1>(), side_calc);
tp, inters.i_info(), inters.d_info(), inters.sides());
if ( tp.operations[1].operation == operation_blocked )
{
tp.operations[0].is_collinear = true;
}
replace_method_and_operations_tm(tp.method, tp.operations[0].operation, tp.operations[1].operation);
replace_method_and_operations_tm(tp.method,
tp.operations[0].operation,
tp.operations[1].operation);
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
*out++ = tp;
// this function assumes that 'u' must be set for a spike
bool ignore_spike
= calculate_spike_operation(tp.operations[0].operation,
inters, is_p_last);
// TODO: move this into the append_xxx and call for each turn?
AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
if ( ! handle_spikes
|| ignore_spike
|| ! append_opposite_spikes<append_touches>( // for 'i' or 'c'
tp, inters, is_p_last, is_q_last, out) )
{
*out++ = tp;
}
}
}
break;
@@ -171,7 +179,7 @@ struct get_turn_info_linear_areal
if ( get_turn_info_for_endpoint<true, true>(
pi, pj, pk, qi, qj, qk,
is_p_first, is_p_last, is_q_first, is_q_last,
tp_model, result, method_equal, out) )
tp_model, inters.result(), method_equal, out) )
{
// do nothing
}
@@ -179,26 +187,26 @@ struct get_turn_info_linear_areal
{
tp.operations[0].is_collinear = true;
if ( ! result.template get<1>().opposite )
if ( ! inters.d_info().opposite )
{
// Both equal
// or collinear-and-ending at intersection point
equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
tp, result.template get<0>(), result.template get<1>(), side_calc);
tp, inters.i_info(), inters.d_info(), inters.sides());
replacer_of_method_and_operations_ec<false> replacer(method_touch);
replacer(tp.method, tp.operations[0].operation, tp.operations[1].operation);
// TODO: This isn't correct handling, hence commented out
/*spike_detector<Point1, Point2> spike_detect(side_calc);
if ( tp.operations[0].operation == operation_union
&& spike_detect.is_spike_p())
// TODO: move this into the append_xxx and call for each turn?
AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
// conditionally handle spikes
if ( ! handle_spikes
|| ! append_collinear_spikes(tp, inters, is_p_last, is_q_last,
method_touch, append_equal, out) )
{
tp.operations[0].operation = operation_continue;
}*/
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
*out++ = tp;
*out++ = tp; // no spikes
}
}
else
{
@@ -207,7 +215,7 @@ struct get_turn_info_linear_areal
TurnInfo,
AssignPolicy
>::apply(pi, qi,
tp, out, result.template get<0>(), result.template get<1>());
tp, out, inters.i_info(), inters.d_info());
}
}
}
@@ -218,7 +226,7 @@ struct get_turn_info_linear_areal
if ( get_turn_info_for_endpoint<true, true>(
pi, pj, pk, qi, qj, qk,
is_p_first, is_p_last, is_q_first, is_q_last,
tp_model, result, method_collinear, out) )
tp_model, inters.result(), method_collinear, out) )
{
// do nothing
}
@@ -226,49 +234,67 @@ struct get_turn_info_linear_areal
{
tp.operations[0].is_collinear = true;
if (! result.template get<1>().opposite)
if ( ! inters.d_info().opposite )
{
if (result.template get<1>().arrival[0] == 0)
method_type method_replace = method_touch_interior;
append_version_c version = append_collinear;
if ( inters.d_info().arrival[0] == 0 )
{
// Collinear, but similar thus handled as equal
equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
tp, result.template get<0>(), result.template get<1>(), side_calc);
tp, inters.i_info(), inters.d_info(), inters.sides());
// TODO: This isn't correct handling, hence commented out
/*spike_detector<Point1, Point2> spike_detect(side_calc);
if ( tp.operations[0].operation == operation_union
&& spike_detect.is_spike_p())
{
tp.operations[0].operation = operation_continue;
}*/
replacer_of_method_and_operations_ec<false> replacer(method_touch);
replacer(tp.method, tp.operations[0].operation, tp.operations[1].operation);
method_replace = method_touch;
version = append_equal;
}
else
{
collinear<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
tp, result.template get<0>(), result.template get<1>(), side_calc);
tp, inters.i_info(), inters.d_info(), inters.sides());
replacer_of_method_and_operations_ec<false> replacer(method_touch_interior);
replacer(tp.method, tp.operations[0].operation, tp.operations[1].operation);
//method_replace = method_touch_interior;
//version = append_collinear;
}
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
*out++ = tp;
replacer_of_method_and_operations_ec<false> replacer(method_replace);
replacer(tp.method, tp.operations[0].operation, tp.operations[1].operation);
// TODO: move this into the append_xxx and call for each turn?
AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
// conditionally handle spikes
if ( ! handle_spikes
|| ! append_collinear_spikes(tp, inters, is_p_last, is_q_last,
method_replace, version, out) )
{
// no spikes
*out++ = tp;
}
}
else
{
// Is this always 'm' ?
replacer_of_method_and_operations_ec<false> replacer(method_touch_interior);
// conditionally handle spikes
if ( handle_spikes )
{
append_opposite_spikes<append_collinear_opposite>(
tp, inters, is_p_last, is_q_last, out);
}
// TODO: ignore for spikes?
// E.g. pass is_p_valid = !is_p_last && !is_pj_spike,
// the same with is_q_valid
collinear_opposite
<
TurnInfo,
AssignPolicy
>::apply(pi, pj, pk, qi, qj, qk,
tp, out, result.template get<0>(), result.template get<1>(), side_calc,
replacer);
tp, out, inters.i_info(), inters.d_info(),
inters.sides(), replacer);
}
}
}
@@ -278,8 +304,21 @@ struct get_turn_info_linear_areal
// degenerate points
if (AssignPolicy::include_degenerate)
{
only_convert<TurnInfo>::apply(tp, result.template get<0>());
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
only_convert::apply(tp, inters.i_info());
if ( is_p_first
&& equals::equals_point_point(pi, tp.point) )
{
tp.operations[0].position = position_front;
}
else if ( is_p_last
&& equals::equals_point_point(pj, tp.point) )
{
tp.operations[0].position = position_back;
}
// tp.operations[1].position = position_middle;
AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
*out++ = tp;
}
}
@@ -299,6 +338,128 @@ struct get_turn_info_linear_areal
return out;
}
template <typename Operation,
typename IntersectionInfo>
static inline bool calculate_spike_operation(Operation & op,
IntersectionInfo const& inters,
bool is_p_last)
{
bool is_p_spike = op == operation_union
&& ! is_p_last
&& inters.is_spike_p();
// we don't know where the spike is going since for both directions 'u' is set
if ( is_p_spike )
{
if ( inters.sides().pk_wrt_q1() < 0 && inters.sides().pk_wrt_q2() < 0 )
{
op = operation_intersection;
return true;
}
}
return false;
}
enum append_version_c { append_equal, append_collinear };
template <typename TurnInfo,
typename IntersectionInfo,
typename OutIt>
static inline bool append_collinear_spikes(TurnInfo & tp,
IntersectionInfo const& inters,
bool is_p_last, bool is_q_last,
method_type method, append_version_c version,
OutIt out)
{
// method == touch || touch_interior
// both position == middle
bool is_p_spike = ( version == append_equal ?
( tp.operations[0].operation == operation_union
|| tp.operations[0].operation == operation_intersection ) :
tp.operations[0].operation == operation_continue )
&& ! is_p_last
&& inters.is_spike_p();
// TODO: throw an exception for spike in Areal?
/*bool is_q_spike = tp.operations[1].operation == spike_op
&& ! is_q_last
&& inters.is_spike_q();*/
if ( is_p_spike )
{
tp.method = method;
tp.operations[0].operation = operation_blocked;
tp.operations[1].operation = operation_union;
*out++ = tp;
tp.operations[0].operation = operation_continue; // boundary
//tp.operations[1].operation = operation_union;
*out++ = tp;
return true;
}
return false;
}
enum append_version_o { append_touches, append_collinear_opposite };
template <append_version_o Version,
typename TurnInfo,
typename IntersectionInfo,
typename OutIt>
static inline bool append_opposite_spikes(TurnInfo & tp,
IntersectionInfo const& inters,
bool is_p_last, bool is_q_last,
OutIt out)
{
bool is_p_spike = ( Version == append_touches ?
( tp.operations[0].operation == operation_continue
|| tp.operations[0].operation == operation_intersection ) :
true )
&& ! is_p_last
&& inters.is_spike_p();
// TODO: throw an exception for spike in Areal?
/*bool is_q_spike = ( Version == append_touches ?
( tp.operations[1].operation == operation_continue
|| tp.operations[1].operation == operation_intersection ) :
true )
&& ! is_q_last
&& inters.is_spike_q();*/
if ( is_p_spike && ( Version == append_touches || inters.d_info().arrival[0] == 1 ) )
{
if ( Version == append_touches )
{
tp.operations[0].is_collinear = true;
//tp.operations[1].is_collinear = ???
tp.method = method_touch;
}
else
{
//tp.operations[0].is_collinear = true;
//tp.operations[1].is_collinear = true;
BOOST_ASSERT(inters.i_info().count > 1);
base_turn_handler::assign_point(tp, method_touch_interior, inters.i_info(), 1);
AssignPolicy::apply(tp, inters.pi(), inters.qi(), inters.i_info(), inters.d_info());
}
tp.operations[0].operation = operation_blocked;
tp.operations[1].operation = operation_continue; // boundary
*out++ = tp;
tp.operations[0].operation = operation_continue; // boundary
//tp.operations[1].operation = operation_continue; // boundary
*out++ = tp;
return true;
}
return false;
}
static inline void replace_method_and_operations_tm(method_type & method,
operation_type & op0,
operation_type & op1)
@@ -323,6 +484,14 @@ struct get_turn_info_linear_areal
{
op1 = operation_union;
}
// spikes in 'm'
if ( method == method_error )
{
method = method_touch_interior;
op0 = operation_union;
op1 = operation_union;
}
}
template <bool IsFront>
@@ -371,6 +540,10 @@ struct get_turn_info_linear_areal
op1 = operation_union;
}
// NOTE: Spikes may NOT be handled for Linear endpoints because it's not
// possible to define a spike on an endpoint. Areal geometries must
// NOT have spikes at all. One thing that could be done is to throw
// an exception when spike is detected in Areal geometry.
template <bool EnableFirst,
bool EnableLast,
@@ -404,38 +577,16 @@ struct get_turn_info_linear_areal
if ( !is_p_first && !is_p_last )
return false;
ov::operation_type p_operation0 = ov::operation_none;
ov::operation_type q_operation0 = ov::operation_none;
ov::operation_type p_operation1 = ov::operation_none;
ov::operation_type q_operation1 = ov::operation_none;
bool p0i, p0j, q0i, q0j; // assign false?
bool p1i, p1j, q1i, q1j; // assign false?
linear_intersections intersections(pi, qi, result, is_p_last, is_q_last);
linear_intersections::ip_info const& ip0 = intersections.template get<0>();
linear_intersections::ip_info const& ip1 = intersections.template get<1>();
const bool opposite = result.template get<1>().opposite;
const bool same_dirs = result.template get<1>().dir_a == 0 && result.template get<1>().dir_b == 0;
{
const int p_how = result.template get<1>().how_a;
const int q_how = result.template get<1>().how_b;
const int p_arrival = result.template get<1>().arrival[0];
const int q_arrival = result.template get<1>().arrival[1];
get_info_e::handle_segment(
is_p_first, is_p_last, p_how, p_arrival,
is_q_first, is_q_last, q_how, q_arrival,
opposite, ip_count, same_dirs,
result.template get<0>().intersections[0],
result.template get<0>().intersections[1],
p_operation0, q_operation0, p_operation1, q_operation1,
p0i, p0j, q0i, q0j,
p1i, p1j, q1i, q1j,
pi, pj, pk, qi, qj, qk);
}
// ANALYSE AND ASSIGN FIRST
// IP on the first point of Linear Geometry
if ( EnableFirst && is_p_first && p0i && !q0i ) // !q0i prevents duplication
if ( EnableFirst && is_p_first && ip0.is_pi && !ip0.is_qi ) // !q0i prevents duplication
{
TurnInfo tp = tp_model;
tp.operations[0].position = position_front;
@@ -445,19 +596,15 @@ struct get_turn_info_linear_areal
{
tp.operations[0].operation = operation_continue;
tp.operations[1].operation = operation_union;
tp.method = q0j ? method_touch : method_touch_interior;
tp.method = ip0.is_qj ? method_touch : method_touch_interior;
}
else
{
// NOTE: the conversion may be problematic
Point1 qi_conv;
geometry::convert(qi, qi_conv);
method_type replaced_method = method_touch_interior;
if ( q0j )
if ( ip0.is_qj )
{
side_calculator<Point1, Point2> side_calc(qi_conv, pi, pj, qi, qj, qk);
side_calculator<Point1, Point2, Point2> side_calc(qi, pi, pj, qi, qj, qk);
std::pair<operation_type, operation_type>
operations = get_info_e::operations_of_equal(side_calc);
@@ -469,11 +616,9 @@ struct get_turn_info_linear_areal
}
else
{
// NOTE: the conversion may be problematic
Point2 pi_conv;
geometry::convert(pi, pi_conv);
side_calculator<Point1, Point2> side_calc(qi_conv, pi, pj, qi, pi_conv, qj);
side_calculator<Point1, Point2,
Point2, Point1, Point1,
Point2, Point1, Point2> side_calc(qi, pi, pj, qi, pi, qj);
std::pair<operation_type, operation_type>
operations = get_info_e::operations_of_equal(side_calc);
@@ -488,7 +633,7 @@ struct get_turn_info_linear_areal
// equals<> or collinear<> will assign the second point,
// we'd like to assign the first one
geometry::convert(result.template get<0>().intersections[0], tp.point);
base_turn_handler::assign_point(tp, tp.method, result.template get<0>(), 0);
// NOTE: not really needed especially for the first point
// for which there is no preceding segment (but consistent with the L/L)
@@ -507,7 +652,7 @@ struct get_turn_info_linear_areal
// IP on the last point of Linear Geometry
if ( EnableLast
&& is_p_last
&& ( ip_count > 1 ? (p1j && !q1i) : (p0j && !q0i) ) ) // prevents duplication
&& ( ip_count > 1 ? (ip1.is_pj && !ip1.is_qi) : (ip0.is_pj && !ip0.is_qi) ) ) // prevents duplication
{
TurnInfo tp = tp_model;
@@ -519,9 +664,7 @@ struct get_turn_info_linear_areal
}
else //if ( result.template get<0>().count == 1 )
{
Point1 qi_conv;
geometry::convert(qi, qi_conv);
side_calculator<Point1, Point2> side_calc(qi_conv, pj, pi, qi, qj, qk);
side_calculator<Point1, Point2, Point2> side_calc(qi, pj, pi, qi, qj, qk);
std::pair<operation_type, operation_type>
operations = get_info_e::operations_of_equal(side_calc);
@@ -538,7 +681,7 @@ struct get_turn_info_linear_areal
}
}
tp.method = ( ip_count > 1 ? q1j : q0j ) ? method_touch : method_touch_interior;
tp.method = ( ip_count > 1 ? ip1.is_qj : ip0.is_qj ) ? method_touch : method_touch_interior;
tp.operations[0].operation = operation_blocked;
tp.operations[0].position = position_back;
tp.operations[1].position = position_middle;
@@ -546,7 +689,7 @@ struct get_turn_info_linear_areal
// equals<> or collinear<> will assign the second point,
// we'd like to assign the first one
std::size_t ip_index = ip_count > 1 ? 1 : 0;
geometry::convert(result.template get<0>().intersections[ip_index], tp.point);
base_turn_handler::assign_point(tp, tp.method, result.template get<0>(), ip_index);
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
*out++ = tp;

View File

@@ -22,71 +22,17 @@ namespace boost { namespace geometry {
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace overlay {
template <typename Point1,
typename Point2,
typename SideCalc = side_calculator<Point1, Point2> >
class spike_detector
{
public:
explicit spike_detector(SideCalc const& side_calc)
: m_side_calc(side_calc)
{}
inline bool is_spike_p() const
{
if ( m_side_calc.pk_wrt_p1() == 0 )
{
int const qk_p1 = m_side_calc.qk_wrt_p1();
int const qk_p2 = m_side_calc.qk_wrt_p2();
if ( qk_p1 == -qk_p2 )
{
if ( qk_p1 == 0 )
{
// TODO check additional things
}
return true;
}
}
return false;
}
inline bool is_spike_q() const
{
if ( m_side_calc.qk_wrt_q1() == 0 )
{
int const pk_q1 = m_side_calc.pk_wrt_q1();
int const pk_q2 = m_side_calc.pk_wrt_q2();
if ( pk_q1 == -pk_q2 )
{
if ( pk_q1 == 0 )
{
// TODO check additional things
}
return true;
}
}
return false;
}
private:
SideCalc const& m_side_calc;
};
template<typename AssignPolicy>
struct get_turn_info_linear_linear
{
static const bool handle_spikes = true;
template
<
typename Point1,
typename Point2,
typename TurnInfo,
typename RescalePolicy,
typename RobustPolicy,
typename OutputIterator
>
static inline OutputIterator apply(
@@ -95,29 +41,13 @@ struct get_turn_info_linear_linear
bool is_p_first, bool is_p_last,
bool is_q_first, bool is_q_last,
TurnInfo const& tp_model,
RescalePolicy const& , // TODO: this will be used. rescale_policy,
RobustPolicy const& robust_policy,
OutputIterator out)
{
typedef model::referring_segment<Point1 const> segment_type1;
typedef model::referring_segment<Point2 const> segment_type2;
segment_type1 p1(pi, pj), p2(pj, pk);
segment_type2 q1(qi, qj), q2(qj, qk);
intersection_info<Point1, Point2, typename TurnInfo::point_type, RobustPolicy>
inters(pi, pj, pk, qi, qj, qk, robust_policy);
side_calculator<Point1, Point2> side_calc(pi, pj, pk, qi, qj, qk);
typedef strategy_intersection
<
typename cs_tag<typename TurnInfo::point_type>::type,
Point1,
Point2,
typename TurnInfo::point_type
> si;
typedef typename si::segment_intersection_strategy_type strategy;
typename strategy::return_type result = strategy::apply(p1, q1);
char const method = result.template get<1>().how;
char const method = inters.d_info().how;
// Copy, to copy possibly extended fields
TurnInfo tp = tp_model;
@@ -131,7 +61,7 @@ struct get_turn_info_linear_linear
get_turn_info_for_endpoint<AssignPolicy, true, true>
::apply(pi, pj, pk, qi, qj, qk,
is_p_first, is_p_last, is_q_first, is_q_last,
tp_model, result, method_none, out);
tp_model, inters, method_none, out);
break;
case 'd' : // disjoint: never do anything
@@ -142,7 +72,7 @@ struct get_turn_info_linear_linear
if ( get_turn_info_for_endpoint<AssignPolicy, false, true>
::apply(pi, pj, pk, qi, qj, qk,
is_p_first, is_p_last, is_q_first, is_q_last,
tp_model, result, method_touch_interior, out) )
tp_model, inters, method_touch_interior, out) )
{
// do nothing
}
@@ -154,21 +84,21 @@ struct get_turn_info_linear_linear
> policy;
// If Q (1) arrives (1)
if (result.template get<1>().arrival[1] == 1)
if ( inters.d_info().arrival[1] == 1)
{
policy::template apply<0>(pi, pj, pk, qi, qj, qk,
tp, result.template get<0>(), result.template get<1>(),
side_calc);
tp, inters.i_info(), inters.d_info(),
inters.sides());
}
else
{
// Swap p/q
side_calculator<Point1, Point2> swapped_side_calc(qi, qj, qk, pi, pj, pk);
side_calculator<Point2, Point1> swapped_side_calc(qi, qj, qk, pi, pj, pk);
policy::template apply<1>(qi, qj, qk, pi, pj, pk,
tp, result.template get<0>(), result.template get<1>(),
swapped_side_calc);
tp, inters.i_info(), inters.d_info(),
swapped_side_calc);
}
if ( tp.operations[0].operation == operation_blocked )
{
tp.operations[1].is_collinear = true;
@@ -178,9 +108,11 @@ struct get_turn_info_linear_linear
tp.operations[0].is_collinear = true;
}
replace_method_and_operations_tm(tp.method, tp.operations[0].operation, tp.operations[1].operation);
replace_method_and_operations_tm(tp.method,
tp.operations[0].operation,
tp.operations[1].operation);
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
*out++ = tp;
}
}
@@ -188,11 +120,11 @@ struct get_turn_info_linear_linear
case 'i' :
{
crosses<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
tp, result.template get<0>(), result.template get<1>());
tp, inters.i_info(), inters.d_info());
replace_operations_i(tp.operations[0].operation, tp.operations[1].operation);
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
*out++ = tp;
}
break;
@@ -202,14 +134,14 @@ struct get_turn_info_linear_linear
if ( get_turn_info_for_endpoint<AssignPolicy, false, true>
::apply(pi, pj, pk, qi, qj, qk,
is_p_first, is_p_last, is_q_first, is_q_last,
tp_model, result, method_touch, out) )
tp_model, inters, method_touch, out) )
{
// do nothing
}
else
{
touch<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
tp, result.template get<0>(), result.template get<1>(), side_calc);
tp, inters.i_info(), inters.d_info(), inters.sides());
if ( tp.operations[0].operation == operation_blocked )
{
@@ -220,10 +152,20 @@ struct get_turn_info_linear_linear
tp.operations[0].is_collinear = true;
}
replace_method_and_operations_tm(tp.method, tp.operations[0].operation, tp.operations[1].operation);
replace_method_and_operations_tm(tp.method,
tp.operations[0].operation,
tp.operations[1].operation);
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
*out++ = tp;
// TODO: move this into the append_xxx and call for each turn?
AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
if ( ! handle_spikes
|| ! append_opposite_spikes<append_touches>(tp, inters,
is_p_last, is_q_last,
out) )
{
*out++ = tp;
}
}
}
break;
@@ -232,7 +174,7 @@ struct get_turn_info_linear_linear
if ( get_turn_info_for_endpoint<AssignPolicy, true, true>
::apply(pi, pj, pk, qi, qj, qk,
is_p_first, is_p_last, is_q_first, is_q_last,
tp_model, result, method_equal, out) )
tp_model, inters, method_equal, out) )
{
// do nothing
}
@@ -241,40 +183,38 @@ struct get_turn_info_linear_linear
tp.operations[0].is_collinear = true;
tp.operations[1].is_collinear = true;
if ( ! result.template get<1>().opposite )
if ( ! inters.d_info().opposite )
{
// Both equal
// or collinear-and-ending at intersection point
equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
tp, result.template get<0>(), result.template get<1>(), side_calc);
tp, inters.i_info(), inters.d_info(), inters.sides());
replacer_of_method_and_operations_ec replacer(method_touch);
replacer(tp.method, tp.operations[0].operation, tp.operations[1].operation);
// TODO: This isn't correct handling, hence commented out
/*spike_detector<Point1, Point2> spike_detect(side_calc);
if ( tp.operations[0].operation == operation_union
&& spike_detect.is_spike_p())
// TODO: move this into the append_xxx and call for each turn?
AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
// conditionally handle spikes
if ( ! handle_spikes
|| ! append_collinear_spikes(tp, inters,
is_p_last, is_q_last,
method_touch, operation_union,
out) )
{
tp.operations[0].operation = operation_continue;
*out++ = tp; // no spikes
}
if ( tp.operations[1].operation == operation_union
&& spike_detect.is_spike_q())
{
tp.operations[1].operation = operation_continue;
}*/
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
*out++ = tp;
}
else
{
// TODO: ignore for spikes or generate something else than opposite?
equal_opposite
<
TurnInfo,
AssignPolicy
>::apply(pi, qi,
tp, out, result.template get<0>(), result.template get<1>());
>::apply(pi, qi, tp, out, inters.i_info(), inters.d_info());
}
}
}
@@ -285,7 +225,7 @@ struct get_turn_info_linear_linear
if ( get_turn_info_for_endpoint<AssignPolicy, true, true>
::apply(pi, pj, pk, qi, qj, qk,
is_p_first, is_p_last, is_q_first, is_q_last,
tp_model, result, method_collinear, out) )
tp_model, inters, method_collinear, out) )
{
// do nothing
}
@@ -294,63 +234,69 @@ struct get_turn_info_linear_linear
tp.operations[0].is_collinear = true;
tp.operations[1].is_collinear = true;
if (! result.template get<1>().opposite)
{
if (result.template get<1>().arrival[0] == 0)
if ( ! inters.d_info().opposite )
{
method_type method_replace = method_touch_interior;
operation_type spike_op = operation_continue;
if ( inters.d_info().arrival[0] == 0 )
{
// Collinear, but similar thus handled as equal
equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
tp, result.template get<0>(), result.template get<1>(), side_calc);
tp, inters.i_info(), inters.d_info(), inters.sides());
// NOTE: don't change the method only if methods are WRT IPs, not segments!
// (currently this approach is used)
// override assigned method
//tp.method = method_collinear;
replacer_of_method_and_operations_ec replacer(method_touch);
replacer(tp.method, tp.operations[0].operation, tp.operations[1].operation);
// TODO: This isn't correct handling, hence commented out
/*spike_detector<Point1, Point2> spike_detect(side_calc);
if ( tp.operations[0].operation == operation_union
&& spike_detect.is_spike_p())
{
tp.operations[0].operation = operation_continue;
}
if ( tp.operations[1].operation == operation_union
&& spike_detect.is_spike_q())
{
tp.operations[1].operation = operation_continue;
}*/
method_replace = method_touch;
spike_op = operation_union;
}
else
{
collinear<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
tp, result.template get<0>(), result.template get<1>(), side_calc);
tp, inters.i_info(), inters.d_info(), inters.sides());
replacer_of_method_and_operations_ec replacer(method_touch_interior);
replacer(tp.method, tp.operations[0].operation, tp.operations[1].operation);
// TEST
//spike_detector<Point1, Point2> spike_detect(side_calc);
//spike_detect.is_spike_p();
//spike_detect.is_spike_q();
//method_replace = method_touch_interior;
//spike_op = operation_continue;
}
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
*out++ = tp;
replacer_of_method_and_operations_ec replacer(method_replace);
replacer(tp.method, tp.operations[0].operation, tp.operations[1].operation);
// TODO: move this into the append_xxx and call for each turn?
AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
// conditionally handle spikes
if ( ! handle_spikes
|| ! append_collinear_spikes(tp, inters,
is_p_last, is_q_last,
method_replace, spike_op,
out) )
{
// no spikes
*out++ = tp;
}
}
else
{
// If this always 'm' ?
replacer_of_method_and_operations_ec replacer(method_touch_interior);
// conditionally handle spikes
if ( handle_spikes )
{
append_opposite_spikes<append_collinear_opposite>(tp, inters,
is_p_last, is_q_last,
out);
}
// TODO: ignore for spikes?
// E.g. pass is_p_valid = !is_p_last && !is_pj_spike,
// the same with is_q_valid
collinear_opposite
<
TurnInfo,
AssignPolicy
>::apply(pi, pj, pk, qi, qj, qk,
tp, out, result.template get<0>(), result.template get<1>(), side_calc,
tp, out, inters.i_info(), inters.d_info(), inters.sides(),
replacer, !is_p_last, !is_q_last);
}
}
@@ -361,8 +307,31 @@ struct get_turn_info_linear_linear
// degenerate points
if (AssignPolicy::include_degenerate)
{
only_convert<TurnInfo>::apply(tp, result.template get<0>());
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
only_convert::apply(tp, inters.i_info());
// if any, only one of those should be true
if ( is_p_first
&& equals::equals_point_point(pi, tp.point) )
{
tp.operations[0].position = position_front;
}
else if ( is_p_last
&& equals::equals_point_point(pj, tp.point) )
{
tp.operations[0].position = position_back;
}
else if ( is_q_first
&& equals::equals_point_point(qi, tp.point) )
{
tp.operations[1].position = position_front;
}
else if ( is_q_last
&& equals::equals_point_point(qj, tp.point) )
{
tp.operations[1].position = position_back;
}
AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
*out++ = tp;
}
}
@@ -382,6 +351,157 @@ struct get_turn_info_linear_linear
return out;
}
template <typename TurnInfo,
typename IntersectionInfo,
typename OutIt>
static inline bool append_collinear_spikes(TurnInfo & tp,
IntersectionInfo const& inters_info,
bool is_p_last, bool is_q_last,
method_type method, operation_type spike_op,
OutIt out)
{
// method == touch || touch_interior
// both position == middle
bool is_p_spike = tp.operations[0].operation == spike_op
&& ! is_p_last
&& inters_info.is_spike_p();
bool is_q_spike = tp.operations[1].operation == spike_op
&& ! is_q_last
&& inters_info.is_spike_q();
if ( is_p_spike && is_q_spike )
{
tp.method = method;
tp.operations[0].operation = operation_blocked;
tp.operations[1].operation = operation_blocked;
*out++ = tp;
tp.operations[0].operation = operation_intersection;
tp.operations[1].operation = operation_intersection;
*out++ = tp;
return true;
}
else if ( is_p_spike )
{
tp.method = method;
tp.operations[0].operation = operation_blocked;
tp.operations[1].operation = operation_union;
*out++ = tp;
tp.operations[0].operation = operation_intersection;
//tp.operations[1].operation = operation_union;
*out++ = tp;
return true;
}
else if ( is_q_spike )
{
tp.method = method;
tp.operations[0].operation = operation_union;
tp.operations[1].operation = operation_blocked;
*out++ = tp;
//tp.operations[0].operation = operation_union;
tp.operations[1].operation = operation_intersection;
*out++ = tp;
return true;
}
return false;
}
enum append_version { append_touches, append_collinear_opposite };
template <append_version Version,
typename TurnInfo,
typename IntersectionInfo,
typename OutIt>
static inline bool append_opposite_spikes(TurnInfo & tp,
IntersectionInfo const& inters,
bool is_p_last, bool is_q_last,
OutIt out)
{
bool is_p_spike = ( Version == append_touches ?
( tp.operations[0].operation == operation_continue
|| tp.operations[0].operation == operation_intersection ) :
true )
&& ! is_p_last
&& inters.is_spike_p();
bool is_q_spike = ( Version == append_touches ?
( tp.operations[1].operation == operation_continue
|| tp.operations[1].operation == operation_intersection ) :
true )
&& ! is_q_last
&& inters.is_spike_q();
bool res = false;
if ( is_p_spike && ( Version == append_touches || inters.d_info().arrival[0] == 1 ) )
{
if ( Version == append_touches )
{
tp.operations[0].is_collinear = true;
//tp.operations[1].is_collinear = ???
tp.method = method_touch;
}
else
{
//tp.operations[0].is_collinear = true;
//tp.operations[1].is_collinear = true;
BOOST_ASSERT(inters.i_info().count > 1);
base_turn_handler::assign_point(tp, method_touch_interior,
inters.i_info(), 1);
AssignPolicy::apply(tp, inters.pi(), inters.qi(),
inters.i_info(), inters.d_info());
}
tp.operations[0].operation = operation_blocked;
tp.operations[1].operation = operation_intersection;
*out++ = tp;
tp.operations[0].operation = operation_intersection;
//tp.operations[1].operation = operation_intersection;
*out++ = tp;
res = true;
}
if ( is_q_spike && ( Version == append_touches || inters.d_info().arrival[1] == 1 ) )
{
if ( Version == append_touches )
{
//tp.operations[0].is_collinear = ???
tp.operations[1].is_collinear = true;
tp.method = method_touch;
}
else
{
//tp.operations[0].is_collinear = true;
//tp.operations[1].is_collinear = true;
BOOST_ASSERT(inters.i_info().count > 0);
base_turn_handler::assign_point(tp, method_touch_interior, inters.i_info(), 0);
AssignPolicy::apply(tp, inters.pi(), inters.qi(),
inters.i_info(), inters.d_info());
}
tp.operations[0].operation = operation_intersection;
tp.operations[1].operation = operation_blocked;
*out++ = tp;
//tp.operations[0].operation = operation_intersection;
tp.operations[1].operation = operation_intersection;
*out++ = tp;
res = true;
}
return res;
}
static inline void replace_method_and_operations_tm(method_type & method,
operation_type & op0,
operation_type & op1)
@@ -412,6 +532,14 @@ struct get_turn_info_linear_linear
{
op1 = operation_union;
}
// spikes in 'm'
if ( method == method_error )
{
method = method_touch_interior;
op0 = operation_union;
op1 = operation_union;
}
}
}

View File

@@ -51,6 +51,7 @@
#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
#include <boost/geometry/algorithms/detail/disjoint/point_point.hpp>
#include <boost/geometry/algorithms/detail/partition.hpp>
#include <boost/geometry/algorithms/detail/recalculate.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp>
@@ -171,12 +172,12 @@ class get_turns_in_sections
public :
// Returns true if terminated, false if interrupted
template <typename Turns, typename RescalePolicy, typename InterruptPolicy>
template <typename Turns, typename RobustPolicy, typename InterruptPolicy>
static inline bool apply(
int source_id1, Geometry1 const& geometry1, Section1 const& sec1,
int source_id2, Geometry2 const& geometry2, Section2 const& sec2,
bool skip_larger,
RescalePolicy const& rescale_policy,
RobustPolicy const& robust_policy,
Turns& turns,
InterruptPolicy& interrupt_policy)
{
@@ -216,7 +217,7 @@ public :
range1_iterator prev1, it1, end1;
get_start_point_iterator(sec1, view1, prev1, it1, end1,
index1, ndi1, dir1, sec2.bounding_box, rescale_policy);
index1, ndi1, dir1, sec2.bounding_box, robust_policy);
// We need a circular iterator because it might run through the closing point.
// One circle is actually enough but this one is just convenient.
@@ -227,12 +228,12 @@ public :
// section 2: [--------------]
// section 1: |----|---|---|---|---|
for (prev1 = it1++, next1++;
it1 != end1 && ! exceeding<0>(dir1, *prev1, sec2.bounding_box, rescale_policy);
it1 != end1 && ! exceeding<0>(dir1, *prev1, sec2.bounding_box, robust_policy);
++prev1, ++it1, ++index1, ++next1, ++ndi1)
{
ever_circling_iterator<range1_iterator> nd_next1(
begin_range_1, end_range_1, next1, true);
advance_to_non_duplicate_next(nd_next1, it1, sec1, rescale_policy);
advance_to_non_duplicate_next(nd_next1, it1, sec1, robust_policy);
int index2 = sec2.begin_index;
int ndi2 = sec2.non_duplicate_index;
@@ -240,12 +241,12 @@ public :
range2_iterator prev2, it2, end2;
get_start_point_iterator(sec2, view2, prev2, it2, end2,
index2, ndi2, dir2, sec1.bounding_box, rescale_policy);
index2, ndi2, dir2, sec1.bounding_box, robust_policy);
ever_circling_iterator<range2_iterator> next2(begin_range_2, end_range_2, it2, true);
next2++;
for (prev2 = it2++, next2++;
it2 != end2 && ! exceeding<0>(dir2, *prev2, sec1.bounding_box, rescale_policy);
it2 != end2 && ! exceeding<0>(dir2, *prev2, sec1.bounding_box, robust_policy);
++prev2, ++it2, ++index2, ++next2, ++ndi2)
{
bool skip = same_source;
@@ -271,7 +272,7 @@ public :
// Move to the "non duplicate next"
ever_circling_iterator<range2_iterator> nd_next2(
begin_range_2, end_range_2, next2, true);
advance_to_non_duplicate_next(nd_next2, it2, sec2, rescale_policy);
advance_to_non_duplicate_next(nd_next2, it2, sec2, robust_policy);
typedef typename boost::range_value<Turns>::type turn_info;
@@ -293,7 +294,7 @@ public :
TurnPolicy::apply(*prev1, *it1, *nd_next1, *prev2, *it2, *nd_next2,
is_1_first, is_1_last, is_2_first, is_2_last,
ti, rescale_policy, std::back_inserter(turns));
ti, robust_policy, std::back_inserter(turns));
if (InterruptPolicy::enabled)
{
@@ -318,27 +319,34 @@ private :
typedef typename model::referring_segment<point2_type const> segment2_type;
template <size_t Dim, typename Point, typename Box, typename RescalePolicy>
static inline bool preceding(int dir, Point const& point, Box const& box, RescalePolicy const& rescale_policy)
template <size_t Dim, typename Point, typename Box, typename RobustPolicy>
static inline bool preceding(int dir, Point const& point, Box const& box, RobustPolicy const& robust_policy)
{
boost::ignore_unused_variable_warning(rescale_policy);
return (dir == 1 && get<Dim>(point) < get<min_corner, Dim>(box))
|| (dir == -1 && get<Dim>(point) > get<max_corner, Dim>(box));
typename robust_point_type<Point, RobustPolicy>::type robust_point;
geometry::recalculate(robust_point, point, robust_policy);
return (dir == 1 && get<Dim>(robust_point) < get<min_corner, Dim>(box))
|| (dir == -1 && get<Dim>(robust_point) > get<max_corner, Dim>(box));
}
template <size_t Dim, typename Point, typename Box, typename RescalePolicy>
static inline bool exceeding(int dir, Point const& point, Box const& box, RescalePolicy const& rescale_policy)
template <size_t Dim, typename Point, typename Box, typename RobustPolicy>
static inline bool exceeding(int dir, Point const& point, Box const& box, RobustPolicy const& robust_policy)
{
boost::ignore_unused_variable_warning(rescale_policy);
return (dir == 1 && get<Dim>(point) > get<max_corner, Dim>(box))
|| (dir == -1 && get<Dim>(point) < get<min_corner, Dim>(box));
typename robust_point_type<Point, RobustPolicy>::type robust_point;
geometry::recalculate(robust_point, point, robust_policy);
return (dir == 1 && get<Dim>(robust_point) > get<max_corner, Dim>(box))
|| (dir == -1 && get<Dim>(robust_point) < get<min_corner, Dim>(box));
}
template <typename Iterator, typename RangeIterator, typename Section, typename RescalePolicy>
template <typename Iterator, typename RangeIterator, typename Section, typename RobustPolicy>
static inline void advance_to_non_duplicate_next(Iterator& next,
RangeIterator const& it, Section const& section, RescalePolicy const& rescale_policy)
RangeIterator const& it, Section const& section, RobustPolicy const& robust_policy)
{
boost::ignore_unused_variable_warning(rescale_policy);
typedef typename robust_point_type<point1_type, RobustPolicy>::type robust_point_type;
robust_point_type robust_point_from_it;
robust_point_type robust_point_from_next;
geometry::recalculate(robust_point_from_it, *it, robust_policy);
geometry::recalculate(robust_point_from_next, *next, robust_policy);
// To see where the next segments bend to, in case of touch/intersections
// on end points, we need (in case of degenerate/duplicate points) an extra
// iterator which moves to the REAL next point, so non duplicate.
@@ -349,10 +357,14 @@ private :
// So advance to the "non duplicate next"
// (the check is defensive, to avoid endless loops)
std::size_t check = 0;
while(! detail::disjoint::disjoint_point_point(*it, *next)
while(! detail::disjoint::disjoint_point_point
(
robust_point_from_it, robust_point_from_next
)
&& check++ < section.range_count)
{
next++;
geometry::recalculate(robust_point_from_next, *next, robust_policy);
}
}
@@ -360,14 +372,14 @@ private :
// because of the logistics of "index" (the section-iterator automatically
// skips to the begin-point, we loose the index or have to recalculate it)
// So we mimic it here
template <typename Range, typename Section, typename Box, typename RescalePolicy>
template <typename Range, typename Section, typename Box, typename RobustPolicy>
static inline void get_start_point_iterator(Section & section,
Range const& range,
typename boost::range_iterator<Range const>::type& it,
typename boost::range_iterator<Range const>::type& prev,
typename boost::range_iterator<Range const>::type& end,
int& index, int& ndi,
int dir, Box const& other_bounding_box, RescalePolicy const& rescale_policy)
int dir, Box const& other_bounding_box, RobustPolicy const& robust_policy)
{
it = boost::begin(range) + section.begin_index;
end = boost::begin(range) + section.end_index + 1;
@@ -375,7 +387,7 @@ private :
// Mimic section-iterator:
// Skip to point such that section interects other box
prev = it++;
for(; it != end && preceding<0>(dir, *it, other_bounding_box, rescale_policy);
for(; it != end && preceding<0>(dir, *it, other_bounding_box, robust_policy);
prev = it++, index++, ndi++)
{}
// Go back one step because we want to start completely preceding
@@ -407,7 +419,7 @@ template
bool Reverse1, bool Reverse2,
typename Turns,
typename TurnPolicy,
typename RescalePolicy,
typename RobustPolicy,
typename InterruptPolicy
>
struct section_visitor
@@ -416,17 +428,17 @@ struct section_visitor
Geometry1 const& m_geometry1;
int m_source_id2;
Geometry2 const& m_geometry2;
RescalePolicy const& m_rescale_policy;
RobustPolicy const& m_rescale_policy;
Turns& m_turns;
InterruptPolicy& m_interrupt_policy;
section_visitor(int id1, Geometry1 const& g1,
int id2, Geometry2 const& g2,
RescalePolicy const& rescale_policy,
RobustPolicy const& robust_policy,
Turns& turns, InterruptPolicy& ip)
: m_source_id1(id1), m_geometry1(g1)
, m_source_id2(id2), m_geometry2(g2)
, m_rescale_policy(rescale_policy)
, m_rescale_policy(robust_policy)
, m_turns(turns)
, m_interrupt_policy(ip)
{}
@@ -465,32 +477,39 @@ class get_turns_generic
{
public:
template <typename RescalePolicy, typename Turns, typename InterruptPolicy>
template <typename RobustPolicy, typename Turns, typename InterruptPolicy>
static inline void apply(
int source_id1, Geometry1 const& geometry1,
int source_id2, Geometry2 const& geometry2,
RescalePolicy const& rescale_policy,
RobustPolicy const& robust_policy,
Turns& turns,
InterruptPolicy& interrupt_policy)
{
// First create monotonic sections...
typedef typename boost::range_value<Turns>::type ip_type;
typedef typename ip_type::point_type point_type;
typedef model::box<point_type> box_type;
typedef model::box
<
typename geometry::robust_point_type
<
point_type, RobustPolicy
>::type
> box_type;
typedef typename geometry::sections<box_type, 2> sections_type;
sections_type sec1, sec2;
geometry::sectionalize<Reverse1>(geometry1, rescale_policy, true, sec1, 0);
geometry::sectionalize<Reverse2>(geometry2, rescale_policy, true, sec2, 1);
geometry::sectionalize<Reverse1>(geometry1, robust_policy, true, sec1, 0);
geometry::sectionalize<Reverse2>(geometry2, robust_policy, true, sec2, 1);
// ... and then partition them, intersecting overlapping sections in visitor method
section_visitor
<
Geometry1, Geometry2,
Reverse1, Reverse2,
Turns, TurnPolicy, RescalePolicy, InterruptPolicy
> visitor(source_id1, geometry1, source_id2, geometry2, rescale_policy, turns, interrupt_policy);
Turns, TurnPolicy, RobustPolicy, InterruptPolicy
> visitor(source_id1, geometry1, source_id2, geometry2, robust_policy, turns, interrupt_policy);
geometry::partition
<
@@ -530,11 +549,11 @@ struct get_turns_cs
>::type iterator_type;
template <typename RescalePolicy, typename Turns, typename InterruptPolicy>
template <typename RobustPolicy, typename Turns, typename InterruptPolicy>
static inline void apply(
int source_id1, Range const& range,
int source_id2, Box const& box,
RescalePolicy const& rescale_policy,
RobustPolicy const& robust_policy,
Turns& turns,
InterruptPolicy& interrupt_policy,
int multi_index = -1, int ring_index = -1)
@@ -605,7 +624,7 @@ struct get_turns_cs
// NOTE: some dummy values could be passed below since this would be called only for Polygons and Boxes
index == 0,
unsigned(index) == segments_count1,
rescale_policy,
robust_policy,
turns, interrupt_policy);
// Future performance enhancement:
// return if told by the interrupt policy
@@ -634,7 +653,7 @@ private:
else return 0;
}
template <typename RescalePolicy, typename Turns, typename InterruptPolicy>
template <typename RobustPolicy, typename Turns, typename InterruptPolicy>
static inline void get_turns_with_box(segment_identifier const& seg_id, int source_id2,
// Points from a range:
point_type const& rp0,
@@ -647,7 +666,7 @@ private:
box_point_type const& bp3,
bool const is_range_first,
bool const is_range_last,
RescalePolicy const& rescale_policy,
RobustPolicy const& robust_policy,
// Output
Turns& turns,
InterruptPolicy& interrupt_policy)
@@ -667,25 +686,25 @@ private:
TurnPolicy::apply(rp0, rp1, rp2, bp0, bp1, bp2,
is_range_first, is_range_last,
true, false,
ti, rescale_policy, std::back_inserter(turns));
ti, robust_policy, std::back_inserter(turns));
ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 1);
TurnPolicy::apply(rp0, rp1, rp2, bp1, bp2, bp3,
is_range_first, is_range_last,
false, false,
ti, rescale_policy, std::back_inserter(turns));
ti, robust_policy, std::back_inserter(turns));
ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 2);
TurnPolicy::apply(rp0, rp1, rp2, bp2, bp3, bp0,
is_range_first, is_range_last,
false, false,
ti, rescale_policy, std::back_inserter(turns));
ti, robust_policy, std::back_inserter(turns));
ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 3);
TurnPolicy::apply(rp0, rp1, rp2, bp3, bp0, bp1,
is_range_first, is_range_last,
false, true,
ti, rescale_policy, std::back_inserter(turns));
ti, robust_policy, std::back_inserter(turns));
if (InterruptPolicy::enabled)
{
@@ -705,11 +724,11 @@ template
>
struct get_turns_polygon_cs
{
template <typename RescalePolicy, typename Turns, typename InterruptPolicy>
template <typename RobustPolicy, typename Turns, typename InterruptPolicy>
static inline void apply(
int source_id1, Polygon const& polygon,
int source_id2, Box const& box,
RescalePolicy const& rescale_policy,
RobustPolicy const& robust_policy,
Turns& turns, InterruptPolicy& interrupt_policy,
int multi_index = -1)
{
@@ -725,7 +744,7 @@ struct get_turns_polygon_cs
intersector_type::apply(
source_id1, geometry::exterior_ring(polygon),
source_id2, box,
rescale_policy,
robust_policy,
turns, interrupt_policy,
multi_index, -1);
@@ -739,7 +758,7 @@ struct get_turns_polygon_cs
intersector_type::apply(
source_id1, *it,
source_id2, box,
rescale_policy,
robust_policy,
turns, interrupt_policy,
multi_index, i);
}
@@ -772,24 +791,24 @@ struct get_turn_info_type<Geometry1, Geometry2, AssignPolicy, Tag1, Tag2, linear
: overlay::get_turn_info_linear_areal<AssignPolicy>
{};
template <typename Geometry1, typename Geometry2,
template <typename Geometry1, typename Geometry2, typename SegmentRatio,
typename Tag1 = typename tag<Geometry1>::type, typename Tag2 = typename tag<Geometry2>::type,
typename TagBase1 = typename topological_tag_base<Geometry1>::type, typename TagBase2 = typename topological_tag_base<Geometry2>::type>
struct turn_operation_type
{
typedef overlay::turn_operation type;
typedef overlay::turn_operation<SegmentRatio> type;
};
template <typename Geometry1, typename Geometry2, typename Tag1, typename Tag2>
struct turn_operation_type<Geometry1, Geometry2, Tag1, Tag2, linear_tag, linear_tag>
template <typename Geometry1, typename Geometry2, typename SegmentRatio, typename Tag1, typename Tag2>
struct turn_operation_type<Geometry1, Geometry2, SegmentRatio, Tag1, Tag2, linear_tag, linear_tag>
{
typedef overlay::turn_operation_linear type;
typedef overlay::turn_operation_linear<SegmentRatio> type;
};
template <typename Geometry1, typename Geometry2, typename Tag1, typename Tag2>
struct turn_operation_type<Geometry1, Geometry2, Tag1, Tag2, linear_tag, areal_tag>
template <typename Geometry1, typename Geometry2, typename SegmentRatio, typename Tag1, typename Tag2>
struct turn_operation_type<Geometry1, Geometry2, SegmentRatio, Tag1, Tag2, linear_tag, areal_tag>
{
typedef overlay::turn_operation_linear type;
typedef overlay::turn_operation_linear<SegmentRatio> type;
};
}} // namespace detail::get_turns
@@ -870,11 +889,11 @@ template
>
struct get_turns_reversed
{
template <typename RescalePolicy, typename Turns, typename InterruptPolicy>
template <typename RobustPolicy, typename Turns, typename InterruptPolicy>
static inline void apply(
int source_id1, Geometry1 const& g1,
int source_id2, Geometry2 const& g2,
RescalePolicy const& rescale_policy,
RobustPolicy const& robust_policy,
Turns& turns,
InterruptPolicy& interrupt_policy)
{
@@ -884,7 +903,7 @@ struct get_turns_reversed
Geometry2, Geometry1,
Reverse2, Reverse1,
TurnPolicy
>::apply(source_id2, g2, source_id1, g1, rescale_policy,
>::apply(source_id2, g2, source_id1, g1, robust_policy,
turns, interrupt_policy);
}
};
@@ -913,26 +932,18 @@ template
typename AssignPolicy,
typename Geometry1,
typename Geometry2,
typename RescalePolicy,
typename RobustPolicy,
typename Turns,
typename InterruptPolicy
>
inline void get_turns(Geometry1 const& geometry1,
Geometry2 const& geometry2,
RescalePolicy const& rescale_policy,
RobustPolicy const& robust_policy,
Turns& turns,
InterruptPolicy& interrupt_policy)
{
concept::check_concepts_and_equal_dimensions<Geometry1 const, Geometry2 const>();
//typedef typename strategy_intersection
// <
// typename cs_tag<Geometry1>::type,
// Geometry1,
// Geometry2,
// typename boost::range_value<Turns>::type
// >::segment_intersection_strategy_type segment_intersection_strategy_type;
typedef detail::overlay::get_turn_info<AssignPolicy> TurnPolicy;
//typedef detail::get_turns::get_turn_info_type<Geometry1, Geometry2, AssignPolicy> TurnPolicy;
@@ -958,7 +969,7 @@ inline void get_turns(Geometry1 const& geometry1,
>::type::apply(
0, geometry1,
1, geometry2,
rescale_policy,
robust_policy,
turns, interrupt_policy);
}

View File

@@ -14,8 +14,17 @@
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
#include <boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
#include <boost/geometry/algorithms/detail/recalculate.hpp>
#include <boost/geometry/policies/robustness/robust_point_type.hpp>
#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
#include <boost/geometry/policies/robustness/robust_type.hpp>
#include <boost/geometry/algorithms/detail/zoom_to_robust.hpp>
#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES)
#include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
#endif
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/geometries/segment.hpp>
@@ -33,7 +42,7 @@ template
typename TurnPoints,
typename Indexed,
typename Geometry1, typename Geometry2,
typename RescalePolicy,
typename RobustPolicy,
bool Reverse1, bool Reverse2,
typename Strategy
>
@@ -42,12 +51,12 @@ struct sort_in_cluster
inline sort_in_cluster(TurnPoints const& turn_points
, Geometry1 const& geometry1
, Geometry2 const& geometry2
, RescalePolicy const& rescale_policy
, RobustPolicy const& robust_policy
, Strategy const& strategy)
: m_turn_points(turn_points)
, m_geometry1(geometry1)
, m_geometry2(geometry2)
, m_rescale_policy(rescale_policy)
, m_rescale_policy(robust_policy)
, m_strategy(strategy)
{}
@@ -56,15 +65,15 @@ private :
TurnPoints const& m_turn_points;
Geometry1 const& m_geometry1;
Geometry2 const& m_geometry2;
RescalePolicy const& m_rescale_policy;
RobustPolicy const& m_rescale_policy;
Strategy const& m_strategy;
typedef typename Indexed::type turn_operation_type;
typedef typename geometry::point_type<Geometry1>::type point_type;
typedef model::point
<
typename geometry::robust_type
<
typename detail::robust_type
<
typename select_coordinate_type<Geometry1, Geometry2>::type
>::type,
@@ -72,6 +81,8 @@ private :
typename geometry::coordinate_system<Geometry1>::type
> robust_point_type;
// Still called by #case_102_multi, #case_107_multi
// #case_recursive_boxes_3
inline void get_situation_map(Indexed const& left, Indexed const& right,
robust_point_type& pi_rob, robust_point_type& pj_rob,
robust_point_type& ri_rob, robust_point_type& rj_rob,
@@ -89,47 +100,67 @@ private :
geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
right.subject.other_id,
si, sj);
geometry::zoom_to_robust(pi, pj, ri, rj, si, sj,
pi_rob, pj_rob,
ri_rob, rj_rob,
si_rob, sj_rob);
geometry::recalculate(pi_rob, pi, m_rescale_policy);
geometry::recalculate(pj_rob, pj, m_rescale_policy);
geometry::recalculate(ri_rob, ri, m_rescale_policy);
geometry::recalculate(rj_rob, rj, m_rescale_policy);
geometry::recalculate(si_rob, si, m_rescale_policy);
geometry::recalculate(sj_rob, sj, m_rescale_policy);
}
#if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO
// This method was still called but did no effect whatsoever on the results,
// with or without robustness-rescaling.
// Probable cause: we rescale in this file ourselves, ignoring passed policy
// TODO: check this more.
// Besides this, it currently does not compile for yet unknown reasons
// (does not find specialization for segment_ratio_type)
// It is currently only called from the Unit Test "multi_intersection.cpp"
// Determine how p/r and p/s are located.
static inline void overlap_info(robust_point_type const& pi, robust_point_type const& pj,
inline void overlap_info(
robust_point_type const& pi, robust_point_type const& pj,
robust_point_type const& ri, robust_point_type const& rj,
robust_point_type const& si, robust_point_type const& sj,
bool& pr_overlap, bool& ps_overlap, bool& rs_overlap)
bool& pr_overlap, bool& ps_overlap, bool& rs_overlap) const
{
// Determine how p/r and p/s are located.
// One of them is coming from opposite direction.
typedef model::referring_segment<robust_point_type const> segment_type;
typedef segment_intersection_points
<
point_type,
typename segment_ratio_type
<
point_type, RobustPolicy
>::type
> intersection_return_type;
typedef strategy::intersection::relate_cartesian_segments
<
policies::relate::segments_intersection_points
<
segment_type,
segment_type,
segment_intersection_points<point_type>
intersection_return_type
>
> policy;
typedef model::referring_segment<robust_point_type const> segment_type;
segment_type p(pi, pj);
segment_type r(ri, rj);
segment_type s(si, sj);
// Get the intersection point (or two points)
segment_intersection_points<point_type> pr = policy::apply(p, r);
segment_intersection_points<point_type> ps = policy::apply(p, s);
segment_intersection_points<point_type> rs = policy::apply(r, s);
intersection_return_type pr = policy::apply(p, r, m_rescale_policy, pi, pj, ri, rj);
intersection_return_type ps = policy::apply(p, s, m_rescale_policy, pi, pj, si, sj);
intersection_return_type rs = policy::apply(r, s, m_rescale_policy, ri, rj, si, sj);
// Check on overlap
pr_overlap = pr.count == 2;
ps_overlap = ps.count == 2;
rs_overlap = rs.count == 2;
}
#endif
#ifdef BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES
@@ -141,11 +172,15 @@ private :
{
if (skip) return;
std::cout << "Case: " << header << " for " << left.index << " / " << right.index << std::endl;
robust_point_type pi, pj, ri, rj, si, sj;
get_situation_map(left, right, pi, pj, ri, rj, si, sj);
#if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO
bool prc = false, psc = false, rsc = false;
overlap_info(pi, pj, ri, rj, si, sj, prc, psc, rsc);
#endif
int const side_ri_p = m_strategy.apply(pi, pj, ri);
int const side_rj_p = m_strategy.apply(pi, pj, rj);
@@ -154,7 +189,6 @@ private :
int const side_si_r = m_strategy.apply(ri, rj, si);
int const side_sj_r = m_strategy.apply(ri, rj, sj);
std::cout << "Case: " << header << " for " << left.index << " / " << right.index << std::endl;
#ifdef BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES_MORE
std::cout << " Segment p:" << geometry::wkt(pi) << " .. " << geometry::wkt(pj) << std::endl;
std::cout << " Segment r:" << geometry::wkt(ri) << " .. " << geometry::wkt(rj) << std::endl;
@@ -172,7 +206,9 @@ private :
<< " ri//p: " << side_ri_p
<< " si//p: " << side_si_p
<< " si//r: " << side_si_r
#if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO
<< " cnts: " << int(prc) << "," << int(psc) << "," << int(rsc)
#endif
//<< " idx: " << left.index << "/" << right.index
;
@@ -365,9 +401,13 @@ private :
#endif
}
#if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO
// We need EXTRA information here: are p/r/s overlapping?
bool pr_ov = false, ps_ov = false, rs_ov = false;
overlap_info(pi, pj, ri, rj, si, sj, pr_ov, ps_ov, rs_ov);
#else
// std::cout << "Boost.Geometry: skipping overlap_info" << std::endl;
#endif
// One coming from right (#83,#90)
// One coming from left (#90, #94, #95)
@@ -375,12 +415,14 @@ private :
{
bool ret = false;
#if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO
if (pr_ov || ps_ov)
{
int r = side_ri_p != 0 ? side_ri_p : side_si_p;
ret = r * side_si_r == 1;
}
else
#endif
{
ret = side_si_r == 1;
}
@@ -397,6 +439,7 @@ private :
// Take the one NOT overlapping
bool ret = false;
bool found = false;
#if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO
if (pr_ov && ! ps_ov)
{
ret = true;
@@ -407,6 +450,7 @@ private :
ret = false;
found = true;
}
#endif
debug_consider(0, left, right, header, false, "aligned", ret);
if (found)
@@ -655,14 +699,14 @@ template
typename TurnPoints,
typename Geometry1,
typename Geometry2,
typename RescalePolicy,
typename RobustPolicy,
typename Strategy
>
inline void handle_cluster(Iterator begin_cluster, Iterator end_cluster,
TurnPoints& turn_points,
operation_type for_operation,
Geometry1 const& geometry1, Geometry2 const& geometry2,
RescalePolicy& rescale_policy,
RobustPolicy& robust_policy,
Strategy const& strategy)
{
// First inspect and (possibly) discard rows
@@ -677,15 +721,15 @@ inline void handle_cluster(Iterator begin_cluster, Iterator end_cluster,
TurnPoints,
IndexType,
Geometry1, Geometry2,
RescalePolicy,
RobustPolicy,
Reverse1, Reverse2,
Strategy
>(turn_points, geometry1, geometry2, rescale_policy, strategy));
>(turn_points, geometry1, geometry2, robust_policy, strategy));
#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES)
typedef typename IndexType::type operations_type;
operations_type const& op = turn_points[begin_cluster->index].operations[begin_cluster->operation_index];
std::cout << std::endl << "Clustered points on equal distance " << op.enriched.distance << std::endl;
std::cout << std::endl << "Clustered points on equal distance " << op.fraction << std::endl;
std::cout << "->Indexes ";
for (Iterator it = begin_cluster; it != end_cluster; ++it)

View File

@@ -33,7 +33,10 @@
#include <boost/geometry/algorithms/detail/overlay/overlay.hpp>
#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
#include <boost/geometry/algorithms/detail/overlay/follow.hpp>
#include <boost/geometry/algorithms/detail/rescale.hpp>
#include <boost/geometry/policies/robustness/robust_point_type.hpp>
#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
#include <boost/geometry/policies/robustness/get_rescale_policy.hpp>
#include <boost/geometry/views/segment_view.hpp>
@@ -58,25 +61,58 @@ struct intersection_segment_segment_point
template
<
typename Segment1, typename Segment2,
typename RobustPolicy,
typename OutputIterator, typename Strategy
>
static inline OutputIterator apply(Segment1 const& segment1,
Segment2 const& segment2, OutputIterator out,
Segment2 const& segment2,
RobustPolicy const& robust_policy,
OutputIterator out,
Strategy const& )
{
typedef typename point_type<PointOut>::type point_type;
typedef typename geometry::robust_point_type
<
typename geometry::point_type<Segment1>::type,
RobustPolicy
>::type robust_point_type;
// TODO: rescale segment -> robust points
robust_point_type pi_rob, pj_rob, qi_rob, qj_rob;
{
// Workaround:
point_type pi, pj, qi, qj;
assign_point_from_index<0>(segment1, pi);
assign_point_from_index<1>(segment1, pj);
assign_point_from_index<0>(segment2, qi);
assign_point_from_index<1>(segment2, qj);
geometry::recalculate(pi_rob, pi, robust_policy);
geometry::recalculate(pj_rob, pj, robust_policy);
geometry::recalculate(qi_rob, qi, robust_policy);
geometry::recalculate(qj_rob, qj, robust_policy);
}
// Get the intersection point (or two points)
segment_intersection_points<point_type> is
= strategy::intersection::relate_cartesian_segments
typedef segment_intersection_points
<
point_type,
typename segment_ratio_type
<
point_type, RobustPolicy
>::type
> intersection_return_type;
typedef strategy::intersection::relate_cartesian_segments
<
policies::relate::segments_intersection_points
<
Segment1,
Segment2,
segment_intersection_points<point_type>
intersection_return_type
>
>::apply(segment1, segment2);
> policy;
intersection_return_type is = policy::apply(segment1, segment2,
robust_policy, pi_rob, pj_rob, qi_rob, qj_rob);
for (std::size_t i = 0; i < is.count; i++)
{
@@ -94,18 +130,25 @@ struct intersection_linestring_linestring_point
template
<
typename Linestring1, typename Linestring2,
typename RobustPolicy,
typename OutputIterator, typename Strategy
>
static inline OutputIterator apply(Linestring1 const& linestring1,
Linestring2 const& linestring2, OutputIterator out,
Linestring2 const& linestring2,
RobustPolicy const& robust_policy,
OutputIterator out,
Strategy const& )
{
typedef typename point_type<PointOut>::type point_type;
typedef detail::overlay::turn_info<point_type> turn_info;
typedef detail::overlay::turn_info
<
point_type,
typename segment_ratio_type<point_type, RobustPolicy>::type
> turn_info;
std::deque<turn_info> turns;
geometry::get_intersection_points(linestring1, linestring2, turns);
geometry::get_intersection_points(linestring1, linestring2, robust_policy, turns);
for (typename boost::range_iterator<std::deque<turn_info> const>::type
it = boost::begin(turns); it != boost::end(turns); ++it)
@@ -149,9 +192,11 @@ struct intersection_of_linestring_with_areal
template
<
typename LineString, typename Areal,
typename RobustPolicy,
typename OutputIterator, typename Strategy
>
static inline OutputIterator apply(LineString const& linestring, Areal const& areal,
RobustPolicy const& robust_policy,
OutputIterator out,
Strategy const& )
{
@@ -169,8 +214,11 @@ struct intersection_of_linestring_with_areal
> follower;
typedef typename point_type<LineStringOut>::type point_type;
typedef detail::overlay::traversal_turn_info<point_type> turn_info;
typedef detail::overlay::traversal_turn_info
<
point_type,
typename geometry::segment_ratio_type<point_type, RobustPolicy>::type
> turn_info;
std::deque<turn_info> turns;
detail::get_turns::no_interrupt_policy policy;
@@ -178,8 +226,8 @@ struct intersection_of_linestring_with_areal
<
false,
(OverlayType == overlay_intersection ? ReverseAreal : !ReverseAreal),
detail::overlay::calculate_distance_policy
>(linestring, areal, detail::no_rescale_policy(), turns, policy);
detail::overlay::assign_null_policy
>(linestring, areal, robust_policy, turns, policy);
if (turns.empty())
{
@@ -195,8 +243,7 @@ struct intersection_of_linestring_with_areal
return out;
}
if (follower::included(border_point, areal))
if (follower::included(border_point, areal, robust_policy))
{
LineStringOut copy;
geometry::convert(linestring, copy);
@@ -217,7 +264,7 @@ struct intersection_of_linestring_with_areal
(
linestring, areal,
geometry::detail::overlay::operation_intersection,
turns, out
turns, robust_policy, out
);
}
};
@@ -359,9 +406,11 @@ struct intersection_insert
false, true, false
>
{
template <typename OutputIterator, typename Strategy>
template <typename RobustPolicy, typename OutputIterator, typename Strategy>
static inline OutputIterator apply(Linestring const& linestring,
Box const& box, OutputIterator out, Strategy const& )
Box const& box,
RobustPolicy const& ,
OutputIterator out, Strategy const& )
{
typedef typename point_type<GeometryOut>::type point_type;
strategy::intersection::liang_barsky<Box, point_type> lb_strategy;
@@ -435,9 +484,11 @@ struct intersection_insert
false, true, false
>
{
template <typename OutputIterator, typename Strategy>
template <typename RobustPolicy, typename OutputIterator, typename Strategy>
static inline OutputIterator apply(Segment const& segment,
Box const& box, OutputIterator out, Strategy const& )
Box const& box,
RobustPolicy const& ,// TODO: propagate to clip_range_with_box
OutputIterator out, Strategy const& )
{
geometry::segment_view<Segment> range(segment);
@@ -467,19 +518,25 @@ struct intersection_insert
Areal1, Areal2, false
>
{
template <typename OutputIterator, typename Strategy>
template <typename RobustPolicy, typename OutputIterator, typename Strategy>
static inline OutputIterator apply(Geometry1 const& geometry1,
Geometry2 const& geometry2, OutputIterator out, Strategy const& )
Geometry2 const& geometry2,
RobustPolicy const& robust_policy,
OutputIterator out, Strategy const& )
{
typedef detail::overlay::turn_info<PointOut> turn_info;
typedef detail::overlay::turn_info
<
PointOut,
typename segment_ratio_type<PointOut, RobustPolicy>::type
> turn_info;
std::vector<turn_info> turns;
detail::get_turns::no_interrupt_policy policy;
geometry::get_turns
<
false, false, detail::overlay::assign_null_policy
>(geometry1, geometry2, detail::no_rescale_policy(), turns, policy);
>(geometry1, geometry2, robust_policy, turns, policy);
for (typename std::vector<turn_info>::const_iterator it
= turns.begin(); it != turns.end(); ++it)
{
@@ -499,9 +556,11 @@ template
>
struct intersection_insert_reversed
{
template <typename OutputIterator, typename Strategy>
template <typename RobustPolicy, typename OutputIterator, typename Strategy>
static inline OutputIterator apply(Geometry1 const& g1,
Geometry2 const& g2, OutputIterator out,
Geometry2 const& g2,
RobustPolicy const& robust_policy,
OutputIterator out,
Strategy const& strategy)
{
return intersection_insert
@@ -509,7 +568,7 @@ struct intersection_insert_reversed
Geometry2, Geometry1, GeometryOut,
OverlayType,
Reverse2, Reverse1, ReverseOut
>::apply(g2, g1, out, strategy);
>::apply(g2, g1, robust_policy, out, strategy);
}
};
@@ -656,35 +715,37 @@ template
bool ReverseSecond,
overlay_type OverlayType,
typename Geometry1, typename Geometry2,
typename RobustPolicy,
typename OutputIterator,
typename Strategy
>
inline OutputIterator insert(Geometry1 const& geometry1,
Geometry2 const& geometry2,
RobustPolicy robust_policy,
OutputIterator out,
Strategy const& strategy)
{
return boost::mpl::if_c
<
geometry::reverse_dispatch<Geometry1, Geometry2>::type::value,
geometry::dispatch::intersection_insert_reversed
<
geometry::reverse_dispatch<Geometry1, Geometry2>::type::value,
geometry::dispatch::intersection_insert_reversed
<
Geometry1, Geometry2,
GeometryOut,
OverlayType,
overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
overlay::do_reverse<geometry::point_order<Geometry2>::value, ReverseSecond>::value,
overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value
>,
geometry::dispatch::intersection_insert
<
Geometry1, Geometry2,
GeometryOut,
OverlayType,
geometry::detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
geometry::detail::overlay::do_reverse<geometry::point_order<Geometry2>::value, ReverseSecond>::value
>
>::type::apply(geometry1, geometry2, out, strategy);
Geometry1, Geometry2,
GeometryOut,
OverlayType,
overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
overlay::do_reverse<geometry::point_order<Geometry2>::value, ReverseSecond>::value,
overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value
>,
geometry::dispatch::intersection_insert
<
Geometry1, Geometry2,
GeometryOut,
OverlayType,
geometry::detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
geometry::detail::overlay::do_reverse<geometry::point_order<Geometry2>::value, ReverseSecond>::value
>
>::type::apply(geometry1, geometry2, robust_policy, out, strategy);
}
@@ -723,10 +784,14 @@ inline OutputIterator intersection_insert(Geometry1 const& geometry1,
concept::check<Geometry1 const>();
concept::check<Geometry2 const>();
typedef typename Strategy::rescale_policy_type rescale_policy_type;
rescale_policy_type robust_policy
= geometry::get_rescale_policy<rescale_policy_type>(geometry1, geometry2);
return detail::intersection::insert
<
GeometryOut, false, overlay_intersection
>(geometry1, geometry2, out, strategy);
>(geometry1, geometry2, robust_policy, out, strategy);
}
@@ -760,12 +825,18 @@ inline OutputIterator intersection_insert(Geometry1 const& geometry1,
concept::check<Geometry1 const>();
concept::check<Geometry2 const>();
typedef typename geometry::rescale_policy_type
<
typename geometry::point_type<Geometry1>::type // TODO from both
>::type rescale_policy_type;
typedef strategy_intersection
<
typename cs_tag<GeometryOut>::type,
Geometry1,
Geometry2,
typename geometry::point_type<GeometryOut>::type
typename geometry::point_type<GeometryOut>::type,
rescale_policy_type
> strategy;
return intersection_insert<GeometryOut>(geometry1, geometry2, out,

View File

@@ -144,10 +144,10 @@ protected:
typename IntersectionInfo,
typename DirInfo
>
static inline void apply(Info& info, Point1 const& p1, Point2 const& p2,
IntersectionInfo const& ii, DirInfo const& di)
static inline void apply(Info& , Point1 const& , Point2 const& ,
IntersectionInfo const& , DirInfo const& )
{
calculate_distance_policy::apply(info, p1, p2, ii, di);
//calculate_distance_policy::apply(info, p1, p2, ii, di);
}
};
@@ -224,10 +224,11 @@ protected:
public:
template
<
typename OutputIterator, typename Strategy
typename RobustPolicy, typename OutputIterator, typename Strategy
>
static inline OutputIterator apply(Linear1 const& linear1,
Linear2 const& linear2,
RobustPolicy const&,
OutputIterator oit,
Strategy const& )
{
@@ -244,9 +245,6 @@ public:
if ( turns.empty() )
{
// the two linear geometries are disjoint
#ifdef GEOMETRY_TEST_DEBUG
std::cout << "NO INTERSECTIONS" << std::endl;
#endif
return linear_linear_no_intersections
<
LinestringOut,
@@ -284,10 +282,11 @@ struct linear_linear_linestring
{
template
<
typename OutputIterator, typename Strategy
typename RobustPolicy, typename OutputIterator, typename Strategy
>
static inline OutputIterator apply(Linear1 const& linear1,
Linear2 const& linear2,
RobustPolicy const& robust_policy,
OutputIterator oit,
Strategy const& strategy)
{
@@ -304,7 +303,7 @@ struct linear_linear_linestring
Linear2, Linear1, LinestringOut, overlay_difference,
EnableFilterContinueTurns, EnableRemoveDuplicateTurns,
EnableDegenerateTurns
>::apply(linear2, linear1, oit, strategy);
>::apply(linear2, linear1, robust_policy, oit, strategy);
}
};

View File

@@ -18,7 +18,6 @@
#include <boost/mpl/assert.hpp>
#include <boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp>
#include <boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp>
#include <boost/geometry/algorithms/detail/overlay/enrichment_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
@@ -27,7 +26,7 @@
#include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
#include <boost/geometry/algorithms/detail/rescale.hpp>
#include <boost/geometry/algorithms/detail/recalculate.hpp>
#include <boost/geometry/algorithms/num_points.hpp>
#include <boost/geometry/algorithms/reverse.hpp>
@@ -38,6 +37,9 @@
#include <boost/geometry/algorithms/detail/overlay/select_rings.hpp>
#include <boost/geometry/algorithms/detail/overlay/do_reverse.hpp>
#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
#ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE
# include <boost/geometry/io/dsv/write.hpp>
#endif
@@ -156,9 +158,10 @@ template
>
struct overlay
{
template <typename OutputIterator, typename Strategy>
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& )
{
@@ -177,8 +180,13 @@ struct overlay
>(geometry1, geometry2, out);
}
typedef typename geometry::coordinate_type<GeometryOut>::type coordinate_type;
typedef typename geometry::point_type<GeometryOut>::type point_type;
typedef detail::overlay::traversal_turn_info<point_type> turn_info;
typedef detail::overlay::traversal_turn_info
<
point_type,
typename geometry::segment_ratio_type<point_type, RobustPolicy>::type
> turn_info;
typedef std::deque<turn_info> container_type;
typedef std::deque
@@ -192,8 +200,6 @@ struct overlay
boost::timer timer;
#endif
detail::no_rescale_policy rescale_policy;
#ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE
std::cout << "get turns" << std::endl;
#endif
@@ -201,8 +207,8 @@ std::cout << "get turns" << std::endl;
geometry::get_turns
<
Reverse1, Reverse2,
detail::overlay::calculate_distance_policy
>(geometry1, geometry2, rescale_policy, turn_points, policy);
detail::overlay::assign_null_policy
>(geometry1, geometry2, robust_policy, turn_points, policy);
#ifdef BOOST_GEOMETRY_TIME_OVERLAY
std::cout << "get_turns: " << timer.elapsed() << std::endl;
@@ -217,7 +223,7 @@ std::cout << "enrich" << std::endl;
? geometry::detail::overlay::operation_union
: geometry::detail::overlay::operation_intersection,
geometry1, geometry2,
rescale_policy,
robust_policy,
side_strategy);
#ifdef BOOST_GEOMETRY_TIME_OVERLAY
@@ -238,7 +244,7 @@ std::cout << "traverse" << std::endl;
Direction == overlay_union
? geometry::detail::overlay::operation_union
: geometry::detail::overlay::operation_intersection,
rescale_policy,
robust_policy,
turn_points, rings
);

View File

@@ -142,9 +142,10 @@ template
>
struct point_point_point
{
template <typename OutputIterator, typename Strategy>
template <typename RobustPolicy, typename OutputIterator, typename Strategy>
static inline OutputIterator apply(Point1 const& point1,
Point2 const& point2,
RobustPolicy const& ,
OutputIterator oit,
Strategy const&)
{
@@ -175,9 +176,10 @@ template
>
struct multipoint_point_point
{
template <typename OutputIterator, typename Strategy>
template <typename RobustPolicy, typename OutputIterator, typename Strategy>
static inline OutputIterator apply(MultiPoint const& multipoint,
Point const& point,
RobustPolicy const& ,
OutputIterator oit,
Strategy const&)
{
@@ -209,9 +211,10 @@ template
>
struct point_multipoint_point
{
template <typename OutputIterator, typename Strategy>
template <typename RobustPolicy, typename OutputIterator, typename Strategy>
static inline OutputIterator apply(Point const& point,
MultiPoint const& multipoint,
RobustPolicy const& ,
OutputIterator oit,
Strategy const&)
{
@@ -244,9 +247,10 @@ template
>
struct multipoint_multipoint_point
{
template <typename OutputIterator, typename Strategy>
template <typename RobustPolicy, typename OutputIterator, typename Strategy>
static inline OutputIterator apply(MultiPoint1 const& multipoint1,
MultiPoint2 const& multipoint2,
RobustPolicy const& robust_policy,
OutputIterator oit,
Strategy const& strategy)
{
@@ -256,7 +260,7 @@ struct multipoint_multipoint_point
return multipoint_multipoint_point
<
MultiPoint2, MultiPoint1, PointOut, OverlayType
>::apply(multipoint2, multipoint1, oit, strategy);
>::apply(multipoint2, multipoint1, robust_policy, oit, strategy);
}
std::vector<typename point_type<MultiPoint2>::type>
@@ -399,9 +403,10 @@ template
>
struct union_pointlike_pointlike_point
{
template <typename OutputIterator, typename Strategy>
template <typename RobustPolicy, typename OutputIterator, typename Strategy>
static inline OutputIterator apply(PointLike1 const& pointlike1,
PointLike2 const& pointlike2,
RobustPolicy const& robust_policy,
OutputIterator oit,
Strategy const& strategy)
{
@@ -412,7 +417,7 @@ struct union_pointlike_pointlike_point
PointLike2, PointLike1, PointOut, overlay_difference,
typename tag<PointLike2>::type,
typename tag<PointLike1>::type
>::apply(pointlike2, pointlike1, oit, strategy);
>::apply(pointlike2, pointlike1, robust_policy, oit, strategy);
}
};

View File

@@ -55,18 +55,18 @@ template
typename Geometry,
typename Turns,
typename TurnPolicy,
typename RescalePolicy,
typename RobustPolicy,
typename InterruptPolicy
>
struct self_section_visitor
{
Geometry const& m_geometry;
RescalePolicy const& m_rescale_policy;
RobustPolicy const& m_rescale_policy;
Turns& m_turns;
InterruptPolicy& m_interrupt_policy;
inline self_section_visitor(Geometry const& g,
RescalePolicy const& rp,
RobustPolicy const& rp,
Turns& turns, InterruptPolicy& ip)
: m_geometry(g)
, m_rescale_policy(rp)
@@ -110,10 +110,10 @@ struct self_section_visitor
template<typename TurnPolicy>
struct get_turns
{
template <typename Geometry, typename RescalePolicy, typename Turns, typename InterruptPolicy>
template <typename Geometry, typename RobustPolicy, typename Turns, typename InterruptPolicy>
static inline bool apply(
Geometry const& geometry,
RescalePolicy const& rescale_policy,
RobustPolicy const& robust_policy,
Turns& turns,
InterruptPolicy& interrupt_policy)
{
@@ -127,13 +127,13 @@ struct get_turns
> sections_type;
sections_type sec;
geometry::sectionalize<false>(geometry, rescale_policy, false, sec);
geometry::sectionalize<false>(geometry, robust_policy, false, sec);
self_section_visitor
<
Geometry,
Turns, TurnPolicy, RescalePolicy, InterruptPolicy
> visitor(geometry, rescale_policy, turns, interrupt_policy);
Turns, TurnPolicy, RobustPolicy, InterruptPolicy
> visitor(geometry, robust_policy, turns, interrupt_policy);
try
{
@@ -198,10 +198,10 @@ struct self_get_turn_points
TurnPolicy
>
{
template <typename RescalePolicy, typename Turns, typename InterruptPolicy>
template <typename RobustPolicy, typename Turns, typename InterruptPolicy>
static inline bool apply(
Box const& ,
RescalePolicy const& ,
RobustPolicy const& ,
Turns& ,
InterruptPolicy& )
{
@@ -243,12 +243,12 @@ template
<
typename AssignPolicy,
typename Geometry,
typename RescalePolicy,
typename RobustPolicy,
typename Turns,
typename InterruptPolicy
>
inline void self_turns(Geometry const& geometry,
RescalePolicy const& rescale_policy,
RobustPolicy const& robust_policy,
Turns& turns, InterruptPolicy& interrupt_policy)
{
concept::check<Geometry const>();
@@ -260,7 +260,7 @@ inline void self_turns(Geometry const& geometry,
typename tag<Geometry>::type,
Geometry,
TurnPolicy
>::apply(geometry, rescale_policy, turns, interrupt_policy);
>::apply(geometry, robust_policy, turns, interrupt_policy);
}

View File

@@ -35,7 +35,6 @@ namespace detail { namespace overlay
template <typename P>
std::ostream& operator<<(std::ostream &os, turn_info<P> const& info)
{
typename geometry::coordinate_type<P>::type d = info.distance;
os << "\t"
<< " src " << info.seg_id.source_index
<< " seg " << info.seg_id.segment_index
@@ -54,7 +53,7 @@ namespace detail { namespace overlay
<< " nxt seg " << info.travels_to_vertex_index
<< " , ip " << info.travels_to_ip_index
<< " , or " << info.next_ip_index
<< " dst " << double(d)
<< " frac " << info.fraction
<< info.visit_state;
if (info.flagged)
{

View File

@@ -24,15 +24,21 @@ namespace detail { namespace overlay
{
template <typename P>
struct traversal_turn_operation : public turn_operation
template <typename Point, typename SegmentRatio>
struct traversal_turn_operation : public turn_operation<SegmentRatio>
{
enrichment_info<P> enriched;
enrichment_info<Point> enriched;
visit_info visited;
};
template <typename P>
struct traversal_turn_info : public turn_info<P, traversal_turn_operation<P> >
template <typename Point, typename SegmentRatio>
struct traversal_turn_info
: public turn_info
<
Point,
SegmentRatio,
traversal_turn_operation<Point, SegmentRatio>
>
{};

View File

@@ -13,7 +13,6 @@
#include <boost/range.hpp>
#include <boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp>
#include <boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp>
#include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
@@ -94,14 +93,16 @@ template
typename G1,
typename G2,
typename Turns,
typename IntersectionInfo
typename IntersectionInfo,
typename RobustPolicy
>
inline bool assign_next_ip(G1 const& g1, G2 const& g2,
Turns& turns,
typename boost::range_iterator<Turns>::type& ip,
GeometryOut& current_output,
IntersectionInfo& info,
segment_identifier& seg_id)
segment_identifier& seg_id,
RobustPolicy const& robust_policy)
{
info.visited.set_visited();
set_visited_for_continue(*ip, info);
@@ -122,12 +123,14 @@ inline bool assign_next_ip(G1 const& g1, G2 const& g2,
{
geometry::copy_segments<Reverse1>(g1, info.seg_id,
info.enriched.travels_to_vertex_index,
robust_policy,
current_output);
}
else
{
geometry::copy_segments<Reverse2>(g2, info.seg_id,
info.enriched.travels_to_vertex_index,
robust_policy,
current_output);
}
seg_id = info.seg_id;
@@ -139,7 +142,8 @@ inline bool assign_next_ip(G1 const& g1, G2 const& g2,
seg_id = info.seg_id;
}
detail::overlay::append_no_dups_or_spikes(current_output, ip->point);
detail::overlay::append_no_dups_or_spikes(current_output, ip->point,
robust_policy);
return true;
}
@@ -230,11 +234,11 @@ template
class traverse
{
public :
template <typename RescalePolicy, typename Turns, typename Rings>
template <typename RobustPolicy, typename Turns, typename Rings>
static inline void apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
detail::overlay::operation_type operation,
RescalePolicy const& rescale_policy,
RobustPolicy const& robust_policy,
Turns& turns, Rings& rings)
{
typedef typename boost::range_value<Rings>::type ring_type;
@@ -279,7 +283,8 @@ public :
set_visited_for_continue(*it, *iit);
ring_type current_output;
geometry::append(current_output, it->point);
detail::overlay::append_no_dups_or_spikes(current_output,
it->point, robust_policy);
turn_iterator current = it;
turn_operation_iterator_type current_iit = iit;
@@ -289,13 +294,14 @@ public :
geometry1, geometry2,
turns,
current, current_output,
*iit, current_seg_id))
*iit, current_seg_id,
robust_policy))
{
Backtrack::apply(
size_at_start,
rings, current_output, turns, *current_iit,
"No next IP",
geometry1, geometry2, rescale_policy, state);
geometry1, geometry2, robust_policy, state);
}
if (! detail::overlay::select_next_ip(
@@ -308,7 +314,7 @@ public :
size_at_start,
rings, current_output, turns, *iit,
"Dead end at start",
geometry1, geometry2, rescale_policy, state);
geometry1, geometry2, robust_policy, state);
}
else
{
@@ -330,7 +336,7 @@ public :
size_at_start,
rings, current_output, turns, *iit,
"Visit again",
geometry1, geometry2, rescale_policy, state);
geometry1, geometry2, robust_policy, state);
}
else
{
@@ -349,7 +355,8 @@ public :
detail::overlay::assign_next_ip<Reverse1, Reverse2>(
geometry1, geometry2,
turns, current, current_output,
*current_iit, current_seg_id);
*current_iit, current_seg_id,
robust_policy);
if (! detail::overlay::select_next_ip(
operation,
@@ -364,7 +371,7 @@ public :
size_at_start,
rings, current_output, turns, *iit,
"Dead end",
geometry1, geometry2, rescale_policy, state);
geometry1, geometry2, robust_policy, state);
}
else
{
@@ -380,7 +387,7 @@ public :
size_at_start,
rings, current_output, turns, *iit,
"Endless loop",
geometry1, geometry2, rescale_policy, state);
geometry1, geometry2, robust_policy, state);
}
}
}
@@ -391,6 +398,7 @@ public :
detail::overlay::debug_traverse(*current, *iit, "->Finished");
if (geometry::num_points(current_output) >= min_num_points)
{
clean_closing_dups_and_spikes(current_output, robust_policy);
rings.push_back(current_output);
}
}

View File

@@ -54,11 +54,13 @@ enum method_type
The class is to be included in the turn_info class, either direct
or a derived or similar class with more (e.g. enrichment) information.
*/
template <typename SegmentRatio>
struct turn_operation
{
operation_type operation;
segment_identifier seg_id;
segment_identifier other_id;
SegmentRatio fraction;
inline turn_operation()
: operation(operation_none)
@@ -78,7 +80,8 @@ struct turn_operation
template
<
typename Point,
typename Operation = turn_operation,
typename SegmentRatio,
typename Operation = turn_operation<SegmentRatio>,
typename Container = boost::array<Operation, 2>
>
struct turn_info

View File

@@ -14,6 +14,8 @@
#include <boost/geometry/arithmetic/arithmetic.hpp>
#include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
#include <boost/geometry/algorithms/detail/recalculate.hpp>
#include <boost/geometry/policies/robustness/robust_point_type.hpp>
#include <boost/geometry/strategies/side.hpp>
#include <boost/geometry/util/math.hpp>
@@ -25,8 +27,18 @@ namespace boost { namespace geometry
namespace detail
{
// Checks if a point ("last_point") causes a spike w.r.t.
// the specified two other points (segment_a, segment_b)
//
// x-------x------x
// a lp b
//
// Above, lp generates a spike w.r.t. segment(a,b)
// So specify last point first, then (a,b) (this is unordered, so unintuitive)
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)
static inline bool point_is_spike_or_equal(Point1 const& last_point,
Point2 const& segment_a,
Point3 const& segment_b)
{
typedef typename strategy::side::services::default_strategy
<
@@ -62,6 +74,49 @@ static inline bool point_is_spike_or_equal(Point1 const& last_point, Point2 cons
return false;
}
template
<
typename Point1,
typename Point2,
typename Point3,
typename RobustPolicy
>
static inline bool point_is_spike_or_equal(Point1 const& last_point,
Point2 const& segment_a,
Point3 const& segment_b,
RobustPolicy const& robust_policy)
{
if (point_is_spike_or_equal(last_point, segment_a, segment_b))
{
return true;
}
if (! RobustPolicy::enabled)
{
return false;
}
// Try using specified robust policy
typedef typename geometry::robust_point_type
<
Point1,
RobustPolicy
>::type robust_point_type;
robust_point_type last_point_rob, segment_a_rob, segment_b_rob;
geometry::recalculate(last_point_rob, last_point, robust_policy);
geometry::recalculate(segment_a_rob, segment_a, robust_policy);
geometry::recalculate(segment_b_rob, segment_b, robust_policy);
return point_is_spike_or_equal
(
last_point_rob,
segment_a_rob,
segment_b_rob
);
}
} // namespace detail
#endif

View File

@@ -22,6 +22,7 @@
#include <boost/numeric/conversion/bounds.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/type_traits.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/geometry/arithmetic/arithmetic.hpp>
#include <boost/geometry/algorithms/append.hpp>
@@ -33,9 +34,6 @@
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/util/for_each_coordinate.hpp>
namespace boost { namespace geometry
{
@@ -72,7 +70,7 @@ struct recalculate_indexed
static inline void apply(Geometry1& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
{
// Do it for both indices in one dimension
std::size_t const dim = Dimension - 1;
static std::size_t const dim = Dimension - 1;
geometry::set<0, dim>(geometry1, strategy.template apply<dim>(geometry::get<0, dim>(geometry2)));
geometry::set<1, dim>(geometry1, strategy.template apply<dim>(geometry::get<1, dim>(geometry2)));
recalculate_indexed<dim>::apply(geometry1, geometry2, strategy);
@@ -89,7 +87,71 @@ struct recalculate_indexed<0>
}
};
struct range_to_range
{
template
<
typename Range1,
typename Range2,
typename Strategy
>
static inline void apply(Range1& destination, Range2 const& source,
Strategy const& strategy)
{
typedef typename geometry::point_type<Range2>::type point_type;
typedef recalculate_point<geometry::dimension<point_type>::value> per_point;
geometry::clear(destination);
for (typename boost::range_iterator<Range2 const>::type it
= boost::begin(source);
it != boost::end(source);
++it)
{
point_type p;
per_point::apply(p, *it, strategy);
geometry::append(destination, p);
}
}
};
struct polygon_to_polygon
{
template
<
typename Polygon1,
typename Polygon2,
typename Strategy
>
static inline void apply(Polygon1& destination, Polygon2 const& source,
Strategy const& strategy)
{
typedef range_to_range per_ring;
per_ring::apply(geometry::exterior_ring(destination),
geometry::exterior_ring(source), strategy);
traits::resize
<
typename boost::remove_reference
<
typename traits::interior_mutable_type<Polygon1>::type
>::type
>::apply(interior_rings(destination), num_interior_rings(source));
typename interior_return_type<Polygon1>::type rings_dest
= interior_rings(destination);
typename interior_return_type<Polygon2 const>::type rings_source
= interior_rings(source);
BOOST_AUTO_TPL(it_source, boost::begin(rings_source));
BOOST_AUTO_TPL(it_dest, boost::begin(rings_dest));
for ( ; it_source != boost::end(rings_source); ++it_source, ++it_dest)
{
per_ring::apply(*it_dest, *it_source, strategy);
}
}
};
}} // namespace detail::recalculate
#endif // DOXYGEN_NO_DETAIL
@@ -105,14 +167,8 @@ template
typename Tag1 = typename geometry::tag<Geometry1>::type,
typename Tag2 = typename geometry::tag<Geometry2>::type
>
struct recalculate
{
BOOST_MPL_ASSERT_MSG
(
false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
, (types<Geometry1>)
);
};
struct recalculate : not_implemented<Tag1, Tag2>
{};
template <typename Point1, typename Point2>
struct recalculate<Point1, Point2, point_tag, point_tag>
@@ -129,6 +185,10 @@ struct recalculate<Segment1, Segment2, segment_tag, segment_tag>
: detail::recalculate::recalculate_indexed<geometry::dimension<Segment1>::value>
{};
template <typename Polygon1, typename Polygon2>
struct recalculate<Polygon1, Polygon2, polygon_tag, polygon_tag>
: detail::recalculate::polygon_to_polygon
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH

View File

@@ -17,6 +17,8 @@
#include <boost/geometry/core/topological_dimension.hpp>
#include <boost/geometry/util/range.hpp>
#include <boost/geometry/algorithms/num_interior_rings.hpp>
#include <boost/geometry/algorithms/detail/point_on_border.hpp>
#include <boost/geometry/algorithms/detail/sub_range.hpp>
#include <boost/geometry/algorithms/detail/single_geometry.hpp>
@@ -193,7 +195,7 @@ struct areal_areal
// TODO: If Areal geometry may have infinite size, change the following line:
// The result should be FFFFFFFFF
set<exterior, exterior, result_dimension<Geometry2>::value>(result);// FFFFFFFFd, d in [1,9] or T
relate::set<exterior, exterior, result_dimension<Geometry2>::value>(result);// FFFFFFFFd, d in [1,9] or T
if ( result.interrupt )
return;
@@ -561,13 +563,6 @@ struct areal_areal
static const bool transpose_result = OpId != 0;
static const int other_id = (OpId + 1) % 2;
static const iterate_direction direction = order_as_direction<geometry::point_order<Geometry const>::value>::value;
static const closure_selector closure = geometry::closure<Geometry const>::value;
typedef typename ring_type<Geometry const>::type ring_type;
typedef typename reversible_view<ring_type const, direction>::type reversible_type;
typedef typename closeable_view<reversible_type const, closure>::type closeable_type;
public:
inline uncertain_rings_analyser(Result & result,
Geometry const& geom,

View File

@@ -12,6 +12,7 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_BOUNDARY_CHECKER_HPP
#include <boost/geometry/util/range.hpp>
#include <boost/geometry/algorithms/num_points.hpp>
#include <boost/geometry/algorithms/detail/sub_range.hpp>
#include <boost/geometry/algorithms/detail/disjoint/point_point.hpp>
@@ -54,34 +55,6 @@ public:
return has_boundary;
}
template <boundary_query BoundaryQuery>
bool is_boundary(point_type const& pt, segment_identifier const& sid) const
{
if ( !has_boundary )
return false;
if ( BoundaryQuery == boundary_front )
{
return sid.segment_index == 0
&& detail::equals::equals_point_point(pt, range::front(geometry));
}
else if ( BoundaryQuery == boundary_back )
{
return sid.segment_index + 2 == geometry::num_points(geometry)
&& detail::equals::equals_point_point(pt, range::back(geometry));
}
else if ( BoundaryQuery == boundary_any )
{
return ( sid.segment_index == 0
&& detail::equals::equals_point_point(pt, range::front(geometry)) )
|| ( sid.segment_index + 2 == geometry::num_points(geometry)
&& detail::equals::equals_point_point(pt, range::back(geometry)) );
}
BOOST_ASSERT(false);
return false;
}
private:
bool has_boundary;
Geometry const& geometry;
@@ -97,41 +70,10 @@ public:
: is_filled(false), geometry(g)
{}
template <boundary_query BoundaryQuery>
bool is_endpoint_boundary(point_type const& pt) const
{
return is_boundary_point(pt);
}
template <boundary_query BoundaryQuery>
bool is_boundary(point_type const& pt, segment_identifier const& sid) const
{
if ( BoundaryQuery == boundary_front )
{
if ( sid.segment_index != 0 )
return false;
}
if ( BoundaryQuery == boundary_back )
{
if ( sid.segment_index + 2 != geometry::num_points(sub_range(geometry, sid)) )
return false;
}
if ( BoundaryQuery == boundary_any )
{
if ( sid.segment_index != 0
&& sid.segment_index + 2 != geometry::num_points(sub_range(geometry, sid)) )
return false;
}
return is_boundary_point(pt);
}
private:
// First call O(NlogN)
// Each next call O(logN)
bool is_boundary_point(point_type const& pt) const
template <boundary_query BoundaryQuery>
bool is_endpoint_boundary(point_type const& pt) const
{
typedef typename boost::range_size<Geometry>::type size_type;
size_type multi_count = boost::size(geometry);
@@ -176,6 +118,7 @@ private:
return equal_points_count % 2 != 0;// && equal_points_count > 0; // the number is odd and > 0
}
private:
mutable bool is_filled;
// TODO: store references/pointers instead of points?
mutable std::vector<point_type> boundary_points;

View File

@@ -23,9 +23,8 @@ namespace boost { namespace geometry
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace relate {
// TODO:
// For 1-point linestrings or with all equal points turns won't be generated!
// Check for those degenerated cases may be connected with this one!
// NOTE: This iterates through single geometries for which turns were not generated.
// It doesn't mean that the geometry is disjoint, only that no turns were detected.
template <std::size_t OpId,
typename Geometry,
@@ -130,14 +129,12 @@ struct for_each_disjoint_geometry_if<OpId, Geometry, Tag, true>
// WARNING! This class stores pointers!
// Passing a reference to local variable will result in undefined behavior!
// TODO: rename to point_id_ref?
template <typename Point>
class point_identifier
class point_info
{
public:
point_identifier() : sid_ptr(0), pt_ptr(0) {}
point_identifier(segment_identifier const& sid, Point const& pt)
point_info() : sid_ptr(NULL), pt_ptr(NULL) {}
point_info(Point const& pt, segment_identifier const& sid)
: sid_ptr(boost::addressof(sid))
, pt_ptr(boost::addressof(pt))
{}
@@ -165,10 +162,10 @@ private:
// WARNING! This class stores pointers!
// Passing a reference to local variable will result in undefined behavior!
class same_single_geometry
class same_single
{
public:
same_single_geometry(segment_identifier const& sid)
same_single(segment_identifier const& sid)
: sid_ptr(boost::addressof(sid))
{}
@@ -178,7 +175,7 @@ public:
}
template <typename Point>
bool operator()(point_identifier<Point> const& pid) const
bool operator()(point_info<Point> const& pid) const
{
return operator()(pid.seg_id());
}
@@ -206,12 +203,12 @@ private:
// WARNING! This class stores pointers!
// Passing a reference to local variable will result in undefined behavior!
template <typename SameRange = same_single_geometry>
template <typename SameRange = same_single>
class segment_watcher
{
public:
segment_watcher()
: m_seg_id_ptr(0)
: m_seg_id_ptr(NULL)
{}
bool update(segment_identifier const& seg_id)
@@ -234,21 +231,24 @@ class exit_watcher
static const std::size_t other_op_id = (OpId + 1) % 2;
typedef typename TurnInfo::point_type point_type;
typedef point_identifier<point_type> point_info;
typedef detail::relate::point_info<point_type> point_info;
public:
exit_watcher()
: exit_operation(overlay::operation_none)
, exit_turn(0)
: m_exit_operation(overlay::operation_none)
, m_exit_turn_ptr(NULL)
{}
void enter(TurnInfo const& turn)
{
other_entry_points.push_back(
point_info(turn.operations[other_op_id].seg_id, turn.point) );
m_other_entry_points.push_back(
point_info(turn.point, turn.operations[other_op_id].seg_id) );
}
void exit(TurnInfo const& turn)
// TODO: exit_per_geometry parameter looks not very safe
// wrong value may be easily passed
void exit(TurnInfo const& turn, bool exit_per_geometry = true)
{
//segment_identifier const& seg_id = turn.operations[op_id].seg_id;
segment_identifier const& other_id = turn.operations[other_op_id].seg_id;
@@ -256,63 +256,76 @@ public:
typedef typename std::vector<point_info>::iterator point_iterator;
// search for the entry point in the same range of other geometry
point_iterator entry_it = std::find_if(other_entry_points.begin(),
other_entry_points.end(),
same_single_geometry(other_id));
point_iterator entry_it = std::find_if(m_other_entry_points.begin(),
m_other_entry_points.end(),
same_single(other_id));
// this end point has corresponding entry point
if ( entry_it != other_entry_points.end() )
if ( entry_it != m_other_entry_points.end() )
{
// here we know that we possibly left LS
// we must still check if we didn't get back on the same point
exit_operation = exit_op;
exit_turn = boost::addressof(turn);
// erase the corresponding entry point
other_entry_points.erase(entry_it);
m_other_entry_points.erase(entry_it);
if ( exit_per_geometry || m_other_entry_points.empty() )
{
// here we know that we possibly left LS
// we must still check if we didn't get back on the same point
m_exit_operation = exit_op;
m_exit_turn_ptr = boost::addressof(turn);
}
}
}
bool is_outside() const
{
// if we didn't entered anything in the past, we're outside
return other_entry_points.empty();
return m_other_entry_points.empty();
}
bool is_outside(TurnInfo const& turn) const
{
return m_other_entry_points.empty()
|| std::find_if(m_other_entry_points.begin(),
m_other_entry_points.end(),
same_single(
turn.operations[other_op_id].seg_id))
== m_other_entry_points.end();
}
overlay::operation_type get_exit_operation() const
{
return exit_operation;
return m_exit_operation;
}
point_type const& get_exit_point() const
{
BOOST_ASSERT(exit_operation != overlay::operation_none);
BOOST_ASSERT(exit_turn);
return exit_turn->point;
BOOST_ASSERT(m_exit_operation != overlay::operation_none);
BOOST_ASSERT(m_exit_turn_ptr);
return m_exit_turn_ptr->point;
}
TurnInfo const& get_exit_turn() const
{
BOOST_ASSERT(exit_operation != overlay::operation_none);
BOOST_ASSERT(exit_turn);
return *exit_turn;
BOOST_ASSERT(m_exit_operation != overlay::operation_none);
BOOST_ASSERT(m_exit_turn_ptr);
return *m_exit_turn_ptr;
}
void reset_detected_exit()
{
exit_operation = overlay::operation_none;
m_exit_operation = overlay::operation_none;
}
void reset()
{
exit_operation = overlay::operation_none;
other_entry_points.clear();
m_exit_operation = overlay::operation_none;
m_other_entry_points.clear();
}
private:
overlay::operation_type exit_operation;
const TurnInfo * exit_turn;
std::vector<point_info> other_entry_points; // TODO: use map here or sorted vector?
overlay::operation_type m_exit_operation;
const TurnInfo * m_exit_turn_ptr;
std::vector<point_info> m_other_entry_points; // TODO: use map here or sorted vector?
};
template <std::size_t OpId, typename Turn>
@@ -327,8 +340,10 @@ inline bool turn_on_the_same_ip(Turn const& prev_turn, Turn const& curr_turn)
return false;
}
// TODO: will this work if between segments there will be some number of degenerated ones?
if ( prev_seg_id.segment_index != curr_seg_id.segment_index
&& ( ! geometry::math::equals(curr_turn.operations[OpId].enriched.distance, 0)
&& ( ! curr_turn.operations[OpId].fraction.is_zero()
|| prev_seg_id.segment_index + 1 != curr_seg_id.segment_index ) )
{
return false;
@@ -361,97 +376,22 @@ static inline bool is_ip_on_boundary(IntersectionPoint const& ip,
// IP on the last point of the linestring
if ( (BoundaryQuery == boundary_back || BoundaryQuery == boundary_any)
&& operation_info.operation == overlay::operation_blocked )
&& operation_info.position == overlay::position_back )
{
BOOST_ASSERT(operation_info.position == overlay::position_back);
// check if this point is a boundary
res = boundary_checker.template is_endpoint_boundary<boundary_back>(ip);
#ifdef BOOST_GEOMETRY_DEBUG_RELATE
BOOST_ASSERT(res == boundary_checker.template is_boundary<boundary_back>(ip, seg_id));
#endif
}
// IP on the last point of the linestring
else if ( (BoundaryQuery == boundary_front || BoundaryQuery == boundary_any)
&& operation_info.position == overlay::position_front )
&& operation_info.position == overlay::position_front )
{
// check if this point is a boundary
res = boundary_checker.template is_endpoint_boundary<boundary_front>(ip);
#ifdef BOOST_GEOMETRY_DEBUG_RELATE
BOOST_ASSERT(res == boundary_checker.template is_boundary<boundary_front>(ip, seg_id));
#endif
}
// IP somewhere in the interior
else
{
#ifdef BOOST_GEOMETRY_DEBUG_RELATE
BOOST_ASSERT(res == boundary_checker.template is_boundary<boundary_any>(ip, seg_id));
#endif
}
return res;
}
// TODO: The tool like this would be useful but this can't be done with the current implementation of
// reversible and closeable views because the reference to local variable would be returned!
//template <typename Geometry>
//struct normalized_range_type
//{
// static const iterate_direction direction = order_as_direction<geometry::point_order<Geometry>::value>::value;
// static const closure_selector closure = geometry::closure<Geometry>::value;
//
// typedef typename ring_type<Geometry>::type ring_type;
// typedef typename reversible_view
// <
// typename boost::mpl::if_c
// <
// boost::is_const<Geometry>::value,
// ring_type const,
// ring_type
// >::type,
// direction
// >::type reversible_type;
// typedef typename closeable_view
// <
// typename boost::mpl::if_c
// <
// boost::is_const<Geometry>::value,
// reversible_type const,
// reversible_type
// >::type,
// closure
// >::type closeable_type;
//
// typedef closeable_type type;
//};
//
//template <typename Geometry>
//struct normalized_range
//{
// template <typename Range>
// static inline
// typename normalized_range_type<Geometry>::type
// apply(Range & rng)
// {
// typename normalized_range_type<Geometry>::reversible_type
// rev_view(rng);
// typename normalized_range_type<Geometry>::closeable_type
// view(rev_view);
//
//// ERROR! HERE THE REFERENCE TO LOCAL rev_view IS RETURNED!
// return view;
// }
//};
//
//template <typename Geometry, typename Id>
//inline
//typename normalized_range_type<Geometry>::type
//normalized_sub_range(Geometry & geometry, Id const& id)
//{
// return normalized_range<Geometry>::apply(detail::sub_range(geometry, id));
//}
}} // namespace detail::relate
#endif // DOXYGEN_NO_DETAIL

View File

@@ -17,6 +17,8 @@
#include <boost/geometry/core/topological_dimension.hpp>
#include <boost/geometry/util/range.hpp>
#include <boost/geometry/algorithms/num_interior_rings.hpp>
#include <boost/geometry/algorithms/detail/point_on_border.hpp>
#include <boost/geometry/algorithms/detail/sub_range.hpp>
#include <boost/geometry/algorithms/detail/single_geometry.hpp>
@@ -25,6 +27,8 @@
#include <boost/geometry/algorithms/detail/relate/boundary_checker.hpp>
#include <boost/geometry/algorithms/detail/relate/follow_helpers.hpp>
#include <boost/geometry/views/normalized_view.hpp>
namespace boost { namespace geometry
{
@@ -194,7 +198,7 @@ struct linear_areal
// TODO: If Areal geometry may have infinite size, change the following line:
// The result should be FFFFFFFFF
set<exterior, exterior, result_dimension<Geometry2>::value, TransposeResult>(result);// FFFFFFFFd, d in [1,9] or T
relate::set<exterior, exterior, result_dimension<Geometry2>::value, TransposeResult>(result);// FFFFFFFFd, d in [1,9] or T
if ( result.interrupt )
return;
@@ -232,20 +236,14 @@ struct linear_areal
// This is set here because in the case if empty Areal geometry were passed
// those shouldn't be set
set<exterior, interior, '2', TransposeResult>(result);// FFFFFF2Fd
relate::set<exterior, interior, '2', TransposeResult>(result);// FFFFFF2Fd
if ( result.interrupt )
return;
{
// for different multi or same ring id: x, u, i, c
// for same multi and different ring id: c, i, u, x
typedef turns::less
<
0, turns::less_greater_op_for_other_same_m_diff_r
<
turns::op_to_int<0,2,3,1,4,0>
>
> less;
typedef turns::less<0, turns::less_op_linear_areal> less;
std::sort(turns.begin(), turns.end(), less());
turns_analyser<turn_type> analyser;
@@ -261,7 +259,7 @@ struct linear_areal
// If 'c' (insersection_boundary) was not found we know that any Ls isn't equal to one of the Rings
if ( !interrupt_policy.is_boundary_found )
{
set<exterior, boundary, '1', TransposeResult>(result);
relate::set<exterior, boundary, '1', TransposeResult>(result);
}
// Don't calculate it if it's required
else if ( may_update<exterior, boundary, '1', TransposeResult>(result) )
@@ -292,7 +290,7 @@ struct linear_areal
if ( it->operations[1].seg_id.ring_index > -1 )
{
// we can be sure that the exterior overlaps the boundary
set<exterior, boundary, '1', TransposeResult>(result);
relate::set<exterior, boundary, '1', TransposeResult>(result);
break;
}
// if there was some previous ring
@@ -307,7 +305,7 @@ struct linear_areal
single_geometry(geometry2, *prev_seg_id_ptr)) )
{
// we can be sure that the exterior overlaps the boundary
set<exterior, boundary, '1', TransposeResult>(result);
relate::set<exterior, boundary, '1', TransposeResult>(result);
break;
}
}
@@ -320,7 +318,7 @@ struct linear_areal
&& prev_seg_id_ptr->ring_index + 1 < it->operations[1].seg_id.ring_index )
{
// we can be sure that the exterior overlaps the boundary
set<exterior, boundary, '1', TransposeResult>(result);
relate::set<exterior, boundary, '1', TransposeResult>(result);
break;
}
}
@@ -335,20 +333,14 @@ struct linear_areal
if ( !has_boundary_inters.result )
{
// we can be sure that the exterior overlaps the boundary
set<exterior, boundary, '1', TransposeResult>(result);
relate::set<exterior, boundary, '1', TransposeResult>(result);
break;
}
// else there is 1d overlap with the boundary so we must analyse the boundary
else
{
// u, c
typedef turns::less
<
1, turns::less_greater_op_for_other_same_m_diff_r
<
turns::op_to_int<0,1,0,0,2,0>
>
> less;
typedef turns::less<1, turns::less_op_areal_linear> less;
std::sort(it, next, less());
// analyse
@@ -364,7 +356,7 @@ struct linear_areal
if ( analyser.is_union_detected )
{
// we can be sure that the boundary of Areal overlaps the exterior of Linear
set<exterior, boundary, '1', TransposeResult>(result);
relate::set<exterior, boundary, '1', TransposeResult>(result);
break;
}
}
@@ -384,7 +376,7 @@ struct linear_areal
single_geometry(geometry2, *prev_seg_id_ptr)) )
{
// we can be sure that the exterior overlaps the boundary
set<exterior, boundary, '1', TransposeResult>(result);
relate::set<exterior, boundary, '1', TransposeResult>(result);
}
}
}
@@ -460,10 +452,11 @@ struct linear_areal
public:
turns_analyser()
: m_previous_turn_ptr(0)
: m_previous_turn_ptr(NULL)
, m_previous_operation(overlay::operation_none)
, m_boundary_counter(0)
, m_interior_detected(false)
, m_first_interior_other_id_ptr(NULL)
{}
template <typename Result,
@@ -490,7 +483,7 @@ struct linear_areal
}
segment_identifier const& seg_id = it->operations[op_id].seg_id;
//segment_identifier const& other_id = it->operations[other_op_id].seg_id;
segment_identifier const& other_id = it->operations[other_op_id].seg_id;
const bool first_in_range = m_seg_watcher.update(seg_id);
@@ -521,6 +514,13 @@ struct linear_areal
if ( op == overlay::operation_blocked )
return;
if ( ( op == overlay::operation_intersection
|| op == overlay::operation_continue )
&& turn_on_the_same_ip<op_id>(m_exit_watcher.get_exit_turn(), *it) )
{
fake_enter_detected = true;
}
m_exit_watcher.reset_detected_exit();
}
@@ -548,33 +548,20 @@ struct linear_areal
{
m_interior_detected = false;
}
else if ( op == overlay::operation_union )
{
// TODO: this probably is not a good way of handling the interiors/enters
// the solution similar to exit_watcher would be more robust
// all enters should be kept and handled.
// maybe integrate it with the exit_watcher -> enter_exit_watcher
if ( m_first_interior_other_id_ptr
&& m_first_interior_other_id_ptr->multi_index == other_id.multi_index )
{
m_interior_detected = false;
}
}
}
// if the new linestring started just now,
// but the previous one went out on the previous point,
// we must check if the boundary of the previous segment is outside
// NOTE: couldn't it be integrated with the handling of the union above?
// THIS IS REDUNDANT WITH THE HANDLING OF THE END OF THE RANGE
//if ( first_in_range
// && ! fake_enter_detected
// && m_previous_operation == overlay::operation_union )
//{
// BOOST_ASSERT(it != first);
// BOOST_ASSERT(m_previous_turn_ptr);
// segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id;
// bool prev_back_b = is_endpoint_on_boundary<boundary_back>(
// range::back(sub_geometry::get(geometry, prev_seg_id)),
// boundary_checker);
// // if there is a boundary on the last point
// if ( prev_back_b )
// {
// update<boundary, exterior, '0', TransposeResult>(res);
// }
//}
// i/u, c/u
if ( op == overlay::operation_intersection
|| op == overlay::operation_continue ) // operation_boundary/operation_boundary_intersection
@@ -592,9 +579,15 @@ struct linear_areal
// interiors overlaps
//update<interior, interior, '1', TransposeResult>(res);
// don't update now
// we might enter a boundary of some other ring on the same IP
m_interior_detected = true;
// TODO: think about the implementation of the more robust version
// this way only the first enter will be handled
if ( !m_interior_detected )
{
// don't update now
// we might enter a boundary of some other ring on the same IP
m_interior_detected = true;
m_first_interior_other_id_ptr = boost::addressof(other_id);
}
}
}
else // operation_boundary
@@ -675,7 +668,8 @@ struct linear_areal
// we're inside, possibly going out right now
if ( ! no_enters_detected )
{
if ( op_blocked )
if ( op_blocked
&& it->operations[op_id].position == overlay::position_back ) // ignore spikes!
{
// check if this is indeed the boundary point
// NOTE: is_ip_on_boundary<>() should be called here but the result will be the same
@@ -780,7 +774,8 @@ struct linear_areal
// here, the possible exit is the real one
// we know that we entered and now we exit
if ( /*m_exit_watcher.get_exit_operation() == overlay::operation_union // THIS CHECK IS REDUNDANT
||*/ m_previous_operation == overlay::operation_union )
||*/ m_previous_operation == overlay::operation_union
&& !m_interior_detected )
{
// for sure
update<interior, exterior, '1', TransposeResult>(res);
@@ -801,10 +796,12 @@ struct linear_areal
}
}
// we might enter some Areal and didn't go out,
else if ( m_previous_operation == overlay::operation_intersection )
else if ( m_previous_operation == overlay::operation_intersection
|| m_interior_detected )
{
// just in case
update<interior, interior, '1', TransposeResult>(res);
m_interior_detected = false;
BOOST_ASSERT(first != last);
BOOST_ASSERT(m_previous_turn_ptr);
@@ -822,14 +819,6 @@ struct linear_areal
}
}
// handle the interior overlap
if ( m_interior_detected )
{
// just in case
update<interior, interior, '1', TransposeResult>(res);
m_interior_detected = false;
}
BOOST_ASSERT_MSG(m_previous_operation != overlay::operation_continue,
"Unexpected operation! Probably the error in get_turns(L,A) or relate(L,A)");
@@ -848,28 +837,13 @@ struct linear_areal
if ( turn.operations[op_id].position == overlay::position_front )
return false;
static const bool reverse2 = detail::overlay::do_reverse<
geometry::point_order<Geometry2>::value
>::value;
typedef typename closeable_view
<
typename range_type<Geometry2>::type const,
closure<Geometry2>::value
>::type range2_cview;
typedef typename reversible_view
<
range2_cview const,
reverse2 ? iterate_reverse : iterate_forward
>::type range2_view;
typedef typename sub_range_return_type<Geometry1 const>::type range1_ref;
range1_ref range1 = sub_range(geometry1, turn.operations[op_id].seg_id);
range2_cview const cview(sub_range(geometry2, turn.operations[other_op_id].seg_id));
range2_view const range2(cview);
typename sub_range_return_type<Geometry1 const>::type
range1 = sub_range(geometry1, turn.operations[op_id].seg_id);
typedef detail::normalized_view<Geometry2 const> const range2_type;
typedef typename boost::range_iterator<range2_type>::type range2_iterator;
range2_type range2(sub_range(geometry2, turn.operations[other_op_id].seg_id));
std::size_t s1 = boost::size(range1);
std::size_t s2 = boost::size(range2);
BOOST_ASSERT(s1 > 1 && s2 > 2);
@@ -897,10 +871,9 @@ struct linear_areal
std::size_t q_seg_jk = (q_seg_ij + 1) % seg_count2;
// TODO: the following function should return immediately, however the worst case complexity is O(N)
// It would be good to replace it with some O(1) mechanism
typename boost::range_iterator<range2_view>::type
qk_it = find_next_non_duplicated(boost::begin(range2),
boost::begin(range2) + q_seg_jk,
boost::end(range2));
range2_iterator qk_it = find_next_non_duplicated(boost::begin(range2),
boost::begin(range2) + q_seg_jk,
boost::end(range2));
// Will this sequence of points be always correct?
overlay::side_calculator<point1_type, point2_type> side_calc(qi_conv, new_pj, pi, qi, qj, *qk_it);
@@ -962,11 +935,12 @@ struct linear_areal
private:
exit_watcher<TurnInfo, op_id> m_exit_watcher;
segment_watcher<same_single_geometry> m_seg_watcher;
segment_watcher<same_single> m_seg_watcher;
TurnInfo * m_previous_turn_ptr;
overlay::operation_type m_previous_operation;
unsigned m_boundary_counter;
bool m_interior_detected;
const segment_identifier * m_first_interior_other_id_ptr;
};
// call analyser.apply() for each turn in range

View File

@@ -17,6 +17,7 @@
#include <boost/geometry/util/range.hpp>
#include <boost/geometry/algorithms/detail/sub_range.hpp>
#include <boost/geometry/algorithms/detail/single_geometry.hpp>
#include <boost/geometry/algorithms/detail/relate/point_geometry.hpp>
#include <boost/geometry/algorithms/detail/relate/turns.hpp>
@@ -67,18 +68,28 @@ public:
return true;
}
update<interior, exterior, '1', TransposeResult>(m_result);
m_flags |= 1;
// check if there is a boundary
if ( m_flags < 2
&& ( m_boundary_checker.template
is_endpoint_boundary<boundary_front>(range::front(linestring))
|| m_boundary_checker.template
is_endpoint_boundary<boundary_back>(range::back(linestring)) ) )
// point-like linestring
if ( count == 2
&& equals::equals_point_point(range::front(linestring),
range::back(linestring)) )
{
update<boundary, exterior, '0', TransposeResult>(m_result);
m_flags |= 2;
update<interior, exterior, '0', TransposeResult>(m_result);
}
else
{
update<interior, exterior, '1', TransposeResult>(m_result);
m_flags |= 1;
// check if there is a boundary
if ( m_flags < 2
&& ( m_boundary_checker.template
is_endpoint_boundary<boundary_front>(range::front(linestring))
|| m_boundary_checker.template
is_endpoint_boundary<boundary_back>(range::back(linestring)) ) )
{
update<boundary, exterior, '0', TransposeResult>(m_result);
m_flags |= 2;
}
}
return m_flags != 3
@@ -91,126 +102,6 @@ private:
unsigned m_flags;
};
//enum linestring_kind { linestring_exterior, linestring_point, linestring_closed, linestring_open };
//
//template <typename Linestring>
//linestring_kind check_linestring_kind(Linestring const& ls)
//{
// std::size_t count = boost::size(ls);
// if ( count == 0 )
// return linestring_exterior;
// else if ( count == 1 )
// return linestring_point;
// else
// {
// bool equal_fb = equals::equals_point_point(range::front(ls), range::back(ls));
// if ( equal_fb )
// {
// typedef typename boost::range_iterator<Linestring const>::type iterator;
// iterator first = boost::begin(ls);
// ++first;
// iterator last = boost::end(ls);
// --last;
// for ( iterator it = first ; it != last ; ++it )
// {
// if ( !equals::equals_point_point(range::front(ls), *it) )
// return linestring_closed;
// }
//
// return linestring_point;
// }
// else
// return linestring_open;
// }
//}
// Called in a loop for:
// Ls/Ls - worst O(N) - 1x point_in_geometry(MLs)
// Ls/MLs - worst O(N) - 1x point_in_geometry(MLs)
// MLs/Ls - worst O(N^2) - Bx point_in_geometry(Ls)
// MLs/MLs - worst O(N^2) - Bx point_in_geometry(Ls)
// TODO: later use spatial index
//template <std::size_t OpId, typename Result, typename BoundaryChecker, typename OtherGeometry>
//class disjoint_linestring_pred_with_point_size_handling
//{
// static const bool transpose_result = OpId != 0;
//
//public:
// disjoint_linestring_pred_with_point_size_handling(Result & res,
// BoundaryChecker & boundary_checker,
// OtherGeometry const& other_geometry)
// : m_result_ptr(boost::addressof(res))
// , m_boundary_checker_ptr(boost::addressof(boundary_checker))
// , m_other_geometry(boost::addressof(other_geometry))
// , m_detected_mask_point(0)
// , m_detected_open_boundary(false)
// {}
//
// template <typename Linestring>
// bool operator()(Linestring const& linestring)
// {
// linestring_kind lk = check_linestring_kind(linestring);
//
// if ( lk == linestring_point ) // just an optimization
// {
// if ( m_detected_mask_point != 7 )
// {
// // check the relation
// int pig = within::point_in_geometry(range::front(linestring), *m_other_geometry);
//
// // point inside
// if ( pig > 0 )
// {
// update<interior, interior, '0', transpose_result>(*m_result_ptr);
// m_detected_mask_point |= 1;
// }
// // point on boundary
// else if ( pig == 0 )
// {
// update<interior, boundary, '0', transpose_result>(*m_result_ptr);
// m_detected_mask_point |= 2;
// }
// // point outside
// else
// {
// update<interior, exterior, '0', transpose_result>(*m_result_ptr);
// m_detected_mask_point |= 4;
// }
// }
// }
// // NOTE: For closed Linestrings I/I=1 could be set automatically
// // but for MultiLinestrings endpoints of closed Linestrings must also be checked for boundary
// else if ( lk == linestring_open || lk == linestring_closed )
// {
// if ( !m_detected_open_boundary ) // just an optimization
// {
// update<interior, exterior, '1', transpose_result>(*m_result_ptr);
//
// // check if there is a boundary
// if ( m_boundary_checker_ptr->template
// is_endpoint_boundary<boundary_front>(range::front(linestring))
// || m_boundary_checker_ptr->template
// is_endpoint_boundary<boundary_back>(range::back(linestring)) )
// {
// update<boundary, exterior, '0', transpose_result>(*m_result_ptr);
//
// m_detected_open_boundary = true;
// }
// }
// }
//
// bool all_detected = m_detected_mask_point == 7 && m_detected_open_boundary;
// return !all_detected && !m_result_ptr->interrupt;
// }
//
//private:
// Result * m_result_ptr;
// BoundaryChecker * m_boundary_checker_ptr;
// const OtherGeometry * m_other_geometry;
// char m_detected_mask_point;
// bool m_detected_open_boundary;
//};
template <typename Geometry1, typename Geometry2>
struct linear_linear
{
@@ -223,7 +114,7 @@ struct linear_linear
static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Result & result)
{
// The result should be FFFFFFFFF
set<exterior, exterior, result_dimension<Geometry1>::value>(result);// FFFFFFFFd, d in [1,9] or T
relate::set<exterior, exterior, result_dimension<Geometry1>::value>(result);// FFFFFFFFd, d in [1,9] or T
if ( result.interrupt )
return;
@@ -234,7 +125,12 @@ struct linear_linear
interrupt_policy_linear_linear<Result> interrupt_policy(result);
turns::get_turns<Geometry1, Geometry2>::apply(turns, geometry1, geometry2, interrupt_policy);
turns::get_turns
<
Geometry1,
Geometry2,
detail::get_turns::get_turn_info_type<Geometry1, Geometry2, turns::assign_policy<true> >
>::apply(turns, geometry1, geometry2, interrupt_policy);
if ( result.interrupt )
return;
@@ -264,14 +160,7 @@ struct linear_linear
|| may_update<boundary, boundary, '0'>(result)
|| may_update<boundary, exterior, '0'>(result) )
{
// x, u, i, c
typedef turns::less
<
0, turns::less_greater_op_for_other_same_m_diff_r
<
turns::op_to_int<0,2,3,1,4,0>
>
> less;
typedef turns::less<0, turns::less_op_linear_linear> less;
std::sort(turns.begin(), turns.end(), less());
turns_analyser<turn_type, 0> analyser;
@@ -291,14 +180,7 @@ struct linear_linear
|| may_update<boundary, boundary, '0', true>(result)
|| may_update<boundary, exterior, '0', true>(result) )
{
// x, u, i, c
typedef turns::less
<
1, turns::less_greater_op_for_other_same_m_diff_r
<
turns::op_to_int<0,2,3,1,4,0>
>
> less;
typedef turns::less<1, turns::less_op_linear_linear> less;
std::sort(turns.begin(), turns.end(), less());
turns_analyser<turn_type, 1> analyser;
@@ -364,8 +246,9 @@ struct linear_linear
public:
turns_analyser()
: m_previous_turn_ptr(0)
: m_previous_turn_ptr(NULL)
, m_previous_operation(overlay::operation_none)
, m_degenerated_turn_ptr(NULL)
{}
template <typename Result,
@@ -377,7 +260,7 @@ struct linear_linear
void apply(Result & res,
TurnIt first, TurnIt it, TurnIt last,
Geometry const& geometry,
OtherGeometry const& /*other_geometry*/,
OtherGeometry const& other_geometry,
BoundaryChecker const& boundary_checker,
OtherBoundaryChecker const& other_boundary_checker)
{
@@ -385,18 +268,47 @@ struct linear_linear
overlay::operation_type op = it->operations[op_id].operation;
if ( op != overlay::operation_union
&& op != overlay::operation_intersection
&& op != overlay::operation_blocked )
{
return;
}
segment_identifier const& seg_id = it->operations[op_id].seg_id;
segment_identifier const& other_id = it->operations[other_op_id].seg_id;
const bool first_in_range = m_seg_watcher.update(seg_id);
if ( op != overlay::operation_union
&& op != overlay::operation_intersection
&& op != overlay::operation_blocked )
{
// degenerated turn
if ( op == overlay::operation_continue
&& it->method == overlay::method_none
&& m_exit_watcher.is_outside(*it)
/*&& ( m_exit_watcher.get_exit_operation() == overlay::operation_none
|| ! turn_on_the_same_ip<op_id>(m_exit_watcher.get_exit_turn(), *it) )*/ )
{
// TODO: rewrite the above condition
// WARNING! For spikes the above condition may be TRUE
// When degenerated turns are be marked in a different way than c,c/c
// different condition will be checked
handle_degenerated(res, *it,
geometry, other_geometry,
boundary_checker, other_boundary_checker,
first_in_range);
// TODO: not elegant solution! should be rewritten.
if ( it->operations[op_id].position == overlay::position_back )
{
m_previous_operation = overlay::operation_blocked;
m_exit_watcher.reset_detected_exit();
}
}
return;
}
// reset
m_degenerated_turn_ptr = NULL;
// handle possible exit
bool fake_enter_detected = false;
if ( m_exit_watcher.get_exit_operation() == overlay::operation_union )
@@ -423,34 +335,15 @@ struct linear_linear
if ( op == overlay::operation_blocked )
return;
if ( op == overlay::operation_intersection
&& turn_on_the_same_ip<op_id>(m_exit_watcher.get_exit_turn(), *it) )
{
fake_enter_detected = true;
}
m_exit_watcher.reset_detected_exit();
}
// if the new linestring started just now,
// but the previous one went out on the previous point,
// we must check if the boundary of the previous segment is outside
// NOTE: couldn't it be integrated with the handling of the union above?
// THIS IS REDUNDANT WITH THE HANDLING OF THE END OF THE RANGE
//if ( first_in_range
// && ! fake_enter_detected
// && m_previous_operation == overlay::operation_union )
//{
// BOOST_ASSERT(it != first);
// BOOST_ASSERT(m_previous_turn_ptr);
// segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id;
// bool prev_back_b = is_endpoint_on_boundary<boundary_back>(
// range::back(sub_geometry::get(geometry, prev_seg_id)),
// boundary_checker);
// // if there is a boundary on the last point
// if ( prev_back_b )
// {
// update<boundary, exterior, '0', transpose_result>(res);
// }
//}
// i/i, i/x, i/u
if ( op == overlay::operation_intersection )
{
@@ -459,8 +352,9 @@ struct linear_linear
// interiors overlaps
update<interior, interior, '1', transpose_result>(res);
bool this_b = is_ip_on_boundary<boundary_front>(it->point,
bool this_b = it->operations[op_id].position == overlay::position_front // ignore spikes!
&& is_ip_on_boundary<boundary_front>(it->point,
it->operations[op_id],
boundary_checker,
seg_id);
@@ -489,7 +383,9 @@ struct linear_linear
else
{
// if we didn't enter in the past, we were outside
if ( was_outside && !fake_enter_detected )
if ( was_outside
&& ! fake_enter_detected
&& it->operations[op_id].position != overlay::position_front )
{
update<interior, exterior, '1', transpose_result>(res);
@@ -521,7 +417,7 @@ struct linear_linear
// to exit we must be currently inside and the current segment must be collinear
if ( !was_outside && is_collinear )
{
m_exit_watcher.exit(*it);
m_exit_watcher.exit(*it, false);
}
bool op_blocked = op == overlay::operation_blocked;
@@ -530,7 +426,8 @@ struct linear_linear
// possibly going out right now
if ( ! was_outside && is_collinear )
{
if ( op_blocked )
if ( op_blocked
&& it->operations[op_id].position == overlay::position_back ) // ignore spikes!
{
// check if this is indeed the boundary point
// NOTE: is_ip_on_boundary<>() should be called here but the result will be the same
@@ -665,24 +562,33 @@ struct linear_linear
// here, the possible exit is the real one
// we know that we entered and now we exit
if ( /*m_exit_watcher.get_exit_operation() == overlay::operation_union // THIS CHECK IS REDUNDANT
||*/ m_previous_operation == overlay::operation_union )
||*/ m_previous_operation == overlay::operation_union
|| m_degenerated_turn_ptr )
{
// for sure
update<interior, exterior, '1', transpose_result>(res);
BOOST_ASSERT(first != last);
BOOST_ASSERT(m_previous_turn_ptr);
segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id;
bool prev_back_b = is_endpoint_on_boundary<boundary_back>(
range::back(sub_range(geometry, prev_seg_id)),
boundary_checker);
// if there is a boundary on the last point
if ( prev_back_b )
const TurnInfo * turn_ptr = NULL;
if ( m_degenerated_turn_ptr )
turn_ptr = m_degenerated_turn_ptr;
else if ( m_previous_turn_ptr )
turn_ptr = m_previous_turn_ptr;
if ( turn_ptr )
{
update<boundary, exterior, '0', transpose_result>(res);
segment_identifier const& prev_seg_id = turn_ptr->operations[op_id].seg_id;
//BOOST_ASSERT(!boost::empty(sub_range(geometry, prev_seg_id)));
bool prev_back_b = is_endpoint_on_boundary<boundary_back>(
range::back(sub_range(geometry, prev_seg_id)),
boundary_checker);
// if there is a boundary on the last point
if ( prev_back_b )
{
update<boundary, exterior, '0', transpose_result>(res);
}
}
}
@@ -690,13 +596,127 @@ struct linear_linear
// reset exit watcher before the analysis of the next Linestring
// note that if there are some enters stored there may be some error above
m_exit_watcher.reset();
m_previous_turn_ptr = NULL;
m_previous_operation = overlay::operation_none;
m_degenerated_turn_ptr = NULL;
}
template <typename Result,
typename Turn,
typename Geometry,
typename OtherGeometry,
typename BoundaryChecker,
typename OtherBoundaryChecker>
void handle_degenerated(Result & res,
Turn const& turn,
Geometry const& geometry,
OtherGeometry const& other_geometry,
BoundaryChecker const& boundary_checker,
OtherBoundaryChecker const& other_boundary_checker,
bool first_in_range)
{
typename detail::single_geometry_return_type<Geometry const>::type
ls1_ref = detail::single_geometry(geometry, turn.operations[op_id].seg_id);
typename detail::single_geometry_return_type<OtherGeometry const>::type
ls2_ref = detail::single_geometry(other_geometry, turn.operations[op_id].other_id);
// only one of those should be true:
if ( turn.operations[op_id].position == overlay::position_front )
{
// valid, point-sized
if ( boost::size(ls2_ref) == 2 )
{
bool front_b = is_endpoint_on_boundary<boundary_front>(turn.point, boundary_checker);
if ( front_b )
{
update<boundary, interior, '0', transpose_result>(res);
}
else
{
update<interior, interior, '0', transpose_result>(res);
}
// operation 'c' should be last for the same IP so we know that the next point won't be the same
update<interior, exterior, '1', transpose_result>(res);
m_degenerated_turn_ptr = boost::addressof(turn);
}
}
else if ( turn.operations[op_id].position == overlay::position_back )
{
// valid, point-sized
if ( boost::size(ls2_ref) == 2 )
{
update<interior, exterior, '1', transpose_result>(res);
bool back_b = is_endpoint_on_boundary<boundary_back>(turn.point, boundary_checker);
if ( back_b )
{
update<boundary, interior, '0', transpose_result>(res);
}
else
{
update<interior, interior, '0', transpose_result>(res);
}
if ( first_in_range )
{
//BOOST_ASSERT(!boost::empty(ls1_ref));
bool front_b = is_endpoint_on_boundary<boundary_front>(
range::front(ls1_ref), boundary_checker);
if ( front_b )
{
update<boundary, exterior, '0', transpose_result>(res);
}
}
}
}
else if ( turn.operations[op_id].position == overlay::position_middle
&& turn.operations[other_op_id].position == overlay::position_middle )
{
update<interior, interior, '0', transpose_result>(res);
// here we don't know which one is degenerated
bool is_point1 = boost::size(ls1_ref) == 2
&& equals::equals_point_point(range::front(ls1_ref), range::back(ls1_ref));
bool is_point2 = boost::size(ls2_ref) == 2
&& equals::equals_point_point(range::front(ls2_ref), range::back(ls2_ref));
// if the second one is degenerated
if ( !is_point1 && is_point2 )
{
update<interior, exterior, '1', transpose_result>(res);
if ( first_in_range )
{
//BOOST_ASSERT(!boost::empty(ls1_ref));
bool front_b = is_endpoint_on_boundary<boundary_front>(
range::front(ls1_ref), boundary_checker);
if ( front_b )
{
update<boundary, exterior, '0', transpose_result>(res);
}
}
m_degenerated_turn_ptr = boost::addressof(turn);
}
}
// NOTE: other.position == front and other.position == back
// will be handled later, for the other geometry
}
private:
exit_watcher<TurnInfo, OpId> m_exit_watcher;
segment_watcher<same_single_geometry> m_seg_watcher;
TurnInfo * m_previous_turn_ptr;
segment_watcher<same_single> m_seg_watcher;
const TurnInfo * m_previous_turn_ptr;
overlay::operation_type m_previous_operation;
const TurnInfo * m_degenerated_turn_ptr;
};
template <typename Result,

View File

@@ -198,19 +198,22 @@ struct interruption_enabled
detail_dispatch::relate::relate<Geometry1, Geometry2>::interruption_enabled;
};
template <typename Geometry1, typename Geometry2, typename Result>
template <typename Geometry1,
typename Geometry2,
typename Result,
bool IsSequence = boost::mpl::is_sequence<Result>::value>
struct result_handler_type
: not_implemented<Result>
{};
template <typename Geometry1, typename Geometry2>
struct result_handler_type<Geometry1, Geometry2, matrix9>
struct result_handler_type<Geometry1, Geometry2, matrix9, false>
{
typedef matrix_handler<matrix9> type;
};
template <typename Geometry1, typename Geometry2>
struct result_handler_type<Geometry1, Geometry2, mask9>
struct result_handler_type<Geometry1, Geometry2, mask9, false>
{
typedef mask_handler
<
@@ -224,7 +227,7 @@ struct result_handler_type<Geometry1, Geometry2, mask9>
};
template <typename Geometry1, typename Geometry2, typename Head, typename Tail>
struct result_handler_type<Geometry1, Geometry2, boost::tuples::cons<Head, Tail> >
struct result_handler_type<Geometry1, Geometry2, boost::tuples::cons<Head, Tail>, false>
{
typedef mask_handler
<
@@ -241,7 +244,7 @@ template <typename Geometry1, typename Geometry2,
char II, char IB, char IE,
char BI, char BB, char BE,
char EI, char EB, char EE>
struct result_handler_type<Geometry1, Geometry2, static_mask<II, IB, IE, BI, BB, BE, EI, EB, EE> >
struct result_handler_type<Geometry1, Geometry2, static_mask<II, IB, IE, BI, BB, BE, EI, EB, EE>, false>
{
typedef static_mask_handler
<
@@ -254,6 +257,20 @@ struct result_handler_type<Geometry1, Geometry2, static_mask<II, IB, IE, BI, BB,
> type;
};
template <typename Geometry1, typename Geometry2, typename StaticSequence>
struct result_handler_type<Geometry1, Geometry2, StaticSequence, true>
{
typedef static_mask_handler
<
StaticSequence,
interruption_enabled
<
Geometry1,
Geometry2
>::value
> type;
};
template <typename MatrixOrMask, typename Geometry1, typename Geometry2>
inline
typename result_handler_type

View File

@@ -468,7 +468,7 @@ struct check_dispatch< boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> >
template <typename Matrix>
static inline bool apply(mask_type const& mask, Matrix const& matrix)
{
return check_dispatch_tuple<mask_type>::template apply(mask, matrix);
return check_dispatch_tuple<mask_type>::apply(mask, matrix);
}
};
@@ -480,7 +480,7 @@ struct check_dispatch< boost::tuples::cons<Head, Tail> >
template <typename Matrix>
static inline bool apply(mask_type const& mask, Matrix const& matrix)
{
return check_dispatch_tuple<mask_type>::template apply(mask, matrix);
return check_dispatch_tuple<mask_type>::apply(mask, matrix);
}
};
@@ -620,8 +620,8 @@ public:
// static_should_handle_element
template <typename StaticMask, field F1, field F2>
struct static_should_handle_element
template <typename StaticMask, field F1, field F2, bool IsSequence>
struct static_should_handle_element_dispatch
{
static const char mask_el = StaticMask::template get<F1, F2>::value;
static const bool value = mask_el == 'F'
@@ -629,6 +629,56 @@ struct static_should_handle_element
|| ( mask_el >= '0' && mask_el <= '9' );
};
template <typename First, typename Last, field F1, field F2>
struct static_should_handle_element_sequence
{
typedef typename boost::mpl::deref<First>::type StaticMask;
static const bool value
= static_should_handle_element_dispatch
<
StaticMask,
F1, F2,
boost::mpl::is_sequence<StaticMask>::value
>::value
|| static_should_handle_element_sequence
<
typename boost::mpl::next<First>::type,
Last,
F1, F2
>::value;
};
template <typename Last, field F1, field F2>
struct static_should_handle_element_sequence<Last, Last, F1, F2>
{
static const bool value = false;
};
template <typename StaticMask, field F1, field F2>
struct static_should_handle_element_dispatch<StaticMask, F1, F2, true>
{
static const bool value
= static_should_handle_element_sequence
<
typename boost::mpl::begin<StaticMask>::type,
typename boost::mpl::end<StaticMask>::type,
F1, F2
>::value;
};
template <typename StaticMask, field F1, field F2>
struct static_should_handle_element
{
static const bool value
= static_should_handle_element_dispatch
<
StaticMask,
F1, F2,
boost::mpl::is_sequence<StaticMask>::value
>::value;
};
// static_interrupt
template <typename StaticMask, char V, field F1, field F2, bool InterruptEnabled, bool IsSequence>
@@ -1081,7 +1131,7 @@ template <typename Geometry1,
typename Geometry2,
std::size_t Dim1 = topological_dimension<Geometry1>::value,
std::size_t Dim2 = topological_dimension<Geometry2>::value>
struct static_mask_touches_type
struct static_mask_touches_impl
{
typedef boost::mpl::vector<
static_mask<'F', 'T', '*', '*', '*', '*', '*', '*', '*'>,
@@ -1092,11 +1142,16 @@ struct static_mask_touches_type
// According to OGC, doesn't apply to P/P
// Using the above mask the result would be always false
template <typename Geometry1, typename Geometry2>
struct static_mask_touches_type<Geometry1, Geometry2, 0, 0>
struct static_mask_touches_impl<Geometry1, Geometry2, 0, 0>
: not_implemented<typename geometry::tag<Geometry1>::type,
typename geometry::tag<Geometry2>::type>
{};
template <typename Geometry1, typename Geometry2>
struct static_mask_touches_type
: static_mask_touches_impl<Geometry1, Geometry2>
{};
// WITHIN
typedef static_mask<'T', '*', 'F', '*', '*', 'F', '*', '*', '*'> static_mask_within;

View File

@@ -15,9 +15,9 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TURNS_HPP
#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/algorithms/detail/overlay/do_reverse.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp>
#include <boost/type_traits/is_base_of.hpp>
@@ -26,44 +26,11 @@ namespace boost { namespace geometry {
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace relate { namespace turns {
// TURN_INFO
// distance_info
// enriched_distance_info
// distance_enriched_info
// distance_enrichment_info
template<typename P>
struct enriched_info
template <bool IncludeDegenerate = false>
struct assign_policy
: overlay::assign_null_policy
{
typedef typename strategy::distance::services::return_type
<
typename strategy::distance::services::comparable_type
<
typename strategy::distance::services::default_strategy
<
point_tag,
P
>::type
>::type,
P, P
>::type distance_type;
inline enriched_info()
: distance(distance_type())
{}
distance_type distance; // distance-measurement from segment.first to IP
};
// turn_operation_linear_with_distance
// distance_enriched_turn_operation_linear
template <typename P>
struct enriched_turn_operation_linear
: public overlay::turn_operation_linear
{
enriched_info<P> enriched;
static bool const include_degenerate = IncludeDegenerate;
};
// GET_TURNS
@@ -71,16 +38,21 @@ struct enriched_turn_operation_linear
template <typename Geometry1,
typename Geometry2,
typename GetTurnPolicy
= detail::get_turns::get_turn_info_type<Geometry1, Geometry2, overlay::calculate_distance_policy> >
= detail::get_turns::get_turn_info_type<Geometry1, Geometry2, assign_policy<> > >
struct get_turns
{
typedef typename geometry::point_type<Geometry1>::type point1_type;
typedef overlay::turn_info
<
point1_type,
enriched_turn_operation_linear<point1_type>
> turn_info;
<
point1_type,
typename segment_ratio_type<point1_type, detail::no_rescale_policy>::type,
typename detail::get_turns::turn_operation_type
<
Geometry1, Geometry2,
typename segment_ratio_type<point1_type, detail::no_rescale_policy>::type
>::type
> turn_info;
template <typename Turns>
static inline void apply(Turns & turns,
@@ -98,6 +70,8 @@ struct get_turns
Geometry2 const& geometry2,
InterruptPolicy & interrupt_policy)
{
typedef typename geometry::point_type<Geometry1>::type point1_type;
static const bool reverse1 = detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value;
static const bool reverse2 = detail::overlay::do_reverse<geometry::point_order<Geometry2>::value>::value;
@@ -135,28 +109,48 @@ struct op_to_int
}
};
template <typename OpToInt = op_to_int<> >
struct less_greater_op_for_other_same_m_diff_r
template <typename OpToInt>
struct less_op_xxx_linear
{
template <typename Op>
inline bool operator()(Op const& left, Op const& right)
{
static OpToInt op_to_int;
return op_to_int(left) < op_to_int(right);
}
};
struct less_op_linear_linear
: less_op_xxx_linear< op_to_int<0,2,3,1,4,0> >
{};
struct less_op_linear_areal
{
template <typename Op>
inline bool operator()(Op const& left, Op const& right)
{
static turns::op_to_int<0,2,3,1,4,0> op_to_int_xuic;
static turns::op_to_int<0,3,2,1,4,0> op_to_int_xiuc;
if ( left.other_id.multi_index == right.other_id.multi_index )
{
if ( left.other_id.ring_index == right.other_id.ring_index )
return op_to_int(left) < op_to_int(right);
return op_to_int_xuic(left) < op_to_int_xuic(right);
else
return op_to_int(left) > op_to_int(right);
return op_to_int_xiuc(left) < op_to_int_xiuc(right);
}
else
{
return op_to_int(left) < op_to_int(right);
//return op_to_int_xuic(left) < op_to_int_xuic(right);
return left.other_id.multi_index < right.other_id.multi_index;
}
}
};
struct less_op_areal_linear
: less_op_xxx_linear< op_to_int<0,1,0,0,2,0> >
{};
struct less_op_areal_areal
{
template <typename Op>
@@ -201,20 +195,20 @@ struct less_op_areal_areal
// sort turns by G1 - source_index == 0 by:
// seg_id -> distance -> operation
template <std::size_t OpId = 0,
typename LessOp = less_greater_op_for_other_same_m_diff_r<> >
typename LessOp = less_op_xxx_linear< op_to_int<> > >
struct less
{
BOOST_STATIC_ASSERT(OpId < 2);
template <typename Op> static inline
bool use_distance(Op const& left, Op const& right)
bool use_fraction(Op const& left, Op const& right)
{
static LessOp less_op;
if ( geometry::math::equals(left.enriched.distance, right.enriched.distance) )
if ( left.fraction == right.fraction )
return less_op(left, right);
else
return left.enriched.distance < right.enriched.distance;
return left.fraction < right.fraction;
}
template <typename Turn>
@@ -223,7 +217,7 @@ struct less
segment_identifier const& sl = left.operations[OpId].seg_id;
segment_identifier const& sr = right.operations[OpId].seg_id;
return sl < sr || ( sl == sr && use_distance(left.operations[OpId], right.operations[OpId]) );
return sl < sr || ( sl == sr && use_fraction(left.operations[OpId], right.operations[OpId]) );
}
};

View File

@@ -29,7 +29,7 @@
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/algorithms/expand.hpp>
#include <boost/geometry/algorithms/detail/rescale.hpp>
#include <boost/geometry/algorithms/detail/recalculate.hpp>
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
#include <boost/geometry/core/access.hpp>
@@ -37,13 +37,17 @@
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/point_order.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
#include <boost/geometry/policies/robustness/robust_point_type.hpp>
#include <boost/geometry/views/closeable_view.hpp>
#include <boost/geometry/views/reversible_view.hpp>
#include <boost/geometry/geometries/segment.hpp>
namespace boost { namespace geometry
{
@@ -257,22 +261,25 @@ struct sectionalize_part
template
<
typename Range, // Can be closeable_view
typename RescalePolicy,
typename RobustPolicy,
typename Sections
>
static inline void apply(Sections& sections,
Range const& range,
RescalePolicy const& rescale_policy,
RobustPolicy const& robust_policy,
bool make_rescaled_boxes,
ring_identifier ring_id,
std::size_t max_count)
{
boost::ignore_unused_variable_warning(rescale_policy);
boost::ignore_unused_variable_warning(robust_policy);
boost::ignore_unused_variable_warning(make_rescaled_boxes);
typedef model::referring_segment<Point const> segment_type;
typedef typename boost::range_value<Sections>::type section_type;
typedef model::segment
<
typename robust_point_type<Point, RobustPolicy>::type
> robust_segment_type;
typedef typename boost::range_iterator<Range const>::type iterator_type;
if ( boost::empty(range) )
@@ -294,12 +301,14 @@ struct sectionalize_part
++previous, ++it, index++)
{
segment_type segment(*previous, *it);
robust_segment_type robust_segment;
geometry::recalculate(robust_segment, segment, robust_policy);
int direction_classes[DimensionCount] = {0};
get_direction_loop
<
0, DimensionCount
>::apply(segment, direction_classes);
>::apply(robust_segment, direction_classes);
// if "dir" == 0 for all point-dimensions, it is duplicate.
// Those sections might be omitted, if wished, lateron
@@ -313,7 +322,7 @@ struct sectionalize_part
if (check_duplicate_loop
<
0, geometry::dimension<Point>::type::value
>::apply(segment)
>::apply(robust_segment)
)
{
duplicate = true;
@@ -365,10 +374,11 @@ struct sectionalize_part
<
int, 0, DimensionCount
>::apply(direction_classes, section.directions);
geometry::expand(section.bounding_box, *previous);
expand_box(*previous, robust_policy, section);
}
geometry::expand(section.bounding_box, *it);
expand_box(*it, robust_policy, section);
section.end_index = index + 1;
section.count++;
if (! duplicate)
@@ -394,6 +404,16 @@ struct sectionalize_part
sections[last_non_duplicate_index].is_non_duplicate_last = true;
}
}
template <typename InputPoint, typename RobustPolicy, typename Section>
static inline void expand_box(InputPoint const& point,
RobustPolicy const& robust_policy,
Section& section)
{
typename geometry::point_type<typename Section::box_type>::type robust_point;
geometry::recalculate(robust_point, point, robust_policy);
geometry::expand(section.bounding_box, robust_point);
}
};
@@ -408,11 +428,11 @@ struct sectionalize_range
template
<
typename Range,
typename RescalePolicy,
typename RobustPolicy,
typename Sections
>
static inline void apply(Range const& range,
RescalePolicy const& rescale_policy,
RobustPolicy const& robust_policy,
bool make_rescaled_boxes,
Sections& sections,
ring_identifier ring_id,
@@ -442,7 +462,7 @@ struct sectionalize_range
}
sectionalize_part<Point, DimensionCount>
::apply(sections, view, rescale_policy, make_rescaled_boxes, ring_id, max_count);
::apply(sections, view, robust_policy, make_rescaled_boxes, ring_id, max_count);
}
};
@@ -456,11 +476,11 @@ struct sectionalize_polygon
template
<
typename Polygon,
typename RescalePolicy,
typename RobustPolicy,
typename Sections
>
static inline void apply(Polygon const& poly,
RescalePolicy const& rescale_policy,
RobustPolicy const& robust_policy,
bool make_rescaled_boxes,
Sections& sections,
ring_identifier ring_id, std::size_t max_count)
@@ -474,7 +494,7 @@ struct sectionalize_polygon
> per_range;
ring_id.ring_index = -1;
per_range::apply(exterior_ring(poly), rescale_policy, make_rescaled_boxes, sections, ring_id, max_count);
per_range::apply(exterior_ring(poly), robust_policy, make_rescaled_boxes, sections, ring_id, max_count);
ring_id.ring_index++;
typename interior_return_type<Polygon const>::type rings
@@ -482,7 +502,7 @@ struct sectionalize_polygon
for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings);
++it, ++ring_id.ring_index)
{
per_range::apply(*it, rescale_policy, make_rescaled_boxes, sections, ring_id, max_count);
per_range::apply(*it, robust_policy, make_rescaled_boxes, sections, ring_id, max_count);
}
}
};
@@ -496,11 +516,11 @@ struct sectionalize_box
template
<
typename Box,
typename RescalePolicy,
typename RobustPolicy,
typename Sections
>
static inline void apply(Box const& box,
RescalePolicy const& rescale_policy,
RobustPolicy const& robust_policy,
bool make_rescaled_boxes,
Sections& sections,
ring_identifier const& ring_id, std::size_t max_count)
@@ -532,7 +552,7 @@ struct sectionalize_box
closed, false,
point_type,
DimensionCount
>::apply(points, rescale_policy, make_rescaled_boxes, sections,
>::apply(points, robust_policy, make_rescaled_boxes, sections,
ring_id, max_count);
}
};
@@ -551,7 +571,7 @@ inline void set_section_unique_ids(Sections& sections)
}
template <typename Sections>
inline void enlargeSections(Sections& sections)
inline void enlarge_sections(Sections& sections)
{
// Robustness issue. Increase sections a tiny bit such that all points are really within (and not on border)
// Reason: turns might, rarely, be missed otherwise (case: "buffer_mp1")
@@ -669,9 +689,9 @@ struct sectionalize<polygon_tag, Polygon, Reverse, DimensionCount>
\param sections structure with sections
\param source_index index to assign to the ring_identifiers
*/
template<bool Reverse, typename Geometry, typename Sections, typename RescalePolicy>
template<bool Reverse, typename Geometry, typename Sections, typename RobustPolicy>
inline void sectionalize(Geometry const& geometry,
RescalePolicy const& rescale_policy,
RobustPolicy const& robust_policy,
bool make_rescaled_boxes,
Sections& sections,
int source_index = 0)
@@ -690,26 +710,28 @@ inline void sectionalize(Geometry const& geometry,
Geometry,
Reverse,
Sections::value
>::apply(geometry, rescale_policy, make_rescaled_boxes, sections, ring_id, 10);
>::apply(geometry, robust_policy, make_rescaled_boxes, sections, ring_id, 10);
detail::sectionalize::set_section_unique_ids(sections);
if (make_rescaled_boxes)
if (! make_rescaled_boxes)
{
detail::sectionalize::enlargeSections(sections);
detail::sectionalize::enlarge_sections(sections);
}
}
#if defined(BOOST_GEOMETRY_UNIT_TEST_SECTIONALIZE)
// Backwards compatibility
template<bool Reverse, typename Geometry, typename Sections>
inline void sectionalize(Geometry const& geometry,
Sections& sections,
int source_index = 0)
Sections& sections,
int source_index = 0)
{
return sectionalize<Reverse>(geometry, detail::no_rescale_policy(),
false, sections,
source_index);
return geometry::sectionalize<Reverse>(geometry, detail::no_rescale_policy(),
false, sections,
source_index);
}
#endif
}} // namespace boost::geometry

View File

@@ -79,11 +79,10 @@ struct less_seg_dist_other_op
}
template <typename Op>
static inline bool use_distance(Op const& left, Op const& right)
static inline bool use_fraction(Op const& left, Op const& right)
{
return left.enriched.distance < right.enriched.distance
|| ( geometry::math::equals(left.enriched.distance,
right.enriched.distance)
return left.fraction < right.fraction
|| ( geometry::math::equals(left.fraction, right.fraction)
&& use_other_id(left, right)
);
}
@@ -94,7 +93,7 @@ struct less_seg_dist_other_op
segment_identifier const& sl = left.operations[OpId].seg_id;
segment_identifier const& sr = right.operations[OpId].seg_id;
return sl < sr || ( sl == sr && use_distance(left.operations[OpId], right.operations[OpId]) );
return sl < sr || ( sl == sr && use_fraction(left.operations[OpId], right.operations[OpId]) );
}
};

View File

@@ -52,6 +52,11 @@ static inline void print_turns(Geometry1 const& g1,
else
out << '\n';
double fraction[2];
fraction[0] = turn.operations[0].fraction.numerator()
/ turn.operations[0].fraction.denominator();
out << geometry::operation_char(turn.operations[0].operation)
<<": seg: " << turn.operations[0].seg_id.source_index
<< ", m: " << turn.operations[0].seg_id.multi_index
@@ -61,11 +66,15 @@ static inline void print_turns(Geometry1 const& g1,
<< ", m: " << turn.operations[0].other_id.multi_index
<< ", r: " << turn.operations[0].other_id.ring_index
<< ", s: " << turn.operations[0].other_id.segment_index;
out << ", fr: " << fraction[0];
out << ", col?: " << turn.operations[0].is_collinear;
out << ' ' << geometry::dsv(turn.point) << ' ';
out << '\n';
fraction[1] = turn.operations[1].fraction.numerator()
/ turn.operations[1].fraction.denominator();
out << geometry::operation_char(turn.operations[1].operation)
<< ": seg: " << turn.operations[1].seg_id.source_index
<< ", m: " << turn.operations[1].seg_id.multi_index
@@ -75,6 +84,7 @@ static inline void print_turns(Geometry1 const& g1,
<< ", m: " << turn.operations[1].other_id.multi_index
<< ", r: " << turn.operations[1].other_id.ring_index
<< ", s: " << turn.operations[1].other_id.segment_index;
out << ", fr: " << fraction[1];
out << ", col?: " << turn.operations[1].is_collinear;
out << ' ' << geometry::dsv(turn.point) << ' ';

View File

@@ -20,7 +20,7 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_POINT_IN_GEOMETRY_HPP
#include <boost/assert.hpp>
#include <boost/static_assert.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/range.hpp>
@@ -114,7 +114,10 @@ inline int point_in_range(Point const& point, Range const& range)
Geometry
>::type strategy_type2;
BOOST_STATIC_ASSERT(boost::is_same<strategy_type, strategy_type2>::value);
static const bool same_strategies = boost::is_same<strategy_type, strategy_type2>::value;
BOOST_MPL_ASSERT_MSG((same_strategies),
DEFAULT_WITHIN_AND_COVERED_BY_STRATEGIES_NOT_COMPATIBLE,
(strategy_type, strategy_type2));
return point_in_range(point, range, strategy_type());
}
@@ -419,7 +422,10 @@ inline int point_in_geometry(Point const& point, Geometry const& geometry)
Geometry
>::type strategy_type2;
BOOST_STATIC_ASSERT(boost::is_same<strategy_type, strategy_type2>::value);
static const bool same_strategies = boost::is_same<strategy_type, strategy_type2>::value;
BOOST_MPL_ASSERT_MSG((same_strategies),
DEFAULT_WITHIN_AND_COVERED_BY_STRATEGIES_NOT_COMPATIBLE,
(strategy_type, strategy_type2));
return point_in_geometry(point, geometry, strategy_type());
}

View File

@@ -20,93 +20,21 @@
#include <boost/geometry/algorithms/envelope.hpp>
#include <boost/geometry/algorithms/expand.hpp>
#include <boost/geometry/algorithms/detail/recalculate.hpp>
#include <boost/geometry/algorithms/detail/get_max_size.hpp>
#include <boost/geometry/geometries/box.hpp>
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/policies/robustness/rescale_policy.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace zoom_to_robust
{
template <typename Box, std::size_t Dimension>
struct get_max_size
{
static inline typename coordinate_type<Box>::type apply(Box const& box)
{
typename coordinate_type<Box>::type s
= geometry::math::abs(geometry::get<1, Dimension>(box) - geometry::get<0, Dimension>(box));
return (std::max)(s, get_max_size<Box, Dimension - 1>::apply(box));
}
};
template <typename Box>
struct get_max_size<Box, 0>
{
static inline typename coordinate_type<Box>::type apply(Box const& box)
{
return geometry::math::abs(geometry::get<1, 0>(box) - geometry::get<0, 0>(box));
}
};
template <typename FpPoint, typename IntPoint, typename CalculationType>
struct rescale_strategy
{
typedef typename geometry::coordinate_type<IntPoint>::type output_ct;
rescale_strategy(FpPoint const& fp_min, IntPoint const& int_min, CalculationType const& the_factor)
: m_fp_min(fp_min)
, m_int_min(int_min)
, m_multiplier(the_factor)
{
}
template <std::size_t Dimension, typename Value>
inline output_ct apply(Value const& value) const
{
// a + (v-b)*f
CalculationType const a = static_cast<CalculationType>(get<Dimension>(m_int_min));
CalculationType const b = static_cast<CalculationType>(get<Dimension>(m_fp_min));
CalculationType const result = a + (value - b) * m_multiplier;
return static_cast<output_ct>(result);
}
FpPoint const& m_fp_min;
IntPoint const& m_int_min;
CalculationType m_multiplier;
};
}} // namespace detail::zoom_to_robust
#endif // DOXYGEN_NO_DETAIL
template <typename Box>
inline typename coordinate_type<Box>::type get_max_size(Box const& box)
{
return detail::zoom_to_robust::get_max_size<Box, dimension<Box>::value - 1>::apply(box);
}
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename CoordinateType, typename IsFloatingPoint>
struct robust_type
{
};
template <typename CoordinateType>
struct robust_type<CoordinateType, boost::false_type>
{
typedef CoordinateType type;
};
template <typename CoordinateType>
struct robust_type<CoordinateType, boost::true_type>
{
typedef int type; // long long?
};
template <typename IsFloatingPoint>
@@ -160,9 +88,9 @@ struct zoom_to_robust<boost::true_type>
geometry::expand(env, g6);
// Scale this to integer-range
typename geometry::coordinate_type<point1_type>::type diff = get_max_size(env);
typename geometry::coordinate_type<point1_type>::type diff = detail::get_max_size(env);
double range = 1000000000.0; // Define a large range to get precise integer coordinates
double factor = double(int(range / double(diff)));
double factor = double(boost::long_long_type(range / double(diff)));
// Assign input/output minimal points
point1_type min_point1;
@@ -170,9 +98,9 @@ struct zoom_to_robust<boost::true_type>
typedef typename point_type<GeometryOut>::type point2_type;
point2_type min_point2;
assign_values(min_point2, int(-range/2.0), int(-range/2.0));
assign_values(min_point2, boost::long_long_type(-range/2.0), boost::long_long_type(-range/2.0));
detail::zoom_to_robust::rescale_strategy<point1_type, point2_type, double> strategy(min_point1, min_point2, factor);
detail::robust_policy<point1_type, point2_type, double> strategy(min_point1, min_point2, factor);
geometry::recalculate(og1, g1, strategy);
geometry::recalculate(og2, g2, strategy);
@@ -187,15 +115,9 @@ struct zoom_to_robust<boost::true_type>
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
template <typename CoordinateType>
struct robust_type
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
typedef typename dispatch::robust_type
<
CoordinateType,
typename boost::is_floating_point<CoordinateType>::type
>::type type;
};
template <typename Geometry1, typename Geometry2>
@@ -209,21 +131,21 @@ inline void zoom_to_robust(Geometry1 const& g1a, Geometry1 const& g1b, Geometry2
// Get the envelop of inputs
model::box<point1_type> env;
envelope(g1a, env);
expand(env, g1b);
geometry::envelope(g1a, env);
geometry::expand(env, g1b);
// Scale this to integer-range
typename coordinate_type<point1_type>::type diff = get_max_size(env);
typename coordinate_type<point1_type>::type diff = detail::get_max_size(env);
double range = 1000000000.0; // Define a large range to get precise integer coordinates
double factor = range / diff;
// Assign input/output minimal points
detail::assign_point_from_index<0>(env, min_point1);
assign_values(min_point2, int(-range/2.0), int(-range/2.0));
assign_values(min_point2, boost::long_long_type(-range/2.0), boost::long_long_type(-range/2.0));
detail::zoom_to_robust::rescale_strategy<point1_type, point2_type, double> strategy(min_point1, min_point2, factor);
recalculate(g2a, g1a, strategy);
recalculate(g2b, g1b, strategy);
detail::robust_policy<point1_type, point2_type, double> strategy(min_point1, min_point2, factor);
geometry::recalculate(g2a, g1a, strategy);
geometry::recalculate(g2b, g1b, strategy);
}
template
@@ -248,6 +170,9 @@ void zoom_to_robust(Geometry1 const& g1, Geometry2 const& g2, Geometry3 const& g
>::apply(g1, g2, g3, g4, g5, g6, og1, og2, og3, og4, og5, og6);
}
} // namespace detail
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry

View File

@@ -12,6 +12,7 @@
#include <algorithm>
#include <boost/geometry/algorithms/detail/overlay/intersection_insert.hpp>
#include <boost/geometry/policies/robustness/get_rescale_policy.hpp>
namespace boost { namespace geometry
{
@@ -43,11 +44,14 @@ template
typename GeometryOut,
typename Geometry1,
typename Geometry2,
typename RobustPolicy,
typename OutputIterator,
typename Strategy
>
inline OutputIterator difference_insert(Geometry1 const& geometry1,
Geometry2 const& geometry2, OutputIterator out,
Geometry2 const& geometry2,
RobustPolicy const& robust_policy,
OutputIterator out,
Strategy const& strategy)
{
concept::check<Geometry1 const>();
@@ -61,7 +65,7 @@ inline OutputIterator difference_insert(Geometry1 const& geometry1,
overlay_difference,
geometry::detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
geometry::detail::overlay::do_reverse<geometry::point_order<Geometry2>::value, true>::value
>::apply(geometry1, geometry2, out, strategy);
>::apply(geometry1, geometry2, robust_policy, out, strategy);
}
/*!
@@ -85,10 +89,13 @@ template
typename GeometryOut,
typename Geometry1,
typename Geometry2,
typename RobustPolicy,
typename OutputIterator
>
inline OutputIterator difference_insert(Geometry1 const& geometry1,
Geometry2 const& geometry2, OutputIterator out)
Geometry2 const& geometry2,
RobustPolicy const& robust_policy,
OutputIterator out)
{
concept::check<Geometry1 const>();
concept::check<Geometry2 const>();
@@ -99,11 +106,12 @@ inline OutputIterator difference_insert(Geometry1 const& geometry1,
typename cs_tag<GeometryOut>::type,
Geometry1,
Geometry2,
typename geometry::point_type<GeometryOut>::type
typename geometry::point_type<GeometryOut>::type,
RobustPolicy
> strategy;
return difference_insert<GeometryOut>(geometry1, geometry2,
out, strategy());
robust_policy, out, strategy());
}
@@ -140,8 +148,17 @@ inline void difference(Geometry1 const& geometry1,
typedef typename boost::range_value<Collection>::type geometry_out;
concept::check<geometry_out>();
typedef typename geometry::rescale_overlay_policy_type
<
Geometry1,
Geometry2
>::type rescale_policy_type;
rescale_policy_type robust_policy
= geometry::get_rescale_policy<rescale_policy_type>(geometry1, geometry2);
detail::difference::difference_insert<geometry_out>(
geometry1, geometry2,
geometry1, geometry2, robust_policy,
std::back_inserter(output_collection));
}

View File

@@ -39,7 +39,6 @@
#include <boost/geometry/algorithms/detail/point_on_border.hpp>
#include <boost/geometry/algorithms/point_on_surface.hpp>
#include <boost/geometry/algorithms/detail/for_each_range.hpp>
#include <boost/geometry/algorithms/detail/rescale.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
@@ -48,6 +47,10 @@
#include <boost/geometry/algorithms/detail/overlay/do_reverse.hpp>
#include <boost/geometry/views/segment_view.hpp>
#include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
namespace boost { namespace geometry
{
@@ -116,8 +119,12 @@ struct disjoint_linear
static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
{
typedef typename geometry::point_type<Geometry1>::type point_type;
typedef overlay::turn_info<point_type> turn_info;
typedef detail::no_rescale_policy rescale_policy_type;
typedef overlay::turn_info
<
point_type,
typename segment_ratio_type<point_type, rescale_policy_type>::type
> turn_info;
std::deque<turn_info> turns;
static const bool reverse1 = overlay::do_reverse<geometry::point_order<Geometry1>::value>::value; // should be false
@@ -127,11 +134,12 @@ struct disjoint_linear
// 1) Stop at any intersection
// 2) In assignment, include also degenerate points (which are normally skipped)
disjoint_interrupt_policy policy;
rescale_policy_type robust_policy;
geometry::get_turns
<
reverse1, reverse2,
assign_disjoint_policy
>(geometry1, geometry2, detail::no_rescale_policy(), turns, policy);
>(geometry1, geometry2, robust_policy, turns, policy);
return !policy.has_intersections;
}
@@ -144,16 +152,28 @@ struct disjoint_segment
{
typedef typename point_type<Segment1>::type point_type;
segment_intersection_points<point_type> is
// We don't need to rescale to detect disjointness
typedef no_rescale_policy rescale_policy_type;
rescale_policy_type robust_policy;
typedef segment_intersection_points
<
point_type,
typename segment_ratio_type
<
point_type,
rescale_policy_type
>::type
> intersection_return_type;
intersection_return_type is
= strategy::intersection::relate_cartesian_segments
<
policies::relate::segments_intersection_points
<
Segment1,
Segment2,
segment_intersection_points<point_type>
intersection_return_type
>
>::apply(segment1, segment2);
>::apply(segment1, segment2, robust_policy);
return is.count == 0;
}

View File

@@ -13,6 +13,7 @@
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/algorithms/detail/overlay/intersection_insert.hpp>
#include <boost/geometry/algorithms/intersects.hpp>
#include <boost/geometry/policies/robustness/get_rescale_policy.hpp>
namespace boost { namespace geometry
@@ -27,11 +28,15 @@ struct intersection_box_box
{
template
<
typename Box1, typename Box2, typename BoxOut,
typename Box1, typename Box2,
typename RobustPolicy,
typename BoxOut,
typename Strategy
>
static inline bool apply(Box1 const& box1,
Box2 const& box2, BoxOut& box_out,
Box2 const& box2,
RobustPolicy const& robust_policy,
BoxOut& box_out,
Strategy const& strategy)
{
typedef typename coordinate_type<BoxOut>::type ct;
@@ -50,7 +55,7 @@ struct intersection_box_box
set<max_corner, Dimension>(box_out, max1 > max2 ? max2 : max1);
return intersection_box_box<Dimension + 1, DimensionCount>
::apply(box1, box2, box_out, strategy);
::apply(box1, box2, robust_policy, box_out, strategy);
}
};
@@ -59,10 +64,13 @@ struct intersection_box_box<DimensionCount, DimensionCount>
{
template
<
typename Box1, typename Box2, typename BoxOut,
typename Box1, typename Box2,
typename RobustPolicy,
typename BoxOut,
typename Strategy
>
static inline bool apply(Box1 const&, Box2 const&, BoxOut&, Strategy const&)
static inline bool apply(Box1 const&, Box2 const&,
RobustPolicy const&, BoxOut&, Strategy const&)
{
return true;
}
@@ -88,9 +96,10 @@ template
>
struct intersection
{
template <typename GeometryOut, typename Strategy>
template <typename RobustPolicy, typename GeometryOut, typename Strategy>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
RobustPolicy const& robust_policy,
GeometryOut& geometry_out,
Strategy const& strategy)
{
@@ -100,7 +109,7 @@ struct intersection
<
Geometry1, Geometry2, OneOut,
overlay_intersection
>::apply(geometry1, geometry2, std::back_inserter(geometry_out), strategy);
>::apply(geometry1, geometry2, robust_policy, std::back_inserter(geometry_out), strategy);
return true;
}
@@ -122,10 +131,11 @@ struct intersection
>
: intersection<Geometry2, Geometry1, Tag2, Tag1, false>
{
template <typename GeometryOut, typename Strategy>
template <typename RobustPolicy, typename GeometryOut, typename Strategy>
static inline bool apply(
Geometry1 const& g1,
Geometry2 const& g2,
RobustPolicy const& robust_policy,
GeometryOut& out,
Strategy const& strategy)
{
@@ -133,7 +143,7 @@ struct intersection
Geometry2, Geometry1,
Tag2, Tag1,
false
>::apply(g2, g1, out, strategy);
>::apply(g2, g1, robust_policy, out, strategy);
}
};
@@ -186,19 +196,29 @@ inline bool intersection(Geometry1 const& geometry1,
concept::check<Geometry1 const>();
concept::check<Geometry2 const>();
typedef typename geometry::rescale_overlay_policy_type
<
Geometry1,
Geometry2
>::type rescale_policy_type;
rescale_policy_type robust_policy
= geometry::get_rescale_policy<rescale_policy_type>(geometry1, geometry2);
typedef strategy_intersection
<
typename cs_tag<Geometry1>::type,
Geometry1,
Geometry2,
typename geometry::point_type<Geometry1>::type
typename geometry::point_type<Geometry1>::type,
rescale_policy_type
> strategy;
return dispatch::intersection<
Geometry1,
Geometry2
>::apply(geometry1, geometry2, geometry_out, strategy());
return dispatch::intersection
<
Geometry1,
Geometry2
>::apply(geometry1, geometry2, robust_policy, geometry_out, strategy());
}

View File

@@ -19,9 +19,11 @@
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp>
#include <boost/geometry/algorithms/detail/rescale.hpp>
#include <boost/geometry/algorithms/disjoint.hpp>
#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
#include <boost/geometry/policies/robustness/get_rescale_policy.hpp>
namespace boost { namespace geometry
{
@@ -44,31 +46,40 @@ inline bool intersects(Geometry const& geometry)
{
concept::check<Geometry const>();
typedef typename geometry::point_type<Geometry>::type point_type;
typedef typename rescale_policy_type<point_type>::type
rescale_policy_type;
typedef detail::overlay::turn_info
<
typename geometry::point_type<Geometry>::type
point_type,
typename segment_ratio_type<point_type, rescale_policy_type>::type
> turn_info;
std::deque<turn_info> turns;
typedef typename strategy_intersection
<
typename cs_tag<Geometry>::type,
Geometry,
Geometry,
typename geometry::point_type<Geometry>::type
>::segment_intersection_strategy_type segment_intersection_strategy_type;
std::deque<turn_info> turns;
typedef detail::overlay::get_turn_info
<
detail::overlay::assign_null_policy
> TurnPolicy;
typedef typename strategy_intersection
<
typename cs_tag<Geometry>::type,
Geometry,
Geometry,
point_type,
rescale_policy_type
>::segment_intersection_strategy_type segment_intersection_strategy_type;
rescale_policy_type robust_policy
= geometry::get_rescale_policy<rescale_policy_type>(geometry);
detail::disjoint::disjoint_interrupt_policy policy;
detail::self_get_turn_points::get_turns
<
TurnPolicy
>::apply(geometry, detail::no_rescale_policy(), turns, policy);
>::apply(geometry, robust_policy, turns, policy);
return policy.has_intersections;
}

View File

@@ -315,13 +315,13 @@ inline bool calculate_point_on_surface(Geometry const& geometry, Point& point)
/*!
\brief Returns point guaranteed to lie on the surface
\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 point to assign
\param geometry geometry to take point from
\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)
inline void point_on_surface(Geometry const& geometry, Point & point)
{
concept::check<Point>();
concept::check<Geometry const>();
@@ -334,12 +334,18 @@ inline void point_on_surface(Geometry const& geometry, Point& point)
}
}
/*!
\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
\return The Point guaranteed to lie on the surface of the Geometry
*/
template<typename Geometry>
inline typename geometry::point_type<Geometry>::type return_point_on_surface(Geometry const& geometry)
inline typename geometry::point_type<Geometry>::type
return_point_on_surface(Geometry const& geometry)
{
typename geometry::point_type<Geometry>::type result;
point_on_surface(geometry, result);
geometry::point_on_surface(geometry, result);
return result;
}

View File

@@ -69,7 +69,7 @@ struct range_remove_spikes
std::size_t const min_num_points = core_detail::closure::minimum_ring_size
<
geometry::closure<Range>::value
>::value;
>::value - 1; // subtract one: a polygon with only one spike should result into one point
if (n < min_num_points)
{
return;
@@ -104,13 +104,13 @@ 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()))
{
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()))
{
cleaned.pop_front();
found = true;
@@ -118,6 +118,13 @@ struct range_remove_spikes
}
while (found);
if (cleaned.size() == 2)
{
// Ticket #9871: open polygon with only two points.
// the second point forms, by definition, a spike
cleaned.pop_back();
}
// Close if necessary
if (geometry::closure<Range>::value == geometry::closed)
{

View File

@@ -46,11 +46,14 @@ template
typename GeometryOut,
typename Geometry1,
typename Geometry2,
typename RobustPolicy,
typename OutputIterator,
typename Strategy
>
inline OutputIterator sym_difference_insert(Geometry1 const& geometry1,
Geometry2 const& geometry2, OutputIterator out,
Geometry2 const& geometry2,
RobustPolicy const& robust_policy,
OutputIterator out,
Strategy const& strategy)
{
concept::check<Geometry1 const>();
@@ -64,7 +67,7 @@ inline OutputIterator sym_difference_insert(Geometry1 const& geometry1,
overlay_difference,
geometry::detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
geometry::detail::overlay::do_reverse<geometry::point_order<Geometry2>::value, true>::value
>::apply(geometry1, geometry2, out, strategy);
>::apply(geometry1, geometry2, robust_policy, out, strategy);
out = geometry::dispatch::intersection_insert
<
Geometry2, Geometry1,
@@ -73,7 +76,7 @@ inline OutputIterator sym_difference_insert(Geometry1 const& geometry1,
geometry::detail::overlay::do_reverse<geometry::point_order<Geometry2>::value>::value,
geometry::detail::overlay::do_reverse<geometry::point_order<Geometry1>::value, true>::value,
geometry::detail::overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value
>::apply(geometry2, geometry1, out, strategy);
>::apply(geometry2, geometry1, robust_policy, out, strategy);
return out;
}
@@ -97,10 +100,12 @@ template
typename GeometryOut,
typename Geometry1,
typename Geometry2,
typename RobustPolicy,
typename OutputIterator
>
inline OutputIterator sym_difference_insert(Geometry1 const& geometry1,
Geometry2 const& geometry2, OutputIterator out)
Geometry2 const& geometry2,
RobustPolicy const& robust_policy, OutputIterator out)
{
concept::check<Geometry1 const>();
concept::check<Geometry2 const>();
@@ -111,10 +116,11 @@ inline OutputIterator sym_difference_insert(Geometry1 const& geometry1,
typename cs_tag<GeometryOut>::type,
Geometry1,
Geometry2,
typename geometry::point_type<GeometryOut>::type
typename geometry::point_type<GeometryOut>::type,
RobustPolicy
> strategy_type;
return sym_difference_insert<GeometryOut>(geometry1, geometry2, out, strategy_type());
return sym_difference_insert<GeometryOut>(geometry1, geometry2, robust_policy, out, strategy_type());
}
}} // namespace detail::sym_difference
@@ -150,8 +156,17 @@ inline void sym_difference(Geometry1 const& geometry1,
typedef typename boost::range_value<Collection>::type geometry_out;
concept::check<geometry_out>();
typedef typename geometry::rescale_overlay_policy_type
<
Geometry1,
Geometry2
>::type rescale_policy_type;
rescale_policy_type robust_policy
= geometry::get_rescale_policy<rescale_policy_type>(geometry1, geometry2);
detail::sym_difference::sym_difference_insert<geometry_out>(
geometry1, geometry2,
geometry1, geometry2, robust_policy,
std::back_inserter(output_collection));
}

View File

@@ -5,8 +5,8 @@
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2013.
// Modifications copyright (c) 2013, Oracle and/or its affiliates.
// This file was modified by Oracle on 2013, 2014.
// Modifications copyright (c) 2013, 2014, Oracle and/or its affiliates.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -15,6 +15,8 @@
// 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_TOUCHES_HPP
#define BOOST_GEOMETRY_ALGORITHMS_TOUCHES_HPP
@@ -29,10 +31,13 @@
#include <boost/geometry/algorithms/intersects.hpp>
#include <boost/geometry/algorithms/num_geometries.hpp>
#include <boost/geometry/algorithms/detail/sub_range.hpp>
#include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
#include <boost/variant/static_visitor.hpp>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/algorithms/detail/relate/relate.hpp>
namespace boost { namespace geometry
{
@@ -40,6 +45,86 @@ namespace boost { namespace geometry
namespace detail { namespace touches
{
// Box/Box
template
<
std::size_t Dimension,
std::size_t DimensionCount
>
struct box_box_loop
{
template <typename Box1, typename Box2>
static inline bool apply(Box1 const& b1, Box2 const& b2, bool & touch)
{
typedef typename coordinate_type<Box1>::type coordinate_type1;
typedef typename coordinate_type<Box2>::type coordinate_type2;
coordinate_type1 const& min1 = get<min_corner, Dimension>(b1);
coordinate_type1 const& max1 = get<max_corner, Dimension>(b1);
coordinate_type2 const& min2 = get<min_corner, Dimension>(b2);
coordinate_type2 const& max2 = get<max_corner, Dimension>(b2);
// TODO assert or exception?
//BOOST_ASSERT(min1 <= max1 && min2 <= max2);
if ( max1 < min2 || max2 < min1 )
{
return false;
}
if ( max1 == min2 || max2 == min1 )
{
touch = true;
}
return box_box_loop
<
Dimension + 1,
DimensionCount
>::apply(b1, b2, touch);
}
};
template
<
std::size_t DimensionCount
>
struct box_box_loop<DimensionCount, DimensionCount>
{
template <typename Box1, typename Box2>
static inline bool apply(Box1 const& , Box2 const&, bool &)
{
return true;
}
};
struct box_box
{
template <typename Box1, typename Box2>
static inline bool apply(Box1 const& b1, Box2 const& b2)
{
BOOST_STATIC_ASSERT((boost::is_same
<
typename geometry::coordinate_system<Box1>::type,
typename geometry::coordinate_system<Box2>::type
>::value
));
assert_dimension_equal<Box1, Box2>();
bool touches = false;
bool ok = box_box_loop
<
0,
dimension<Box1>::type::value
>::apply(b1, b2, touches);
return ok && touches;
}
};
// Areal/Areal
struct areal_interrupt_policy
{
static bool const enabled = true;
@@ -117,134 +202,6 @@ struct areal_interrupt_policy
}
};
template <typename Linear>
struct linear_areal_interrupt_policy
{
static bool const enabled = true;
bool found_touch;
bool found_not_touch;
Linear const& linear;
// dummy variable required by self_get_turn_points::get_turns
static bool const has_intersections = false;
inline bool result()
{
return found_touch && !found_not_touch;
}
inline linear_areal_interrupt_policy(Linear const& l)
: found_touch(false), found_not_touch(false), linear(l)
{}
template <typename Range>
inline bool apply(Range const& range)
{
// if already rejected (temp workaround?)
if ( found_not_touch )
return true;
typedef typename boost::range_iterator<Range const>::type iterator;
for ( iterator it = boost::begin(range) ; it != boost::end(range) ; ++it )
{
if ( it->operations[0].operation == overlay::operation_intersection )
{
if ( it->operations[1].operation == overlay::operation_union &&
is_turn_on_last_point(*it) )
{
found_touch = true;
continue;
}
else
{
found_not_touch = true;
return true;
}
}
switch(it->method)
{
case overlay::method_crosses:
found_not_touch = true;
return true;
case overlay::method_equal:
case overlay::method_touch:
case overlay::method_touch_interior:
case overlay::method_collinear:
if ( ok_for_touch(*it) )
{
found_touch = true;
}
else
{
found_not_touch = true;
return true;
}
break;
case overlay::method_none :
case overlay::method_disjoint :
case overlay::method_error :
break;
}
}
return false;
}
template <typename Turn>
inline bool ok_for_touch(Turn const& turn)
{
return turn.both(overlay::operation_union)
|| turn.both(overlay::operation_blocked)
|| turn.combination(overlay::operation_union, overlay::operation_blocked)
|| turn.both(overlay::operation_continue)
|| turn.combination(overlay::operation_union, overlay::operation_intersection)
;
}
template <typename Turn>
inline bool is_turn_on_last_point(Turn const& turn)
{
typename sub_range_return_type<Linear const>::type
g = sub_range(linear, turn.operations[0].seg_id);
std::size_t s = boost::size(g);
if ( s == 0 )
return false; // shouldn't return here
else if ( s == 1 )
return equals::equals_point_point(turn.point, *boost::begin(g)); // nor here
else
return equals::equals_point_point(turn.point, *(boost::end(g)-1));
}
};
template <std::size_t Max>
struct turns_count_interrupt_policy
{
static bool const enabled = true;
std::size_t turns_count;
// dummy variable required by self_get_turn_points::get_turns
static bool const has_intersections = false;
inline turns_count_interrupt_policy()
: turns_count(0)
{}
template <typename Range>
inline bool apply(Range const& range)
{
turns_count += boost::size(range);
if ( Max < turns_count )
return true;
return false;
}
};
template<typename Geometry>
struct check_each_ring_for_within
{
@@ -261,16 +218,13 @@ struct check_each_ring_for_within
{
typename geometry::point_type<Range>::type p;
geometry::point_on_border(p, range);
if (geometry::within(p, m_geometry))
if ( !has_within && geometry::within(p, m_geometry) )
{
has_within = true;
}
}
};
// TODO: currently this function checks if a point of at least one range from g2 is within g1
// shouldn't it check the opposite?
template <typename FirstGeometry, typename SecondGeometry>
inline bool rings_containing(FirstGeometry const& geometry1,
SecondGeometry const& geometry2)
@@ -286,9 +240,12 @@ struct areal_areal
static inline
bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
{
typedef detail::no_rescale_policy rescale_policy_type;
typedef typename geometry::point_type<Geometry1>::type point_type;
typedef detail::overlay::turn_info
<
typename geometry::point_type<Geometry1>::type
point_type,
typename segment_ratio_type<point_type, rescale_policy_type>::type
> turn_info;
typedef detail::overlay::get_turn_info
@@ -298,12 +255,13 @@ struct areal_areal
std::deque<turn_info> turns;
detail::touches::areal_interrupt_policy policy;
rescale_policy_type robust_policy;
boost::geometry::get_turns
<
detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
detail::overlay::do_reverse<geometry::point_order<Geometry2>::value>::value,
detail::overlay::assign_null_policy
>(geometry1, geometry2, detail::no_rescale_policy(), turns, policy);
>(geometry1, geometry2, robust_policy, turns, policy);
return policy.result()
&& ! geometry::detail::touches::rings_containing(geometry1, geometry2)
@@ -311,99 +269,17 @@ struct areal_areal
}
};
template <typename Geometry1, typename Geometry2>
struct linear_areal
// P/*
struct use_point_in_geometry
{
static inline
bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
{
typedef detail::overlay::turn_info
<
typename geometry::point_type<Geometry1>::type
> turn_info;
typedef detail::overlay::get_turn_info
<
detail::overlay::assign_null_policy
> policy_type;
std::deque<turn_info> turns;
detail::touches::linear_areal_interrupt_policy<Geometry1> policy(geometry1);
boost::geometry::get_turns
<
detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
detail::overlay::do_reverse<geometry::point_order<Geometry2>::value>::value,
detail::overlay::assign_null_policy
>(geometry1, geometry2, detail::no_rescale_policy(), turns, policy);
return policy.result()
&& ! geometry::detail::touches::rings_containing(geometry2, geometry1);
}
};
template <typename Point, typename Geometry>
struct point_geometry
{
static inline
bool apply(Point const& point, Geometry const& geometry)
template <typename Point, typename Geometry>
static inline bool apply(Point const& point, Geometry const& geometry)
{
return detail::within::point_in_geometry(point, geometry) == 0;
}
};
template <typename Geometry1, typename Geometry2>
struct linestring_linestring
{
static inline
bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
{
std::size_t s1 = boost::size(geometry1);
std::size_t s2 = boost::size(geometry2);
// TODO: throw on empty input?
if ( s1 == 0 || s2 == 0 )
return false;
typedef detail::overlay::turn_info
<
typename geometry::point_type<Geometry1>::type
> turn_info;
typedef detail::overlay::get_turn_info
<
detail::overlay::assign_null_policy
> policy_type;
std::deque<turn_info> turns;
turns_count_interrupt_policy<2> policy;
boost::geometry::get_turns
<
detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
detail::overlay::do_reverse<geometry::point_order<Geometry2>::value>::value,
detail::overlay::assign_null_policy
>(geometry1, geometry2, detail::no_rescale_policy(), turns, policy);
if ( 2 < policy.turns_count )
return false;
else if ( 2 == policy.turns_count )
{
return ( detail::equals::equals_point_point(turns[0].point, *(boost::end(geometry1)-1))
&& detail::equals::equals_point_point(turns[1].point, *(boost::end(geometry2)-1)) )
|| ( detail::equals::equals_point_point(turns[0].point, *(boost::end(geometry2)-1))
&& detail::equals::equals_point_point(turns[1].point, *(boost::end(geometry1)-1)) );
}
else if ( 1 == policy.turns_count )
{
return detail::equals::equals_point_point(turns[0].point, *(boost::end(geometry1)-1))
|| detail::equals::equals_point_point(turns[0].point, *(boost::end(geometry2)-1));
}
else
{
return detail::within::point_in_geometry(*boost::begin(geometry1), geometry2) >= 0
|| detail::within::point_in_geometry(*boost::begin(geometry2), geometry1) >= 0;
}
}
};
}}
#endif // DOXYGEN_NO_DETAIL
@@ -417,11 +293,12 @@ template
typename Geometry1, typename Geometry2,
typename Tag1 = typename tag<Geometry1>::type,
typename Tag2 = typename tag<Geometry2>::type,
typename CastedTag1 = typename tag_cast<Tag1, point_tag, linear_tag, areal_tag>::type,
typename CastedTag2 = typename tag_cast<Tag2, point_tag, linear_tag, areal_tag>::type,
typename CastedTag1 = typename tag_cast<Tag1, pointlike_tag, linear_tag, areal_tag>::type,
typename CastedTag2 = typename tag_cast<Tag2, pointlike_tag, linear_tag, areal_tag>::type,
bool Reverse = reverse_dispatch<Geometry1, Geometry2>::type::value
>
struct touches : not_implemented<Tag1, Tag2>
struct touches
: not_implemented<Tag1, Tag2>
{};
// If reversal is needed, perform it
@@ -440,10 +317,10 @@ struct touches<Geometry1, Geometry2, Tag1, Tag2, CastedTag1, CastedTag2, true>
}
};
// touches(Pt, Pt), touches(Pt, MPt), touches(MPt, MPt)
// P/P
template <typename Geometry1, typename Geometry2, typename Tag1, typename Tag2>
struct touches<Geometry1, Geometry2, Tag1, Tag2, point_tag, point_tag, false>
: detail::touches::point_geometry<Geometry1, Geometry2>
struct touches<Geometry1, Geometry2, Tag1, Tag2, pointlike_tag, pointlike_tag, false>
{
static inline bool apply(Geometry1 const& , Geometry2 const& )
{
@@ -451,38 +328,64 @@ struct touches<Geometry1, Geometry2, Tag1, Tag2, point_tag, point_tag, false>
}
};
// touches(Point, Linear), touches(Point, Areal)
// P/*
template <typename Point, typename Geometry, typename Tag2, typename CastedTag2>
struct touches<Point, Geometry, point_tag, Tag2, point_tag, CastedTag2, false>
: detail::touches::point_geometry<Point, Geometry>
struct touches<Point, Geometry, point_tag, Tag2, pointlike_tag, CastedTag2, false>
: detail::touches::use_point_in_geometry
{};
// TODO: support touches(MPt, Linear/Areal)
// touches(Linestring, Linestring)
template <typename Linestring1, typename Linestring2>
struct touches<Linestring1, Linestring2, linestring_tag, linestring_tag, linear_tag, linear_tag, false>
: detail::touches::linestring_linestring<Linestring1, Linestring2>
// Box/Box
template <typename Box1, typename Box2, typename CastedTag1, typename CastedTag2>
struct touches<Box1, Box2, box_tag, box_tag, CastedTag1, CastedTag2, false>
: detail::touches::box_box
{};
// TODO: support touches(MLs, MLs) and touches(Ls, MLs)
template <typename Box1, typename Box2>
struct touches<Box1, Box2, box_tag, box_tag, areal_tag, areal_tag, false>
: detail::touches::box_box
{};
// L/L
template <typename Linear1, typename Linear2, typename Tag1, typename Tag2>
struct touches<Linear1, Linear2, Tag1, Tag2, linear_tag, linear_tag, false>
: detail::relate::relate_base
<
detail::relate::static_mask_touches_type,
Linear1,
Linear2
>
{};
// L/A
// touches(Linear, Areal)
template <typename Linear, typename Areal, typename Tag1, typename Tag2>
struct touches<Linear, Areal, Tag1, Tag2, linear_tag, areal_tag, false>
: detail::touches::linear_areal<Linear, Areal>
: detail::relate::relate_base
<
detail::relate::static_mask_touches_type,
Linear,
Areal
>
{};
// e.g. for touches(Poly, MLs)
template <typename Areal, typename Linear, typename Tag1, typename Tag2>
struct touches<Areal, Linear, Tag1, Tag2, areal_tag, linear_tag, false>
{
static inline bool apply(Areal const& areal, Linear const& linear)
{
return detail::touches::linear_areal<Linear, Areal>::apply(linear, areal);
}
};
// touches(Areal, Areal)
// A/L
template <typename Linear, typename Areal, typename Tag1, typename Tag2>
struct touches<Linear, Areal, Tag1, Tag2, linear_tag, areal_tag, true>
: detail::relate::relate_base
<
detail::relate::static_mask_touches_type,
Areal,
Linear
>
{};
// A/A
template <typename Areal1, typename Areal2, typename Tag1, typename Tag2>
struct touches<Areal1, Areal2, Tag1, Tag2, areal_tag, areal_tag, false>
: detail::touches::areal_areal<Areal1, Areal2>
@@ -585,10 +488,13 @@ struct self_touches
{
concept::check<Geometry const>();
typedef detail::no_rescale_policy rescale_policy_type;
typedef typename geometry::point_type<Geometry>::type point_type;
typedef detail::overlay::turn_info
<
typename geometry::point_type<Geometry>::type
> turn_info;
<
point_type,
typename segment_ratio_type<point_type, rescale_policy_type>::type
> turn_info;
typedef detail::overlay::get_turn_info
<
@@ -597,10 +503,11 @@ struct self_touches
std::deque<turn_info> turns;
detail::touches::areal_interrupt_policy policy;
rescale_policy_type robust_policy;
detail::self_get_turn_points::get_turns
<
policy_type
>::apply(geometry, detail::no_rescale_policy(), turns, policy);
>::apply(geometry, robust_policy, turns, policy);
return policy.result();
}

View File

@@ -23,6 +23,7 @@
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/algorithms/detail/overlay/overlay.hpp>
#include <boost/geometry/policies/robustness/get_rescale_policy.hpp>
#include <boost/geometry/algorithms/detail/overlay/linear_linear.hpp>
#include <boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp>
@@ -71,15 +72,17 @@ struct union_insert
true
>: union_insert<Geometry2, Geometry1, GeometryOut>
{
template <typename OutputIterator, typename Strategy>
template <typename RobustPolicy, typename OutputIterator, typename Strategy>
static inline OutputIterator apply(Geometry1 const& g1,
Geometry2 const& g2, OutputIterator out,
Geometry2 const& g2,
RobustPolicy const& robust_policy,
OutputIterator out,
Strategy const& strategy)
{
return union_insert
<
Geometry2, Geometry1, GeometryOut
>::apply(g2, g1, out, strategy);
>::apply(g2, g1, robust_policy, out, strategy);
}
};
@@ -180,18 +183,20 @@ template
<
typename GeometryOut,
typename Geometry1, typename Geometry2,
typename RobustPolicy,
typename OutputIterator,
typename Strategy
>
inline OutputIterator insert(Geometry1 const& geometry1,
Geometry2 const& geometry2,
RobustPolicy const& robust_policy,
OutputIterator out,
Strategy const& strategy)
{
return dispatch::union_insert
<
Geometry1, Geometry2, GeometryOut
>::apply(geometry1, geometry2, out, strategy);
>::apply(geometry1, geometry2, robust_policy, out, strategy);
}
/*!
@@ -229,7 +234,11 @@ inline OutputIterator union_insert(Geometry1 const& geometry1,
concept::check<Geometry2 const>();
concept::check<GeometryOut>();
return detail::union_::insert<GeometryOut>(geometry1, geometry2, out, strategy);
typedef typename Strategy::rescale_policy_type rescale_policy_type;
rescale_policy_type robust_policy
= geometry::get_rescale_policy<rescale_policy_type>(geometry1, geometry2);
return detail::union_::insert<GeometryOut>(geometry1, geometry2, robust_policy, out, strategy);
}
/*!
@@ -261,12 +270,19 @@ inline OutputIterator union_insert(Geometry1 const& geometry1,
concept::check<Geometry2 const>();
concept::check<GeometryOut>();
typedef typename geometry::rescale_overlay_policy_type
<
Geometry1,
Geometry2
>::type rescale_policy_type;
typedef strategy_intersection
<
typename cs_tag<GeometryOut>::type,
Geometry1,
Geometry2,
typename geometry::point_type<GeometryOut>::type
typename geometry::point_type<GeometryOut>::type,
rescale_policy_type
> strategy;
return union_insert<GeometryOut>(geometry1, geometry2, out, strategy());

View File

@@ -14,7 +14,6 @@
#ifndef BOOST_GEOMETRY_CORE_TAG_HPP
#define BOOST_GEOMETRY_CORE_TAG_HPP
#include <boost/mpl/assert.hpp>
#include <boost/geometry/core/tags.hpp>

View File

@@ -447,7 +447,8 @@ template
typename OutputIterator,
typename DistanceStrategy,
typename JoinStrategy,
typename EndStrategy
typename EndStrategy,
typename RobustPolicy
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
, typename Mapper
#endif
@@ -455,7 +456,8 @@ template
inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator out,
DistanceStrategy const& distance_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy
EndStrategy const& end_strategy,
RobustPolicy const& robust_policy
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
, Mapper& mapper
#endif
@@ -467,8 +469,9 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator
detail::buffer::buffered_piece_collection
#endif
<
typename geometry::ring_type<GeometryOutput>::type
> collection;
typename geometry::ring_type<GeometryOutput>::type,
RobustPolicy
> collection(robust_policy);
dispatch::buffer_inserter
<
@@ -495,7 +498,7 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
//collection.map_turns(mapper);
collection.map_pieces<geometry::polygon_tag>(mapper); //, false, true);
collection.template map_pieces<geometry::polygon_tag>(mapper); //, false, true);
//collection.map_traverse(mapper);
#endif

View File

@@ -21,7 +21,6 @@
#include <boost/geometry/extensions/strategies/buffer_side.hpp>
#include <boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp>
#include <boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
@@ -46,14 +45,14 @@ class backtrack_for_buffer
public :
typedef detail::overlay::backtrack_state state_type;
template <typename Operation, typename Rings, typename Turns, typename Geometry, typename RescalePolicy>
template <typename Operation, typename Rings, typename Turns, typename Geometry, typename RobustPolicy>
static inline void apply(std::size_t size_at_start,
Rings& rings, typename boost::range_value<Rings>::type& ring,
Turns& turns, Operation& operation,
std::string const& /*reason*/,
Geometry const& ,
Geometry const& ,
RescalePolicy const& ,
RobustPolicy const& ,
state_type& state
)
{
@@ -88,8 +87,6 @@ struct turn_assign_for_buffer
template <typename Point1, typename Point2, typename Turn, typename IntersectionInfo, typename DirInfo>
static inline void apply(Turn& turn, Point1 const& p1, Point2 const& p2, IntersectionInfo const& intersection_info, DirInfo const& dir_info)
{
detail::overlay::calculate_distance_policy::apply(turn, p1, p2,
intersection_info, dir_info);
if (dir_info.opposite && intersection_info.count == 2)
{
turn.is_opposite = true;
@@ -99,8 +96,9 @@ struct turn_assign_for_buffer
// Should follow traversal-turn-concept (enrichment, visit structure)
// and adds index in piece vector to find it back
template <typename Point>
struct buffer_turn_operation : public detail::overlay::traversal_turn_operation<Point>
template <typename Point, typename SegmentRatio>
struct buffer_turn_operation
: public detail::overlay::traversal_turn_operation<Point, SegmentRatio>
{
int piece_index;
bool include_in_occupation_map;
@@ -112,8 +110,14 @@ struct buffer_turn_operation : public detail::overlay::traversal_turn_operation<
};
// Version for buffer including type of location, is_opposite, and helper variables
template <typename Point>
struct buffer_turn_info : public detail::overlay::turn_info<Point, buffer_turn_operation<Point> >
template <typename Point, typename SegmentRatio>
struct buffer_turn_info
: public detail::overlay::turn_info
<
Point,
SegmentRatio,
buffer_turn_operation<Point, SegmentRatio>
>
{
bool is_opposite;

View File

@@ -30,7 +30,6 @@
#include <boost/geometry/algorithms/detail/overlay/add_rings.hpp>
#include <boost/geometry/algorithms/detail/overlay/assign_parents.hpp>
#include <boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp>
#include <boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp>
#include <boost/geometry/algorithms/detail/overlay/enrichment_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp>
@@ -104,61 +103,7 @@ struct check_original<point_tag>
};
template <typename P>
class relaxed_side
{
public :
// Template member function, because it is not always trivial
// or convenient to explicitly mention the typenames in the
// strategy-struct itself.
// Types can be all three different. Therefore it is
// not implemented (anymore) as "segment"
static inline int apply(P const& p1, P const& p2, P const& p)
{
typedef typename coordinate_type<P>::type coordinate_type;
coordinate_type const x = get<0>(p);
coordinate_type const y = get<1>(p);
coordinate_type const sx1 = get<0>(p1);
coordinate_type const sy1 = get<1>(p1);
coordinate_type const sx2 = get<0>(p2);
coordinate_type const sy2 = get<1>(p2);
// Promote float->double, small int->int
typedef typename geometry::select_most_precise
<
coordinate_type,
double
>::type promoted_type;
promoted_type const dx = sx2 - sx1;
promoted_type const dy = sy2 - sy1;
promoted_type const dpx = x - sx1;
promoted_type const dpy = y - sy1;
promoted_type const s
= geometry::detail::determinant<promoted_type>
(
dx, dy,
dpx, dpy
);
promoted_type const zero = promoted_type();
promoted_type const relaxed_epsilon = std::numeric_limits<double>::epsilon() * 5.0;
return math::abs(s) < relaxed_epsilon ? 0
: s > zero ? 1
: -1;
}
};
template <typename Ring>
template <typename Ring, typename RobustPolicy>
struct buffered_piece_collection
{
typedef typename geometry::point_type<Ring>::type point_type;
@@ -193,20 +138,42 @@ struct buffered_piece_collection
std::map<std::pair<segment_identifier, segment_identifier>, std::set<int> > m_turn_indices_per_segment_pair;
typedef typename geometry::rescale_policy_type
<
typename geometry::point_type<Ring>::type
>::type rescale_policy_type;
typedef typename geometry::segment_ratio_type
<
point_type,
RobustPolicy
>::type segment_ratio_type;
typedef buffer_turn_info
<
point_type,
segment_ratio_type
> buffer_turn_info_type;
typedef buffer_turn_operation
<
point_type,
segment_ratio_type
> buffer_turn_operation_type;
typedef std::vector<buffer_turn_info_type> turn_vector_type;
typedef std::vector<buffer_turn_info<point_type> > turn_vector_type;
typedef detail::overlay::get_turn_info
<
turn_assign_for_buffer
> turn_policy;
turn_vector_type m_turns;
geometry::detail::no_rescale_policy m_rescale_policy;
// To check clustered locations we keep track of segments being opposite somewhere
std::set<segment_identifier> m_in_opposite_segments;
RobustPolicy const& m_rescale_policy;
struct buffer_occupation_info : public occupation_info<angle_info<point_type, coordinate_type> >
{
std::set<segment_identifier> seg_ids;
@@ -216,10 +183,9 @@ struct buffered_piece_collection
typedef occupation_map<point_type, buffer_occupation_info> occupation_map_type;
occupation_map_type m_occupation_map;
struct redundant_turn
{
inline bool operator()(buffer_turn_info<point_type> const& turn) const
inline bool operator()(buffer_turn_info_type const& turn) const
{
// Erase discarded turns (location not OK) and the turns
// only used to detect oppositeness.
@@ -228,6 +194,10 @@ struct buffered_piece_collection
}
};
buffered_piece_collection(RobustPolicy const& robust_policy)
: m_rescale_policy(robust_policy)
{}
inline bool is_neighbor(piece const& piece1, piece const& piece2) const
{
@@ -294,7 +264,7 @@ struct buffered_piece_collection
iterator it2_first = boost::begin(ring2) + seg_id2.segment_index;
iterator it2_last = boost::begin(ring2) + piece2.last_segment_index;
buffer_turn_info<point_type> the_model;
buffer_turn_info_type the_model;
the_model.operations[0].piece_index = piece1.index;
the_model.operations[0].seg_id = piece1.first_seg_id;
@@ -340,32 +310,7 @@ struct buffered_piece_collection
}
}
inline segment_relation_code get_segment_relation(point_type const& point,
segment_identifier const& seg_id) const
{
typedef typename boost::range_iterator<std::vector<point_type> const>::type iterator_type;
iterator_type it = boost::begin(offsetted_rings[seg_id.multi_index]) + seg_id.segment_index;
iterator_type prev = it++;
int side = side_strategy::apply(point, *prev, *it);
if (side == 0)
{
if (geometry::equals(point, *prev))
{
return segment_relation_on_left;
}
else if (geometry::equals(point, *it))
{
return segment_relation_on_right;
}
else if (collinear_point_on_segment(point, *prev, *it))
{
return segment_relation_within;
}
}
return segment_relation_disjoint;
}
inline void add_angles(int turn_index, int operation_index, point_type const& point, buffer_turn_operation<point_type> const& operation)
inline void add_angles(int turn_index, int operation_index, point_type const& point, buffer_turn_operation_type const& operation)
{
point_type mapped_point;
buffer_occupation_info& info = m_occupation_map.find_or_insert(point, mapped_point);
@@ -384,7 +329,7 @@ struct buffered_piece_collection
{
m_occupation_map.insert_turn_index(turn_index);
buffer_turn_info<point_type> const& turn = m_turns[turn_index];
buffer_turn_info_type const& turn = m_turns[turn_index];
//std::cout << "Adding point " << turn_index << " " << geometry::wkt(turn.point) << std::endl;
@@ -395,7 +340,7 @@ struct buffered_piece_collection
inline void classify_turn(buffer_turn_info<point_type>& turn, piece const& pc) const
inline void classify_turn(buffer_turn_info_type& turn, piece const& pc) const
{
if (pc.type == buffered_flat_end)
{
@@ -440,10 +385,10 @@ struct buffered_piece_collection
{
// The piece is a full (pseudo) circle. There are no helper segments. We only check if it is the turn is inside the generated circle,
// or on the border.
int const side_wrt_circle = side_on_convex_range< /*relaxed_side<point_type> */ side_strategy >(turn.point,
int const side_wrt_circle = side_on_convex_range<side_strategy>(turn.point,
boost::begin(ring) + seg_id.segment_index,
boost::begin(ring) + pc.last_segment_index,
seg_id, on_segment_seg_id);
seg_id, on_segment_seg_id, m_rescale_policy);
switch (side_wrt_circle)
{
case 0 : turn.count_on_offsetted++; break;
@@ -452,17 +397,17 @@ struct buffered_piece_collection
return;
}
int side_helper = side_on_convex_range<side_strategy>(turn.point, pc.helper_segments);
int side_helper = side_on_convex_range<side_strategy>(turn.point, pc.helper_segments, m_rescale_policy);
if (side_helper == 1)
{
// Left or outside
return;
}
int const side_offsetted = side_on_convex_range< /*relaxed_side<point_type> */ side_strategy >(turn.point,
int const side_offsetted = side_on_convex_range<side_strategy>(turn.point,
boost::begin(ring) + seg_id.segment_index,
boost::begin(ring) + pc.last_segment_index,
seg_id, on_segment_seg_id);
seg_id, on_segment_seg_id, m_rescale_policy);
if (side_offsetted == 1)
{
return;
@@ -479,8 +424,8 @@ struct buffered_piece_collection
}
if (side_helper == 0)
{
if (geometry::equals(turn.point, pc.helper_segments.back())
|| geometry::equals(turn.point, pc.helper_segments.front()))
if (detail::overlay::points_equal_or_close(turn.point, pc.helper_segments.back(), m_rescale_policy)
|| detail::overlay::points_equal_or_close(turn.point, pc.helper_segments.front(), m_rescale_policy))
{
turn.count_on_corner++;
}
@@ -692,17 +637,6 @@ struct buffered_piece_collection
}
}
#define BOOST_GEOMETRY_DEBUG_BUFFER_SITUATION_MAP
#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_SITUATION_MAP
inline int get_side(point_type const& point, Ring const& ring, int segment_index)
{
typedef typename boost::range_iterator<Ring const> iterator_type;
iterator_type it = boost::begin(ring) + segment_index;
iterator_type prev = it++;
return side_strategy::apply(point, *prev, *it);
}
#endif
template <typename Iterator>
static inline point_type const& select_for_side(Iterator first, Iterator second, int index)
{
@@ -723,53 +657,32 @@ struct buffered_piece_collection
iterator_type prev1 = it1++;
iterator_type prev2 = it2++;
int code1 = side_strategy::apply(select_for_side(prev1, it1, which), *prev2, *it2);
int code2 = side_strategy::apply(select_for_side(prev2, it2, which), *prev1, *it1);
typedef typename geometry::robust_point_type
<
point_type,
RobustPolicy
>::type robust_point_type;
robust_point_type p1_rob, p2_rob, prev1_rob, prev2_rob, cur1_rob, cur2_rob;
geometry::recalculate(p1_rob, select_for_side(prev1, it1, which), m_rescale_policy);
geometry::recalculate(p2_rob, select_for_side(prev2, it2, which), m_rescale_policy);
geometry::recalculate(prev1_rob, *prev1, m_rescale_policy);
geometry::recalculate(prev2_rob, *prev2, m_rescale_policy);
geometry::recalculate(cur1_rob, *it1, m_rescale_policy);
geometry::recalculate(cur2_rob, *it2, m_rescale_policy);
int const code1 = side_strategy::apply(p1_rob, prev2_rob, cur2_rob);
int const code2 = side_strategy::apply(p2_rob, prev1_rob, cur1_rob);
if (code1 == 1 && code2 == -1) return 1;
if (code1 == -1 && code2 == 1) return -1;
// ROBUSTNESS: in near collinear cases one might be zero, the other non-zero.
// This happens several times.
if (code1 != 0) return code1;
if (code2 != 0) return -code2;
// // Check if the other side gives some more info
// // (I've never seen this is the case though it might be so, if they are much longer.
//int code1f = side_strategy::apply(*prev1, *prev2, *it2);
//int code2f = side_strategy::apply(*prev2, *prev1, *it1);
// if (code1f != 0 || code2f != 0)
// {
// std::cout << "From: " << code1f << " " << code2f << std::endl;
// if (code1f != 0) return -code1f;
// if (code2f != 0) return code2f;
// }
// Collinear?
#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_SITUATION_MAP
//std::cout << "Collinear: " << code1 << " " << code2 << std::endl;
#endif
return 0;
}
inline void debug_segment(segment_identifier id)
{
typedef typename boost::range_iterator<buffered_ring<Ring> const>::type iterator;
buffered_ring<Ring> const& ring = offsetted_rings[id.multi_index];
iterator it = boost::begin(ring) + id.segment_index;
iterator prev = it++;
geometry::model::referring_segment<point_type const&> segment(*prev, *it);
//std::cout << geometry::wkt(*prev) << " " << geometry::wkt(*it) << std::endl;
}
struct cluster_info
{
inline cluster_info(int i, point_type p, buffer_turn_operation<point_type> op)
inline cluster_info(int i, point_type p, buffer_turn_operation_type op)
: turn_index(i)
, point(p)
, operation(op)
@@ -781,7 +694,7 @@ struct buffered_piece_collection
int turn_index;
point_type point;
buffer_turn_operation<point_type> operation;
buffer_turn_operation_type operation;
};
struct clustered_info
@@ -791,14 +704,6 @@ struct buffered_piece_collection
std::vector<cluster_info> intersecting_segments;
};
#ifdef OLD
struct situation_info
{
std::set<int> turn_indices;
std::set<segment_identifier> seg_ids;
};
#endif
static inline bool add_mutual_intersection(clustered_info const& cluster, segment_identifier const& seg_id)
{
bool result = false;
@@ -838,19 +743,12 @@ struct buffered_piece_collection
return true;
}
if (geometry::equals(a.point, b.point))
if (detail::overlay::points_equal_or_close(a.point, b.point, m_rescale_policy))
{
std::cout << "=";
return true;
}
relaxed_less<point_type> comparator;
if (comparator.equals(a.point, b.point))
{
std::cout << "*";
return true;
}
return false;
}
@@ -891,7 +789,7 @@ struct buffered_piece_collection
for (typename boost::range_iterator<turn_vector_type>::type it =
boost::begin(m_turns); it != boost::end(m_turns); ++it, ++index)
{
buffer_turn_info<point_type> const& turn = *it;
buffer_turn_info_type const& turn = *it;
// Take care with all the indices
map[turn.operations[0].seg_id].piece_index = turn.operations[0].piece_index;
@@ -924,7 +822,7 @@ struct buffered_piece_collection
for (typename boost::range_iterator<turn_vector_type>::type it =
boost::begin(m_turns); it != boost::end(m_turns); ++it, ++index)
{
buffer_turn_info<point_type>& turn = *it;
buffer_turn_info_type& turn = *it;
//std::cout << "Referring to point " << geometry::wkt(turn.point) << std::endl;
if (m_in_opposite_segments.count(turn.operations[0].seg_id) > 0
|| m_in_opposite_segments.count(turn.operations[1].seg_id) > 0)
@@ -941,7 +839,7 @@ struct buffered_piece_collection
for (typename boost::range_iterator<turn_vector_type>::type it =
boost::begin(m_turns); it != boost::end(m_turns); ++it, ++index)
{
buffer_turn_info<point_type>& turn = *it;
buffer_turn_info_type& turn = *it;
if (m_in_opposite_segments.count(turn.operations[0].seg_id) == 0
&& m_in_opposite_segments.count(turn.operations[1].seg_id) == 0)
{

View File

@@ -26,18 +26,24 @@ namespace detail { namespace buffer
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
template <typename Ring>
template <typename Ring, typename RobustPolicy>
struct buffered_piece_collection_with_mapper
: public buffered_piece_collection<Ring>
: public buffered_piece_collection<Ring, RobustPolicy>
{
typedef buffered_piece_collection<Ring, RobustPolicy> super_type;
buffered_piece_collection_with_mapper(RobustPolicy const& robust_policy)
: super_type(robust_policy)
{}
template <typename Mapper>
inline void map_opposite_locations(Mapper& mapper)
{
typedef typename super_type::occupation_map_type occupation_map_type;
for (typename boost::range_iterator<typename occupation_map_type::map_type>::type it =
boost::begin(m_occupation_map.map);
it != boost::end(m_occupation_map.map); ++it)
boost::begin(this->m_occupation_map.map);
it != boost::end(this->m_occupation_map.map); ++it)
{
mapper.map(it->first, it->second.occupied() ? "fill:rgb(255,0,255);" : "fill:rgb(0,192,0);", 7);
@@ -55,6 +61,8 @@ struct buffered_piece_collection_with_mapper
bool const incoming = it->second.angles[i].incoming;
segment_identifier seg_id = it->second.angles[i].seg_id;
typedef typename super_type::point_type point_type;
geometry::model::linestring<point_type> line;
point_type p1, p2;
geometry::set<0>(p1, geometry::get<0>(it->first) + cos(angle) * 0.1);
@@ -90,13 +98,16 @@ struct buffered_piece_collection_with_mapper
template <typename Mapper>
inline void map_turns(Mapper& mapper)
{
typedef typename super_type::point_type point_type;
typedef typename super_type::turn_vector_type turn_vector_type;
typedef typename geometry::coordinate_type<point_type>::type coordinate_type;
std::map<std::pair<coordinate_type, coordinate_type>, int> offsets;
int index = 0;
for (typename boost::range_iterator<turn_vector_type>::type it =
boost::begin(m_turns); it != boost::end(m_turns); ++it)
boost::begin(this->m_turns); it != boost::end(this->m_turns); ++it)
{
if (! it->opposite())
{
@@ -152,8 +163,9 @@ struct buffered_piece_collection_with_mapper
template <typename Tag, typename Mapper>
inline void map_pieces(Mapper& mapper, bool pieces = true, bool indices = true)
{
for(typename piece_vector::const_iterator it = boost::begin(m_pieces);
it != boost::end(m_pieces);
typedef typename super_type::piece_vector piece_vector;
for(typename piece_vector::const_iterator it = boost::begin(this->m_pieces);
it != boost::end(this->m_pieces);
++it)
{
Ring corner;
@@ -162,7 +174,7 @@ struct buffered_piece_collection_with_mapper
if (seg_id.segment_index >= 0)
{
buffered_ring<Ring> const& ring = offsetted_rings[seg_id.multi_index];
buffered_ring<Ring> const& ring = this->offsetted_rings[seg_id.multi_index];
std::copy(boost::begin(ring) + seg_id.segment_index,
boost::begin(ring) + it->last_segment_index,
@@ -207,6 +219,8 @@ struct buffered_piece_collection_with_mapper
{
// Put starting piece_index / segment_index in centroid
typedef typename super_type::point_type point_type;
point_type centroid;
if (corner.size() > 3)
{
@@ -227,8 +241,10 @@ struct buffered_piece_collection_with_mapper
template <typename Mapper>
inline void map_offsetted_points(Mapper& mapper)
{
for(typename buffered_ring_collection<buffered_ring<Ring> >::const_iterator oit = boost::begin(offsetted_rings);
oit != boost::end(offsetted_rings);
typedef typename super_type::point_type point_type;
for(typename buffered_ring_collection<buffered_ring<Ring> >::const_iterator oit = boost::begin(this->offsetted_rings);
oit != boost::end(this->offsetted_rings);
++oit)
{
int index = 0;
@@ -245,8 +261,8 @@ struct buffered_piece_collection_with_mapper
template <typename Mapper>
inline void map_traverse(Mapper& mapper)
{
for(typename buffered_ring_collection<Ring>::const_iterator it = boost::begin(traversed_rings);
it != boost::end(traversed_rings);
for(typename buffered_ring_collection<Ring>::const_iterator it = boost::begin(this->traversed_rings);
it != boost::end(this->traversed_rings);
++it)
{
mapper.map(*it, "opacity:0.4;fill:none;stroke:rgb(0,255,0);stroke-width:8");
@@ -256,8 +272,8 @@ struct buffered_piece_collection_with_mapper
template <typename Mapper>
inline void map_offsetted(Mapper& mapper)
{
for(typename buffered_ring_collection<buffered_ring<Ring> >::const_iterator it = boost::begin(offsetted_rings);
it != boost::end(offsetted_rings);
for(typename buffered_ring_collection<buffered_ring<Ring> >::const_iterator it = boost::begin(this->offsetted_rings);
it != boost::end(this->offsetted_rings);
++it)
{
if (it->discarded())

View File

@@ -179,33 +179,15 @@ struct copy_segment_point
{};
template
<
typename MultiRing,
bool Reverse,
typename SegmentIdentifier,
typename RangeOut
>
template<bool Reverse>
struct copy_segments
<
detail::buffer::buffered_ring_collection_tag,
MultiRing,
Reverse,
SegmentIdentifier,
RangeOut
Reverse
>
: detail::copy_segments::copy_segments_multi
<
MultiRing,
SegmentIdentifier,
RangeOut,
detail::copy_segments::copy_segments_ring
<
typename boost::range_value<MultiRing>::type,
Reverse,
SegmentIdentifier,
RangeOut
>
detail::copy_segments::copy_segments_ring<Reverse>
>
{};

View File

@@ -52,9 +52,11 @@ inline bool collinear_point_on_segment(P0 const& subject, P1 const& p1, P2 const
}
template <typename SideStrategy, typename Point, typename Range>
inline int side_on_convex_range(Point const& subject, Range const& range)
template <typename SideStrategy, typename Point, typename Range, typename RobustPolicy>
inline int side_on_convex_range(Point const& subject,
Range const& range, RobustPolicy const& robust_policy)
{
// TODO merge this implementation with next function with same name
if (boost::empty(range))
{
return 1;
@@ -62,17 +64,26 @@ inline int side_on_convex_range(Point const& subject, Range const& range)
bool has_collinear = false;
typedef typename boost::range_iterator
<
Range const
>::type iterator_type;
typedef typename geometry::robust_point_type
<
Point,
RobustPolicy
>::type robust_point_type;
typedef typename boost::range_iterator<Range const>::type iterator_type;
iterator_type it = boost::begin(range);
for (iterator_type prev = it++;
it != boost::end(range);
prev = it++)
robust_point_type subject_rob, previous_rob;
geometry::recalculate(subject_rob, subject, robust_policy);
geometry::recalculate(previous_rob, *it, robust_policy);
for (++it; it != boost::end(range); ++it)
{
int const side = SideStrategy::apply(subject, *prev, *it);
robust_point_type current_rob;
geometry::recalculate(current_rob, *it, robust_policy);
int const side = SideStrategy::apply(subject_rob, previous_rob, current_rob);
switch(side)
{
case 1 :
@@ -81,28 +92,50 @@ inline int side_on_convex_range(Point const& subject, Range const& range)
// Check if it is really on the segment.
// If not, it is either on the left (because polygon is convex)
// or it is still on one of the other segments (if segments are collinear)
if (collinear_point_on_segment(subject, *prev, *it))
if (collinear_point_on_segment(subject_rob, previous_rob, current_rob))
{
return 0;
}
has_collinear = true;
break;
}
previous_rob = current_rob;
}
return has_collinear ? 1 : -1;
}
template <typename SideStrategy, typename Point, typename Iterator>
template <typename SideStrategy, typename Point, typename Iterator, typename RobustPolicy>
static inline int side_on_convex_range(Point const& subject,
Iterator first, Iterator last,
/* by value: */ segment_identifier seg_id,
segment_identifier& on_segment_seg_id)
segment_identifier& on_segment_seg_id,
RobustPolicy const& robust_policy)
{
typedef typename geometry::robust_point_type
<
Point,
RobustPolicy
>::type robust_point_type;
bool has_collinear = false;
Iterator it = first;
for (Iterator prev = it++; it != last; prev = it++, seg_id.segment_index++)
if (it == last)
{
int side = SideStrategy::apply(subject, *prev, *it);
return 1;
}
robust_point_type subject_rob, previous_rob;
geometry::recalculate(subject_rob, subject, robust_policy);
geometry::recalculate(previous_rob, *it, robust_policy);
for (++it; it != last; ++it, seg_id.segment_index++)
{
robust_point_type current_rob;
geometry::recalculate(current_rob, *it, robust_policy);
int const side = SideStrategy::apply(subject_rob, previous_rob, current_rob);
switch(side)
{
case 1 :
@@ -111,7 +144,7 @@ static inline int side_on_convex_range(Point const& subject,
// Check if it is REALLY on the segment.
// If not, it is either on the left (because polygon is convex)
// or it is still on one of the other segments (if segments are collinear)
if (collinear_point_on_segment(subject, *prev, *it))
if (collinear_point_on_segment(subject_rob, previous_rob, current_rob))
{
on_segment_seg_id = seg_id;
return 0;
@@ -119,6 +152,7 @@ static inline int side_on_convex_range(Point const& subject,
has_collinear = true;
break;
}
previous_rob = current_rob;
}
return has_collinear ? 1 : -1;
}

View File

@@ -21,7 +21,6 @@
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/enrichment_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp>
#include <boost/geometry/algorithms/detail/point_on_border.hpp>
@@ -110,7 +109,7 @@ struct dissolve_ring_or_polygon
detail::dissolve::no_interrupt_policy policy;
geometry::self_turns
<
detail::overlay::calculate_distance_policy
detail::overlay::assign_null_policy
>(geometry, rescale_policy, turns, policy);
// The dissolve process is not necessary if there are no turns at all

View File

@@ -10,7 +10,9 @@
#ifndef BOOST_GEOMETRY_ITERATORS_CONCATENATE_ITERATOR_HPP
#define BOOST_GEOMETRY_ITERATORS_CONCATENATE_ITERATOR_HPP
#include <boost/type_traits.hpp>
#include <boost/assert.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/iterator.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include <boost/iterator/iterator_categories.hpp>
@@ -57,18 +59,26 @@ public:
(concatenate_iterator<OtherIt1, OtherIt2, OtherValue> const& other)
: m_it1(other.m_it1), m_end1(other.m_end1), m_it2(other.m_it2)
{
BOOST_STATIC_ASSERT
( boost::is_convertible<OtherIt1, Iterator1>::value
&& boost::is_convertible<OtherIt2, Iterator2>::value );
static const bool are_conv
= boost::is_convertible<OtherIt1, Iterator1>::value
&& boost::is_convertible<OtherIt2, Iterator2>::value;
BOOST_MPL_ASSERT_MSG((are_conv),
NOT_CONVERTIBLE,
(types<OtherIt1, OtherIt2>));
}
template <typename OtherIt1, typename OtherIt2, typename OtherValue>
concatenate_iterator
operator=(concatenate_iterator<OtherIt1, OtherIt2, OtherValue> const& other)
{
BOOST_STATIC_ASSERT
( boost::is_convertible<OtherIt1, Iterator1>::value
&& boost::is_convertible<OtherIt2, Iterator2>::value );
static const bool are_conv
= boost::is_convertible<OtherIt1, Iterator1>::value
&& boost::is_convertible<OtherIt2, Iterator2>::value;
BOOST_MPL_ASSERT_MSG((are_conv),
NOT_CONVERTIBLE,
(types<OtherIt1, OtherIt2>));
m_it1 = other.m_it1;
m_end1 = other.m_end1;

View File

@@ -10,7 +10,9 @@
#ifndef BOOST_GEOMETRY_ITERATORS_FLATTEN_ITERATOR_HPP
#define BOOST_GEOMETRY_ITERATORS_FLATTEN_ITERATOR_HPP
#include <boost/type_traits.hpp>
#include <boost/assert.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/iterator.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include <boost/iterator/iterator_categories.hpp>
@@ -84,15 +86,19 @@ public:
m_outer_end(other.m_outer_end),
m_inner_it(other.m_inner_it)
{
BOOST_STATIC_ASSERT( boost::is_convertible
<
OtherOuterIterator, OuterIterator
>::value
&& boost::is_convertible
<
OtherInnerIterator, InnerIterator
>::value );
static const bool are_conv
= boost::is_convertible
<
OtherOuterIterator, OuterIterator
>::value
&& boost::is_convertible
<
OtherInnerIterator, InnerIterator
>::value;
BOOST_MPL_ASSERT_MSG((are_conv),
NOT_CONVERTIBLE,
(types<OtherOuterIterator, OtherInnerIterator>));
}
template
@@ -112,14 +118,19 @@ public:
OtherAccessInnerEnd
> const& other)
{
BOOST_STATIC_ASSERT( boost::is_convertible
<
OtherOuterIterator, OuterIterator
>::value
&& boost::is_convertible
<
OtherInnerIterator, InnerIterator
>::value );
static const bool are_conv
= boost::is_convertible
<
OtherOuterIterator, OuterIterator
>::value
&& boost::is_convertible
<
OtherInnerIterator, InnerIterator
>::value;
BOOST_MPL_ASSERT_MSG((are_conv),
NOT_CONVERTIBLE,
(types<OtherOuterIterator, OtherInnerIterator>));
m_outer_it = other.m_outer_it;
m_outer_end = other.m_outer_end;
@@ -184,17 +195,17 @@ private:
OtherAccessInnerEnd
> const& other) const
{
if ( this->m_outer_it != other.m_outer_it )
if ( m_outer_it != other.m_outer_it )
{
return false;
}
if ( this->m_outer_it == m_outer_end )
if ( m_outer_it == m_outer_end )
{
return true;
}
return this->m_inner_it == other.m_inner_it;
return m_inner_it == other.m_inner_it;
}
inline void increment()

View File

@@ -10,6 +10,15 @@
#ifndef BOOST_GEOMETRY_ITERATORS_POINT_ITERATOR_HPP
#define BOOST_GEOMETRY_ITERATORS_POINT_ITERATOR_HPP
#include <boost/mpl/assert.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/range.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/multi/core/tags.hpp>
#include <boost/geometry/iterators/dispatch/point_iterator.hpp>
#include <boost/geometry/iterators/point_iterator_type.hpp>
@@ -234,12 +243,15 @@ public:
point_iterator(point_iterator<OtherGeometry> const& other)
: base(*other.base_ptr())
{
BOOST_STATIC_ASSERT
( boost::is_convertible
<
typename dispatch::point_iterator_type<OtherGeometry>::type,
typename dispatch::point_iterator_type<Geometry>::type
>::value );
static const bool is_conv
= boost::is_convertible<
typename dispatch::point_iterator_type<OtherGeometry>::type,
typename dispatch::point_iterator_type<Geometry>::type
>::value;
BOOST_MPL_ASSERT_MSG((is_conv),
NOT_CONVERTIBLE,
(point_iterator<OtherGeometry>));
}
};

View File

@@ -14,9 +14,14 @@
#include <boost/geometry/iterators/dispatch/point_iterator.hpp>
#include <boost/range.hpp>
#include <boost/type_traits.hpp>
#include <boost/mpl/if.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/ring_type.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/multi/core/tags.hpp>
#include <boost/geometry/iterators/flatten_iterator.hpp>
#include <boost/geometry/iterators/concatenate_iterator.hpp>
@@ -107,12 +112,12 @@ private:
typedef typename detail_dispatch::point_iterator_inner_range_type
<
Polygon
>::type InnerRange;
>::type inner_range;
public:
typedef concatenate_iterator
<
typename boost::range_iterator<InnerRange>::type,
typename boost::range_iterator<inner_range>::type,
flatten_iterator
<
typename boost::range_iterator
@@ -121,14 +126,14 @@ public:
>::type,
typename dispatch::point_iterator_type
<
InnerRange
inner_range
>::type,
typename detail_dispatch::point_iterator_value_type
<
Polygon
>::type,
dispatch::points_begin<InnerRange>,
dispatch::points_end<InnerRange>
dispatch::points_begin<inner_range>,
dispatch::points_end<inner_range>
>,
typename detail_dispatch::point_iterator_value_type<Polygon>::type
> type;
@@ -149,19 +154,19 @@ private:
typedef typename detail_dispatch::point_iterator_inner_range_type
<
MultiLinestring
>::type InnerRange;
>::type inner_range;
public:
typedef flatten_iterator
<
typename boost::range_iterator<MultiLinestring>::type,
typename dispatch::point_iterator_type<InnerRange>::type,
typename dispatch::point_iterator_type<inner_range>::type,
typename detail_dispatch::point_iterator_value_type
<
MultiLinestring
>::type,
dispatch::points_begin<InnerRange>,
dispatch::points_end<InnerRange>
dispatch::points_begin<inner_range>,
dispatch::points_end<inner_range>
> type;
};
@@ -173,19 +178,19 @@ private:
typedef typename detail_dispatch::point_iterator_inner_range_type
<
MultiPolygon
>::type InnerRange;
>::type inner_range;
public:
typedef flatten_iterator
<
typename boost::range_iterator<MultiPolygon>::type,
typename dispatch::point_iterator_type<InnerRange>::type,
typename dispatch::point_iterator_type<inner_range>::type,
typename detail_dispatch::point_iterator_value_type
<
MultiPolygon
>::type,
dispatch::points_begin<InnerRange>,
dispatch::points_end<InnerRange>
dispatch::points_begin<inner_range>,
dispatch::points_end<inner_range>
> type;
};

View File

@@ -28,17 +28,19 @@ namespace detail { namespace copy_segments
{
template
<
typename MultiGeometry,
typename SegmentIdentifier,
typename RangeOut,
typename Policy
>
template<typename Policy>
struct copy_segments_multi
{
template
<
typename MultiGeometry,
typename SegmentIdentifier,
typename RobustPolicy,
typename RangeOut
>
static inline void apply(MultiGeometry const& multi_geometry,
SegmentIdentifier const& seg_id, int to_index,
RobustPolicy const& robust_policy,
RangeOut& current_output)
{
@@ -50,7 +52,9 @@ struct copy_segments_multi
// Call the single-version
Policy::apply(multi_geometry[seg_id.multi_index],
seg_id, to_index, current_output);
seg_id, to_index,
robust_policy,
current_output);
}
};
@@ -64,33 +68,11 @@ namespace dispatch
{
template
<
typename MultiPolygon,
bool Reverse,
typename SegmentIdentifier,
typename RangeOut
>
struct copy_segments
<
multi_polygon_tag,
MultiPolygon,
Reverse,
SegmentIdentifier,
RangeOut
>
template<bool Reverse>
struct copy_segments<multi_polygon_tag, Reverse>
: detail::copy_segments::copy_segments_multi
<
MultiPolygon,
SegmentIdentifier,
RangeOut,
detail::copy_segments::copy_segments_polygon
<
typename boost::range_value<MultiPolygon>::type,
Reverse,
SegmentIdentifier,
RangeOut
>
detail::copy_segments::copy_segments_polygon<Reverse>
>
{};

View File

@@ -39,11 +39,11 @@ template
>
struct get_turns_multi_polygon_cs
{
template <typename RescalePolicy, typename Turns, typename InterruptPolicy>
template <typename RobustPolicy, typename Turns, typename InterruptPolicy>
static inline void apply(
int source_id1, Multi const& multi,
int source_id2, Box const& box,
RescalePolicy const& rescale_policy,
RobustPolicy const& robust_policy,
Turns& turns, InterruptPolicy& interrupt_policy)
{
typedef typename boost::range_iterator
@@ -63,7 +63,7 @@ struct get_turns_multi_polygon_cs
Reverse, ReverseBox,
TurnPolicy
>::apply(source_id1, *it, source_id2, box,
rescale_policy, turns, interrupt_policy, i);
robust_policy, turns, interrupt_policy, i);
}
}
};

View File

@@ -43,11 +43,11 @@ struct sectionalize_multi
template
<
typename MultiGeometry,
typename RescalePolicy,
typename RobustPolicy,
typename Sections
>
static inline void apply(MultiGeometry const& multi,
RescalePolicy const& rescale_policy,
RobustPolicy const& robust_policy,
bool make_rescaled_boxes,
Sections& sections, ring_identifier ring_id, std::size_t max_count)
{
@@ -57,7 +57,7 @@ struct sectionalize_multi
it != boost::end(multi);
++it, ++ring_id.multi_index)
{
Policy::apply(*it, rescale_policy, make_rescaled_boxes, sections, ring_id, max_count);
Policy::apply(*it, robust_policy, make_rescaled_boxes, sections, ring_id, max_count);
}
}
};

View File

@@ -45,10 +45,13 @@ struct intersection_multi_linestring_multi_linestring_point
template
<
typename MultiLinestring1, typename MultiLinestring2,
typename RobustPolicy,
typename OutputIterator, typename Strategy
>
static inline OutputIterator apply(MultiLinestring1 const& ml1,
MultiLinestring2 const& ml2, OutputIterator out,
MultiLinestring2 const& ml2,
RobustPolicy const& robust_policy,
OutputIterator out,
Strategy const& strategy)
{
// Note, this loop is quadratic w.r.t. number of linestrings per input.
@@ -68,7 +71,7 @@ struct intersection_multi_linestring_multi_linestring_point
++it2)
{
out = intersection_linestring_linestring_point<PointOut>
::apply(*it1, *it2, out, strategy);
::apply(*it1, *it2, robust_policy, out, strategy);
}
}
@@ -83,10 +86,13 @@ struct intersection_linestring_multi_linestring_point
template
<
typename Linestring, typename MultiLinestring,
typename RobustPolicy,
typename OutputIterator, typename Strategy
>
static inline OutputIterator apply(Linestring const& linestring,
MultiLinestring const& ml, OutputIterator out,
MultiLinestring const& ml,
RobustPolicy const& robust_policy,
OutputIterator out,
Strategy const& strategy)
{
for (typename boost::range_iterator
@@ -97,7 +103,7 @@ struct intersection_linestring_multi_linestring_point
++it)
{
out = intersection_linestring_linestring_point<PointOut>
::apply(linestring, *it, out, strategy);
::apply(linestring, *it, robust_policy, out, strategy);
}
return out;
@@ -118,9 +124,11 @@ struct intersection_of_multi_linestring_with_areal
template
<
typename MultiLinestring, typename Areal,
typename RobustPolicy,
typename OutputIterator, typename Strategy
>
static inline OutputIterator apply(MultiLinestring const& ml, Areal const& areal,
RobustPolicy const& robust_policy,
OutputIterator out,
Strategy const& strategy)
{
@@ -134,7 +142,7 @@ struct intersection_of_multi_linestring_with_areal
out = intersection_of_linestring_with_areal
<
ReverseAreal, LineStringOut, OverlayType
>::apply(*it, areal, out, strategy);
>::apply(*it, areal, robust_policy, out, strategy);
}
return out;
@@ -154,16 +162,18 @@ struct intersection_of_areal_with_multi_linestring
template
<
typename Areal, typename MultiLinestring,
typename RobustPolicy,
typename OutputIterator, typename Strategy
>
static inline OutputIterator apply(Areal const& areal, MultiLinestring const& ml,
RobustPolicy const& robust_policy,
OutputIterator out,
Strategy const& strategy)
{
return intersection_of_multi_linestring_with_areal
<
ReverseAreal, LineStringOut, OverlayType
>::apply(ml, areal, out, strategy);
>::apply(ml, areal, robust_policy, out, strategy);
}
};
@@ -175,10 +185,13 @@ struct clip_multi_linestring
template
<
typename MultiLinestring, typename Box,
typename RobustPolicy,
typename OutputIterator, typename Strategy
>
static inline OutputIterator apply(MultiLinestring const& multi_linestring,
Box const& box, OutputIterator out, Strategy const& )
Box const& box,
RobustPolicy const& robust_policy,
OutputIterator out, Strategy const& )
{
typedef typename point_type<LinestringOut>::type point_type;
strategy::intersection::liang_barsky<Box, point_type> lb_strategy;
@@ -187,7 +200,7 @@ struct clip_multi_linestring
it != boost::end(multi_linestring); ++it)
{
out = detail::intersection::clip_range_with_box
<LinestringOut>(box, *it, out, lb_strategy);
<LinestringOut>(box, *it, robust_policy, out, lb_strategy);
}
return out;
}

View File

@@ -158,15 +158,6 @@ struct segments_de9im
false, false, false, true);
}
static inline return_type collinear_disjoint()
{
return de9im_segment(0,0,
-1, -1, 1,
-1, -1, 0,
1, 0, 2,
true);
}
};

View File

@@ -88,7 +88,8 @@ struct direction_type
// New information
side_info sides;
int arrival[2]; // 1=arrival, -1departure, 0=neutral; == how_a//how_b
// THIS IS EQUAL TO arrival_a, arrival_b - they probably can go now we have robust fractions
int arrival[2]; // 1=arrival, -1=departure, 0=neutral; == how_a//how_b
// About arrival[0] (== arrival of a2 w.r.t. b) for COLLINEAR cases
@@ -110,28 +111,19 @@ struct direction_type
};
template <typename S1, typename S2, typename CalculationType = void>
struct segments_direction
{
typedef direction_type return_type;
typedef S1 segment_type1;
typedef S2 segment_type2;
typedef typename select_calculation_type
<
S1, S2, CalculationType
>::type coordinate_type;
// Get the same type, but at least a double
typedef typename select_most_precise<coordinate_type, double>::type rtype;
template <typename R>
static inline return_type segments_intersect(side_info const& sides,
R const&,
coordinate_type const& , coordinate_type const& ,
coordinate_type const& , coordinate_type const& ,
S1 const& , S2 const& )
template
<
typename Segment1,
typename Segment2,
typename SegmentIntersectionInfo
>
static inline return_type segments_crosses(side_info const& sides,
SegmentIntersectionInfo const& ,
Segment1 const& , Segment2 const& )
{
bool const ra0 = sides.get<0,0>() == 0;
bool const ra1 = sides.get<0,1>() == 0;
@@ -171,63 +163,112 @@ struct segments_direction
;
}
static inline return_type collinear_touch(
coordinate_type const& ,
coordinate_type const& , int arrival_a, int arrival_b)
template <typename Ratio>
static inline int arrival_value(Ratio const& r_from, Ratio const& r_to)
{
// Though this is 'collinear', we handle it as To/From/Angle because it is the same.
// It only does NOT have a direction.
side_info sides;
//int const arrive = how == 'T' ? 1 : -1;
bool opposite = arrival_a == arrival_b;
return
! opposite
? return_type(sides, 'a', arrival_a, arrival_b)
: return_type(sides, arrival_a == 0 ? 't' : 'f', arrival_a, arrival_b, 0, 0, true);
// a1--------->a2
// b1----->b2
// a departs: -1
// a1--------->a2
// b1----->b2
// a arrives: 1
// a1--------->a2
// b1----->b2
// both arrive there -> r-to = 1/1, or 0/1 (on_segment)
// First check the TO (for arrival), then FROM (for departure)
return r_to.in_segment() ? 1
: r_to.on_segment() ? 0
: r_from.on_segment() ? -1
: -1
;
}
template <typename S>
static inline return_type collinear_interior_boundary_intersect(S const& , bool,
int arrival_a, int arrival_b, bool opposite)
template <typename Ratio>
static inline void analyze(Ratio const& r,
int& in_segment_count,
int& on_end_count,
int& outside_segment_count)
{
if (r.on_end())
{
on_end_count++;
}
else if (r.in_segment())
{
in_segment_count++;
}
else
{
outside_segment_count++;
}
}
template <typename Segment1, typename Segment2, typename Ratio>
static inline return_type segments_collinear(
Segment1 const& , Segment2 const&,
Ratio const& ra_from_wrt_b, Ratio const& ra_to_wrt_b,
Ratio const& rb_from_wrt_a, Ratio const& rb_to_wrt_a)
{
// If segments are opposite, the ratio of the FROM w.r.t. the other
// is larger than the ratio of the TO w.r.t. the other
bool const opposite = ra_to_wrt_b < ra_from_wrt_b;
return_type r('c', opposite);
r.arrival[0] = arrival_a;
r.arrival[1] = arrival_b;
// IMPORTANT: the order of conditions is different as in intersection_points.hpp
// We assign A in 0 and B in 1
r.arrival[0] = arrival_value(ra_from_wrt_b, ra_to_wrt_b);
r.arrival[1] = arrival_value(rb_from_wrt_a, rb_to_wrt_a);
// Analyse them
int a_in_segment_count = 0;
int a_on_end_count = 0;
int a_outside_segment_count = 0;
int b_in_segment_count = 0;
int b_on_end_count = 0;
int b_outside_segment_count = 0;
analyze(ra_from_wrt_b,
a_in_segment_count, a_on_end_count, a_outside_segment_count);
analyze(ra_to_wrt_b,
a_in_segment_count, a_on_end_count, a_outside_segment_count);
analyze(rb_from_wrt_a,
b_in_segment_count, b_on_end_count, b_outside_segment_count);
analyze(rb_to_wrt_a,
b_in_segment_count, b_on_end_count, b_outside_segment_count);
if (a_on_end_count == 1
&& b_on_end_count == 1
&& a_outside_segment_count == 1
&& b_outside_segment_count == 1)
{
// This is a collinear touch
// --------> A (or B)
// <---------- B (or A)
// We adapt the "how"
// TODO: how was to be refactored anyway,
if (! opposite)
{
r.how = 'a';
}
else
{
r.how = r.arrival[0] == 0 ? 't' : 'f';
}
}
else if (a_on_end_count == 2
&& b_on_end_count == 2)
{
r.how = 'e';
}
return r;
}
static inline return_type collinear_a_in_b(S1 const& , bool opposite)
{
return_type r('c', opposite);
r.arrival[0] = 1;
r.arrival[1] = -1;
return r;
}
static inline return_type collinear_b_in_a(S2 const& , bool opposite)
{
return_type r('c', opposite);
r.arrival[0] = -1;
r.arrival[1] = 1;
return r;
}
static inline return_type collinear_overlaps(
coordinate_type const& , coordinate_type const& ,
coordinate_type const& , coordinate_type const& ,
int arrival_a, int arrival_b, bool opposite)
{
return_type r('c', opposite);
r.arrival[0] = arrival_a;
r.arrival[1] = arrival_b;
return r;
}
static inline return_type segment_equal(S1 const& , bool opposite)
{
return return_type('e', opposite);
}
static inline return_type degenerate(S1 const& , bool)
template <typename Segment>
static inline return_type degenerate(Segment const& , bool)
{
return return_type('0', false);
}
@@ -237,11 +278,6 @@ struct segments_direction
return return_type('d', false);
}
static inline return_type collinear_disjoint()
{
return return_type('d', false);
}
static inline return_type error(std::string const&)
{
// Return "E" to denote error

View File

@@ -16,7 +16,7 @@
#include <boost/concept_check.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/geometry/arithmetic/determinant.hpp>
#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/strategies/side_info.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
@@ -29,106 +29,154 @@ namespace boost { namespace geometry
namespace policies { namespace relate
{
template <typename S1, typename S2, typename ReturnType, typename CalculationType = void>
/*!
\brief Policy calculating the intersection points themselves
*/
template
<
typename ReturnType
>
struct segments_intersection_points
{
typedef ReturnType return_type;
typedef S1 segment_type1;
typedef S2 segment_type2;
typedef typename select_calculation_type
<
S1, S2, CalculationType
>::type coordinate_type;
template <typename R>
static inline return_type segments_intersect(side_info const&,
R const& r,
coordinate_type const& dx1, coordinate_type const& dy1,
coordinate_type const& , coordinate_type const& ,
S1 const& s1, S2 const& )
template
<
typename Point,
typename Segment,
typename SegmentRatio,
typename T
>
static inline void assign(Point& point,
Segment const& segment,
SegmentRatio const& ratio,
T const& dx, T const& dy)
{
typedef typename geometry::coordinate_type
<
typename return_type::point_type
>::type return_coordinate_type;
typedef typename geometry::coordinate_type<Point>::type coordinate_type;
coordinate_type const s1x = get<0, 0>(s1);
coordinate_type const s1y = get<0, 1>(s1);
return_type result;
result.count = 1;
set<0>(result.intersections[0],
geometry::math::round<return_coordinate_type>(R(s1x) + r * R(dx1)));
set<1>(result.intersections[0],
geometry::math::round<return_coordinate_type>(R(s1y) + r * R(dy1)));
return result;
// Calculate the intersection point based on segment_ratio
// Up to know, division was postponed. Here we divide using numerator/
// denominator. In case of integer this might result in an integer
// division.
BOOST_ASSERT(ratio.denominator() != 0);
set<0>(point, boost::numeric_cast<coordinate_type>(
get<0, 0>(segment)
+ ratio.numerator() * dx / ratio.denominator()));
set<1>(point, boost::numeric_cast<coordinate_type>(
get<0, 1>(segment)
+ ratio.numerator() * dy / ratio.denominator()));
}
static inline return_type collinear_touch(coordinate_type const& x,
coordinate_type const& y, int, int)
template
<
typename Segment1,
typename Segment2,
typename SegmentIntersectionInfo
>
static inline return_type segments_crosses(side_info const&,
SegmentIntersectionInfo const& sinfo,
Segment1 const& s1, Segment2 const& s2)
{
return_type result;
result.count = 1;
set<0>(result.intersections[0], x);
set<1>(result.intersections[0], y);
if (sinfo.robust_ra < sinfo.robust_rb)
{
assign(result.intersections[0], s1, sinfo.robust_ra,
sinfo.dx_a, sinfo.dy_a);
}
else
{
assign(result.intersections[0], s2, sinfo.robust_rb,
sinfo.dx_b, sinfo.dy_b);
}
result.fractions[0].assign(sinfo);
return result;
}
template <typename S>
static inline return_type collinear_inside(S const& s, int index1 = 0, int index2 = 1)
template <typename Segment1, typename Segment2, typename Ratio>
static inline return_type segments_collinear(
Segment1 const& a, Segment2 const& b,
Ratio const& ra_from_wrt_b, Ratio const& ra_to_wrt_b,
Ratio const& rb_from_wrt_a, Ratio const& rb_to_wrt_a)
{
return_type result;
result.count = 2;
set<0>(result.intersections[index1], get<0, 0>(s));
set<1>(result.intersections[index1], get<0, 1>(s));
set<0>(result.intersections[index2], get<1, 0>(s));
set<1>(result.intersections[index2], get<1, 1>(s));
return result;
}
int index = 0, count_a = 0, count_b = 0;
Ratio on_a[2];
template <typename S>
static inline return_type collinear_interior_boundary_intersect(S const& s, bool a_in_b,
int, int, bool opposite)
{
int index1 = opposite && ! a_in_b ? 1 : 0;
return collinear_inside(s, index1, 1 - index1);
}
// The conditions "index < 2" are necessary for non-robust handling,
// if index would be 2 this indicate an (currently uncatched) error
static inline return_type collinear_a_in_b(S1 const& s, bool)
{
return collinear_inside(s);
}
static inline return_type collinear_b_in_a(S2 const& s, bool opposite)
{
int index1 = opposite ? 1 : 0;
return collinear_inside(s, index1, 1 - index1);
}
// IMPORTANT: the order of conditions is different as in direction.hpp
if (ra_from_wrt_b.on_segment()
&& index < 2)
{
// a1--------->a2
// b1----->b2
//
// ra1 (relative to b) is between 0/1:
// -> First point of A is intersection point
detail::assign_point_from_index<0>(a, result.intersections[index]);
result.fractions[index].assign(Ratio::zero(), ra_from_wrt_b);
on_a[index] = Ratio::zero();
index++;
count_a++;
}
if (rb_from_wrt_a.in_segment()
&& index < 2)
{
// We take the first intersection point of B
// a1--------->a2
// b1----->b2
// But only if it is not located on A
// a1--------->a2
// b1----->b2 rb_from_wrt_a == 0/1 -> a already taken
static inline return_type collinear_overlaps(
coordinate_type const& x1, coordinate_type const& y1,
coordinate_type const& x2, coordinate_type const& y2,
int, int, bool)
{
return_type result;
result.count = 2;
set<0>(result.intersections[0], x1);
set<1>(result.intersections[0], y1);
set<0>(result.intersections[1], x2);
set<1>(result.intersections[1], y2);
return result;
}
detail::assign_point_from_index<0>(b, result.intersections[index]);
result.fractions[index].assign(rb_from_wrt_a, Ratio::zero());
on_a[index] = rb_from_wrt_a;
index++;
count_b++;
}
if (ra_to_wrt_b.on_segment()
&& index < 2)
{
// Similarly, second IP (here a2)
// a1--------->a2
// b1----->b2
detail::assign_point_from_index<1>(a, result.intersections[index]);
result.fractions[index].assign(Ratio::one(), ra_to_wrt_b);
on_a[index] = Ratio::one();
index++;
count_a++;
}
if (rb_to_wrt_a.in_segment()
&& index < 2)
{
detail::assign_point_from_index<1>(b, result.intersections[index]);
result.fractions[index].assign(rb_to_wrt_a, Ratio::one());
on_a[index] = rb_to_wrt_a;
index++;
count_b++;
}
// TEMPORARY
// If both are from b, and b is reversed w.r.t. a, we swap IP's
// to align them w.r.t. a
// get_turn_info still relies on some order (in some collinear cases)
if (index == 2 && on_a[1] < on_a[0])
{
std::swap(result.fractions[0], result.fractions[1]);
std::swap(result.intersections[0], result.intersections[1]);
}
result.count = index;
static inline return_type segment_equal(S1 const& s, bool)
{
return_type result;
result.count = 2;
// TODO: order of IP's
set<0>(result.intersections[0], get<0, 0>(s));
set<1>(result.intersections[0], get<0, 1>(s));
set<0>(result.intersections[1], get<1, 0>(s));
set<1>(result.intersections[1], get<1, 1>(s));
return result;
}
@@ -141,17 +189,13 @@ struct segments_intersection_points
return return_type();
}
static inline return_type collinear_disjoint()
{
return return_type();
}
static inline return_type degenerate(S1 const& s, bool)
template <typename Segment>
static inline return_type degenerate(Segment const& segment, bool)
{
return_type result;
result.count = 1;
set<0>(result.intersections[0], get<0, 0>(s));
set<1>(result.intersections[0], get<0, 1>(s));
set<0>(result.intersections[0], get<0, 0>(segment));
set<1>(result.intersections[0], get<0, 1>(segment));
return result;
}
};

View File

@@ -0,0 +1,109 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_GEOMETRY_POLICIES_RELATE_INTERSECTION_RATIOS_HPP
#define BOOST_GEOMETRY_GEOMETRY_POLICIES_RELATE_INTERSECTION_RATIOS_HPP
#include <algorithm>
#include <string>
#include <boost/concept_check.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/strategies/side_info.hpp>
namespace boost { namespace geometry
{
namespace policies { namespace relate
{
/*!
\brief Policy returning segment ratios
\note Template argument FractionType should be a fraction_type<SegmentRatio>
*/
template
<
typename FractionType
>
struct segments_intersection_ratios
{
typedef FractionType return_type;
template
<
typename Segment1,
typename Segment2,
typename SegmentIntersectionInfo
>
static inline return_type segments_crosses(side_info const&,
SegmentIntersectionInfo const& sinfo,
Segment1 const& , Segment2 const& )
{
return_type result;
result.assign(sinfo);
return result;
}
template <typename Segment1, typename Segment2, typename Ratio>
static inline return_type segments_collinear(
Segment1 const& , Segment2 const& ,
Ratio const& ra_from_wrt_b, Ratio const& ra_to_wrt_b,
Ratio const& rb_from_wrt_a, Ratio const& rb_to_wrt_a)
{
// We have only one result, for (potentially) two IP's,
// so we take a first one
return_type result;
if (ra_from_wrt_b.on_segment())
{
result.assign(Ratio::zero(), ra_from_wrt_b);
}
else if (rb_from_wrt_a.in_segment())
{
result.assign(rb_from_wrt_a, Ratio::zero());
}
else if (ra_to_wrt_b.on_segment())
{
result.assign(Ratio::one(), ra_to_wrt_b);
}
else if (rb_to_wrt_a.in_segment())
{
result.assign(rb_to_wrt_a, Ratio::one());
}
return result;
}
static inline return_type disjoint()
{
return return_type();
}
static inline return_type error(std::string const&)
{
return return_type();
}
template <typename Segment>
static inline return_type degenerate(Segment const& segment, bool)
{
return return_type();
}
};
}} // namespace policies::relate
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_GEOMETRY_POLICIES_RELATE_INTERSECTION_RATIOS_HPP

View File

@@ -14,8 +14,6 @@
#include <boost/tuple/tuple.hpp>
#include <boost/geometry/strategies/side_info.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
#include <boost/geometry/util/select_most_precise.hpp>
namespace boost { namespace geometry
{
@@ -26,7 +24,7 @@ namespace policies { namespace relate
// "tupled" to return intersection results together.
// Now with two, with some meta-programming and derivations it can also be three (or more)
template <typename Policy1, typename Policy2, typename CalculationType = void>
template <typename Policy1, typename Policy2>
struct segments_tupled
{
typedef boost::tuple
@@ -35,101 +33,32 @@ struct segments_tupled
typename Policy2::return_type
> return_type;
// Take segments of first policy, they should be equal
typedef typename Policy1::segment_type1 segment_type1;
typedef typename Policy1::segment_type2 segment_type2;
typedef typename select_calculation_type
<
segment_type1,
segment_type2,
CalculationType
>::type coordinate_type;
// Get the same type, but at least a double
typedef typename select_most_precise<coordinate_type, double>::type rtype;
template <typename R>
static inline return_type segments_intersect(side_info const& sides,
R const& r,
coordinate_type const& dx1, coordinate_type const& dy1,
coordinate_type const& dx2, coordinate_type const& dy2,
segment_type1 const& s1, segment_type2 const& s2)
template <typename Segment1, typename Segment2, typename SegmentIntersectionInfo>
static inline return_type segments_crosses(side_info const& sides,
SegmentIntersectionInfo const& sinfo,
Segment1 const& s1, Segment2 const& s2)
{
return boost::make_tuple
(
Policy1::segments_intersect(sides, r,
dx1, dy1, dx2, dy2, s1, s2),
Policy2::segments_intersect(sides, r,
dx1, dy1, dx2, dy2, s1, s2)
Policy1::segments_crosses(sides, sinfo, s1, s2),
Policy2::segments_crosses(sides, sinfo, s1, s2)
);
}
static inline return_type collinear_touch(coordinate_type const& x,
coordinate_type const& y, int arrival_a, int arrival_b)
template <typename Segment1, typename Segment2, typename Ratio>
static inline return_type segments_collinear(
Segment1 const& segment1, Segment2 const& segment2,
Ratio const& ra1, Ratio const& ra2, Ratio const& rb1, Ratio const& rb2)
{
return boost::make_tuple
(
Policy1::collinear_touch(x, y, arrival_a, arrival_b),
Policy2::collinear_touch(x, y, arrival_a, arrival_b)
Policy1::segments_collinear(segment1, segment2, ra1, ra2, rb1, rb2),
Policy2::segments_collinear(segment1, segment2, ra1, ra2, rb1, rb2)
);
}
template <typename S>
static inline return_type collinear_interior_boundary_intersect(S const& segment,
bool a_within_b,
int arrival_a, int arrival_b, bool opposite)
{
return boost::make_tuple
(
Policy1::collinear_interior_boundary_intersect(segment, a_within_b, arrival_a, arrival_b, opposite),
Policy2::collinear_interior_boundary_intersect(segment, a_within_b, arrival_a, arrival_b, opposite)
);
}
static inline return_type collinear_a_in_b(segment_type1 const& segment,
bool opposite)
{
return boost::make_tuple
(
Policy1::collinear_a_in_b(segment, opposite),
Policy2::collinear_a_in_b(segment, opposite)
);
}
static inline return_type collinear_b_in_a(segment_type2 const& segment,
bool opposite)
{
return boost::make_tuple
(
Policy1::collinear_b_in_a(segment, opposite),
Policy2::collinear_b_in_a(segment, opposite)
);
}
static inline return_type collinear_overlaps(
coordinate_type const& x1, coordinate_type const& y1,
coordinate_type const& x2, coordinate_type const& y2,
int arrival_a, int arrival_b, bool opposite)
{
return boost::make_tuple
(
Policy1::collinear_overlaps(x1, y1, x2, y2, arrival_a, arrival_b, opposite),
Policy2::collinear_overlaps(x1, y1, x2, y2, arrival_a, arrival_b, opposite)
);
}
static inline return_type segment_equal(segment_type1 const& s,
bool opposite)
{
return boost::make_tuple
(
Policy1::segment_equal(s, opposite),
Policy2::segment_equal(s, opposite)
);
}
static inline return_type degenerate(segment_type1 const& segment,
template <typename Segment>
static inline return_type degenerate(Segment const& segment,
bool a_degenerate)
{
return boost::make_tuple
@@ -157,15 +86,6 @@ struct segments_tupled
);
}
static inline return_type collinear_disjoint()
{
return boost::make_tuple
(
Policy1::collinear_disjoint(),
Policy2::collinear_disjoint()
);
}
};
}} // namespace policies::relate

View File

@@ -0,0 +1,285 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2014 Bruno Lalande, Paris, France.
// Copyright (c) 2014 Mateusz Loskot, London, UK.
// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_POLICIES_ROBUSTNESS_GET_RESCALE_POLICY_HPP
#define BOOST_GEOMETRY_POLICIES_ROBUSTNESS_GET_RESCALE_POLICY_HPP
#include <cstddef>
#include <boost/type_traits.hpp>
#include <boost/geometry/core/tag_cast.hpp>
#include <boost/geometry/algorithms/envelope.hpp>
#include <boost/geometry/algorithms/expand.hpp>
#include <boost/geometry/algorithms/detail/recalculate.hpp>
#include <boost/geometry/algorithms/detail/get_max_size.hpp>
#include <boost/geometry/policies/robustness/robust_type.hpp>
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/geometries/box.hpp>
#include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
#include <boost/geometry/policies/robustness/rescale_policy.hpp>
#include <boost/geometry/util/promote_floating_point.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace get_rescale_policy
{
template <typename Point, typename RobustPoint, typename Geometry, typename Factor>
static inline void init_rescale_policy(Geometry const& geometry,
Point& min_point,
RobustPoint& min_robust_point,
Factor& factor)
{
// Get bounding boxes
model::box<Point> env = geometry::return_envelope<model::box<Point> >(geometry);
// Scale this to integer-range
typedef typename promote_floating_point
<
typename geometry::coordinate_type<Point>::type
>::type num_type;
num_type const diff = boost::numeric_cast<num_type>(detail::get_max_size(env));
num_type const range = 10000000.0; // Define a large range to get precise integer coordinates
num_type const half = 0.5;
factor = boost::numeric_cast<num_type>(
boost::numeric_cast<boost::long_long_type>(half + range / diff));
// Assign input/output minimal points
detail::assign_point_from_index<0>(env, min_point);
num_type const two = 2;
boost::long_long_type const min_coordinate
= boost::numeric_cast<boost::long_long_type>(-range / two);
assign_values(min_robust_point, min_coordinate, min_coordinate);
}
template <typename Point, typename RobustPoint, typename Geometry1, typename Geometry2, typename Factor>
static inline void init_rescale_policy(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Point& min_point,
RobustPoint& min_robust_point,
Factor& factor)
{
// Get bounding boxes
model::box<Point> env = geometry::return_envelope<model::box<Point> >(geometry1);
model::box<Point> env2 = geometry::return_envelope<model::box<Point> >(geometry2);
geometry::expand(env, env2);
// TODO: merge this with implementation above
// Scale this to integer-range
typedef typename promote_floating_point
<
typename geometry::coordinate_type<Point>::type
>::type num_type;
num_type const diff = boost::numeric_cast<num_type>(detail::get_max_size(env));
num_type const range = 10000000.0; // Define a large range to get precise integer coordinates
num_type const half = 0.5;
factor = boost::numeric_cast<num_type>(
boost::numeric_cast<boost::long_long_type>(half + range / diff));
// Assign input/output minimal points
detail::assign_point_from_index<0>(env, min_point);
num_type const two = 2;
boost::long_long_type const min_coordinate
= boost::numeric_cast<boost::long_long_type>(-range / two);
assign_values(min_robust_point, min_coordinate, min_coordinate);
}
template
<
typename Point,
bool IsFloatingPoint
>
struct rescale_policy_type
{
typedef no_rescale_policy type;
};
// We rescale only all FP types
template
<
typename Point
>
struct rescale_policy_type<Point, true>
{
typedef typename geometry::coordinate_type<Point>::type coordinate_type;
typedef model::point
<
typename detail::robust_type<coordinate_type>::type,
geometry::dimension<Point>::value,
typename geometry::coordinate_system<Point>::type
> robust_point_type;
typedef typename promote_floating_point<coordinate_type>::type factor_type;
typedef detail::robust_policy<Point, robust_point_type, factor_type> type;
};
template <typename Policy>
struct get_rescale_policy
{
template <typename Geometry>
static inline Policy apply(Geometry const& geometry)
{
typedef typename point_type<Geometry>::type point_type;
typedef typename geometry::coordinate_type<Geometry>::type coordinate_type;
typedef typename promote_floating_point<coordinate_type>::type factor_type;
typedef model::point
<
typename detail::robust_type<coordinate_type>::type,
geometry::dimension<point_type>::value,
typename geometry::coordinate_system<point_type>::type
> robust_point_type;
point_type min_point;
robust_point_type min_robust_point;
factor_type factor;
init_rescale_policy(geometry, min_point, min_robust_point, factor);
return Policy(min_point, min_robust_point, factor);
}
template <typename Geometry1, typename Geometry2>
static inline Policy apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
{
typedef typename point_type<Geometry1>::type point_type;
typedef typename geometry::coordinate_type<Geometry1>::type coordinate_type;
typedef typename promote_floating_point<coordinate_type>::type factor_type;
typedef model::point
<
typename detail::robust_type<coordinate_type>::type,
geometry::dimension<point_type>::value,
typename geometry::coordinate_system<point_type>::type
> robust_point_type;
point_type min_point;
robust_point_type min_robust_point;
factor_type factor;
init_rescale_policy(geometry1, geometry2, min_point, min_robust_point, factor);
return Policy(min_point, min_robust_point, factor);
}
};
// Specialization for no-rescaling
template <>
struct get_rescale_policy<no_rescale_policy>
{
template <typename Geometry>
static inline no_rescale_policy apply(Geometry const& )
{
return no_rescale_policy();
}
template <typename Geometry1, typename Geometry2>
static inline no_rescale_policy apply(Geometry1 const& , Geometry2 const& )
{
return no_rescale_policy();
}
};
}} // namespace detail::get_rescale_policy
#endif // DOXYGEN_NO_DETAIL
template<typename Point>
struct rescale_policy_type
: public detail::get_rescale_policy::rescale_policy_type
<
Point,
#if defined(BOOST_GEOMETRY_NO_ROBUSTNESS)
false
#else
boost::is_floating_point
<
typename geometry::coordinate_type<Point>::type
>::type::value
#endif
>
{
BOOST_STATIC_ASSERT
((
boost::is_same
<
typename geometry::tag<Point>::type,
geometry::point_tag
>::type::value
));
};
template
<
typename Geometry1,
typename Geometry2,
typename Tag1 = typename tag_cast
<
typename tag<Geometry1>::type,
box_tag,
pointlike_tag,
linear_tag,
areal_tag
>::type,
typename Tag2 = typename tag_cast
<
typename tag<Geometry2>::type,
box_tag,
pointlike_tag,
linear_tag,
areal_tag
>::type
>
struct rescale_overlay_policy_type
// Default: no rescaling
: public detail::get_rescale_policy::rescale_policy_type
<
typename geometry::point_type<Geometry1>::type,
false
>
{};
// Areal/areal: get rescale policy based on coordinate type
template
<
typename Geometry1,
typename Geometry2
>
struct rescale_overlay_policy_type<Geometry1, Geometry2, areal_tag, areal_tag>
: public rescale_policy_type
<
typename geometry::point_type<Geometry1>::type
>
{};
template <typename Policy, typename Geometry>
inline Policy get_rescale_policy(Geometry const& geometry)
{
return detail::get_rescale_policy::get_rescale_policy<Policy>::apply(geometry);
}
template <typename Policy, typename Geometry1, typename Geometry2>
inline Policy get_rescale_policy(Geometry1 const& geometry1, Geometry2 const& geometry2)
{
return detail::get_rescale_policy::get_rescale_policy<Policy>::apply(geometry1, geometry2);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_POLICIES_ROBUSTNESS_GET_RESCALE_POLICY_HPP

View File

@@ -0,0 +1,66 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2013 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2013 Bruno Lalande, Paris, France.
// Copyright (c) 2013 Mateusz Loskot, London, UK.
// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_POLICIES_ROBUSTNESS_NO_RESCALE_POLICY_HPP
#define BOOST_GEOMETRY_POLICIES_ROBUSTNESS_NO_RESCALE_POLICY_HPP
#include <stddef.h>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/policies/robustness/robust_point_type.hpp>
#include <boost/geometry/policies/robustness/segment_ratio.hpp>
#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
// Probably this will be moved out of namespace detail
struct no_rescale_policy
{
static bool const enabled = false;
// We don't rescale but return the reference of the input
template <std::size_t Dimension, typename Value>
inline Value const& apply(Value const& value) const
{
return value;
}
};
} // namespace detail
#endif
// Implement meta-functions for this policy
template <typename Point>
struct robust_point_type<Point, detail::no_rescale_policy>
{
// The point itself
typedef Point type;
};
template <typename Point>
struct segment_ratio_type<Point, detail::no_rescale_policy>
{
// Define a segment_ratio defined on coordinate type, e.g.
// int/int or float/float
typedef typename geometry::coordinate_type<Point>::type coordinate_type;
typedef segment_ratio<coordinate_type> type;
};
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_POLICIES_ROBUSTNESS_NO_RESCALE_POLICY_HPP

View File

@@ -0,0 +1,82 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2014 Bruno Lalande, Paris, France.
// Copyright (c) 2014 Mateusz Loskot, London, UK.
// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_POLICIES_ROBUSTNESS_RESCALE_POLICY_HPP
#define BOOST_GEOMETRY_POLICIES_ROBUSTNESS_RESCALE_POLICY_HPP
#include <cstddef>
#include <boost/type_traits.hpp>
#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
#include <boost/geometry/policies/robustness/robust_point_type.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
template <typename FpPoint, typename IntPoint, typename CalculationType>
struct robust_policy
{
static bool const enabled = true;
typedef typename geometry::coordinate_type<IntPoint>::type output_ct;
robust_policy(FpPoint const& fp_min, IntPoint const& int_min, CalculationType const& the_factor)
: m_fp_min(fp_min)
, m_int_min(int_min)
, m_multiplier(the_factor)
{
}
template <std::size_t Dimension, typename Value>
inline output_ct apply(Value const& value) const
{
// a + (v-b)*f
CalculationType const a = static_cast<CalculationType>(get<Dimension>(m_int_min));
CalculationType const b = static_cast<CalculationType>(get<Dimension>(m_fp_min));
CalculationType const result = a + (value - b) * m_multiplier;
return static_cast<output_ct>(result);
}
FpPoint m_fp_min;
IntPoint m_int_min;
CalculationType m_multiplier;
};
} // namespace detail
#endif
// Implement meta-functions for this policy
// Define the IntPoint as a robust-point type
template <typename Point, typename FpPoint, typename IntPoint, typename CalculationType>
struct robust_point_type<Point, detail::robust_policy<FpPoint, IntPoint, CalculationType> >
{
typedef IntPoint type;
};
// Meta function for rescaling, if rescaling is done segment_ratio is based on long long
template <typename Point, typename FpPoint, typename IntPoint, typename CalculationType>
struct segment_ratio_type<Point, detail::robust_policy<FpPoint, IntPoint, CalculationType> >
{
typedef segment_ratio<boost::long_long_type> type;
};
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_POLICIES_ROBUSTNESS_RESCALE_POLICY_HPP

View File

@@ -0,0 +1,28 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2013 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2013 Bruno Lalande, Paris, France.
// Copyright (c) 2013 Mateusz Loskot, London, UK.
// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_POLICIES_ROBUSTNESS_ROBUST_POINT_TYPE_HPP
#define BOOST_GEOMETRY_POLICIES_ROBUSTNESS_ROBUST_POINT_TYPE_HPP
#include <boost/geometry/algorithms/not_implemented.hpp>
namespace boost { namespace geometry
{
// Meta-function to typedef a robust point type for a policy
template <typename Point, typename Policy>
struct robust_point_type {}; //: not_implemented<> {};
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_POLICIES_ROBUSTNESS_ROBUST_POINT_TYPE_HPP

View File

@@ -0,0 +1,67 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2014 Bruno Lalande, Paris, France.
// Copyright (c) 2014 Mateusz Loskot, London, UK.
// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_POLICIES_ROBUSTNESS_ROBUST_TYPE_HPP
#define BOOST_GEOMETRY_POLICIES_ROBUSTNESS_ROBUST_TYPE_HPP
#include <boost/type_traits.hpp>
#include <boost/config.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail_dispatch
{
template <typename CoordinateType, typename IsFloatingPoint>
struct robust_type
{
};
template <typename CoordinateType>
struct robust_type<CoordinateType, boost::false_type>
{
typedef CoordinateType type;
};
template <typename CoordinateType>
struct robust_type<CoordinateType, boost::true_type>
{
typedef boost::long_long_type type;
};
} // namespace detail_dispatch
namespace detail
{
template <typename CoordinateType>
struct robust_type
{
typedef typename detail_dispatch::robust_type
<
CoordinateType,
typename boost::is_floating_point<CoordinateType>::type
>::type type;
};
} // namespace detail
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_POLICIES_ROBUSTNESS_ROBUST_TYPE_HPP

View File

@@ -0,0 +1,236 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2013 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_POLICIES_ROBUSTNESS_SEGMENT_RATIO_HPP
#define BOOST_GEOMETRY_POLICIES_ROBUSTNESS_SEGMENT_RATIO_HPP
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <boost/rational.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/promote_floating_point.hpp>
namespace boost { namespace geometry
{
namespace detail { namespace segment_ratio
{
template
<
typename Type,
bool IsIntegral = boost::is_integral<Type>::type::value
>
struct less {};
template <typename Type>
struct less<Type, true>
{
template <typename Ratio>
static inline bool apply(Ratio const& lhs, Ratio const& rhs)
{
return boost::rational<Type>(lhs.numerator(), lhs.denominator())
< boost::rational<Type>(rhs.numerator(), rhs.denominator());
}
};
template <typename Type>
struct less<Type, false>
{
template <typename Ratio>
static inline bool apply(Ratio const& lhs, Ratio const& rhs)
{
BOOST_ASSERT(lhs.denominator() != 0);
BOOST_ASSERT(rhs.denominator() != 0);
return lhs.numerator() * rhs.denominator()
< rhs.numerator() * lhs.denominator();
}
};
template
<
typename Type,
bool IsIntegral = boost::is_integral<Type>::type::value
>
struct equal {};
template <typename Type>
struct equal<Type, true>
{
template <typename Ratio>
static inline bool apply(Ratio const& lhs, Ratio const& rhs)
{
return boost::rational<Type>(lhs.numerator(), lhs.denominator())
== boost::rational<Type>(rhs.numerator(), rhs.denominator());
}
};
template <typename Type>
struct equal<Type, false>
{
template <typename Ratio>
static inline bool apply(Ratio const& lhs, Ratio const& rhs)
{
BOOST_ASSERT(lhs.denominator() != 0);
BOOST_ASSERT(rhs.denominator() != 0);
return geometry::math::equals
(
lhs.numerator() * rhs.denominator(),
rhs.numerator() * lhs.denominator()
);
}
};
}}
//! Small class to keep a ratio (e.g. 1/4)
//! Main purpose is intersections and checking on 0, 1, and smaller/larger
//! The prototype used Boost.Rational. However, we also want to store FP ratios,
//! (so numerator/denominator both in float)
//! and Boost.Rational starts with GCD which we prefer to avoid if not necessary
//! On a segment means: this ratio is between 0 and 1 (both inclusive)
//!
template <typename Type>
class segment_ratio
{
public :
typedef Type numeric_type;
// Type-alias for the type itself
typedef segment_ratio<Type> thistype;
inline segment_ratio()
: m_numerator(0)
, m_denominator(1)
, m_approximation(0)
{}
inline segment_ratio(const Type& nominator, const Type& denominator)
: m_numerator(nominator)
, m_denominator(denominator)
{
initialize();
}
inline Type const& numerator() const { return m_numerator; }
inline Type const& denominator() const { return m_denominator; }
inline void assign(const Type& nominator, const Type& denominator)
{
m_numerator = nominator;
m_denominator = denominator;
initialize();
}
inline void initialize()
{
// Minimal normalization
// 1/-4 => -1/4, -1/-4 => 1/4
if (m_denominator < 0)
{
m_numerator = -m_numerator;
m_denominator = -m_denominator;
}
typedef typename promote_floating_point<Type>::type num_type;
static const num_type scale = 1000000.0;
m_approximation =
m_denominator == 0 ? 0
: boost::numeric_cast<int>
(
boost::numeric_cast<num_type>(m_numerator) * scale
/ boost::numeric_cast<num_type>(m_denominator)
);
}
inline bool is_zero() const { return math::equals(m_numerator, 0); }
inline bool is_one() const { return math::equals(m_numerator, m_denominator); }
inline bool on_segment() const
{
// e.g. 0/4 or 4/4 or 2/4
return m_numerator >= 0 && m_numerator <= m_denominator;
}
inline bool in_segment() const
{
// e.g. 1/4
return m_numerator > 0 && m_numerator < m_denominator;
}
inline bool on_end() const
{
// e.g. 0/4 or 4/4
return is_zero() || is_one();
}
inline bool left() const
{
// e.g. -1/4
return m_numerator < 0;
}
inline bool right() const
{
// e.g. 5/4
return m_numerator > m_denominator;
}
inline bool close_to(thistype const& other) const
{
return geometry::math::abs(m_approximation - other.m_approximation) < 2;
}
inline bool operator< (thistype const& other) const
{
return close_to(other)
? detail::segment_ratio::less<Type>::apply(*this, other)
: m_approximation < other.m_approximation;
}
inline bool operator== (thistype const& other) const
{
return close_to(other)
&& detail::segment_ratio::equal<Type>::apply(*this, other);
}
static inline thistype zero()
{
static thistype result(0, 1);
return result;
}
static inline thistype one()
{
static thistype result(1, 1);
return result;
}
#if defined(BOOST_GEOMETRY_DEFINE_STREAM_OPERATOR_SEGMENT_RATIO)
friend std::ostream& operator<<(std::ostream &os, segment_ratio const& ratio)
{
os << ratio.m_numerator << "/" << ratio.m_denominator;
return os;
}
#endif
private :
Type m_numerator;
Type m_denominator;
// Contains ratio on scale 0..1000000 (for 0..1)
// This is an approximation for fast and rough comparisons
// Boost.Rational is used if the approximations are close.
// Reason: performance, Boost.Rational does a GCD by default and also the
// comparisons contain while-loops.
int m_approximation;
};
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_POLICIES_ROBUSTNESS_SEGMENT_RATIO_HPP

View File

@@ -9,24 +9,20 @@
// 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_RESCALE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RESCALE_HPP
#ifndef BOOST_GEOMETRY_POLICIES_ROBUSTNESS_SEGMENT_RATIO_TYPE_HPP
#define BOOST_GEOMETRY_POLICIES_ROBUSTNESS_SEGMENT_RATIO_TYPE_HPP
#include <boost/geometry/algorithms/not_implemented.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
// Meta-function to access segment-ratio for a policy
template <typename Point, typename Policy>
struct segment_ratio_type {}; // : not_implemented<> {};
// To be removed later, when we will initialize a real policy
namespace detail
{
struct no_rescale_policy {};
}
#endif
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RESCALE_HPP
#endif // BOOST_GEOMETRY_POLICIES_ROBUSTNESS_SEGMENT_RATIO_TYPE_HPP

View File

@@ -319,7 +319,7 @@ private:
typedef typename strategy::side::services::default_strategy<cs_tag>::type side;
output.push_back(p);
register std::size_t output_size = output.size();
std::size_t output_size = output.size();
while (output_size >= 3)
{
rev_iterator rit = output.rbegin();

View File

@@ -20,38 +20,44 @@
#include <boost/geometry/strategies/intersection_result.hpp>
#include <boost/geometry/strategies/cartesian/cart_intersect.hpp>
#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
namespace boost { namespace geometry
{
// The intersection strategy is a "compound strategy",
// it contains a segment-intersection-strategy
// and a side-strategy
/*!
\tparam CalculationType \tparam_calculation
*/
\brief "compound strategy", containing a segment-intersection-strategy
and a side-strategy
*/
template
<
typename Tag,
typename Geometry1,
typename Geometry2,
typename IntersectionPoint,
typename RobustPolicy,
typename CalculationType = void
>
struct strategy_intersection
{
private :
// for development BOOST_STATIC_ASSERT((! boost::is_same<RobustPolicy, void>::type::value));
typedef typename geometry::point_type<Geometry1>::type point1_type;
typedef typename geometry::point_type<Geometry2>::type point2_type;
typedef typename model::referring_segment<point1_type const> segment1_type;
typedef typename model::referring_segment<point2_type const> segment2_type;
typedef segment_intersection_points
<
IntersectionPoint,
typename geometry::segment_ratio_type
<
IntersectionPoint
> ip_type;
IntersectionPoint, RobustPolicy
>::type
> ip_type;
public:
typedef strategy::intersection::relate_cartesian_segments
@@ -60,18 +66,9 @@ public:
<
policies::relate::segments_intersection_points
<
segment1_type,
segment2_type,
ip_type,
CalculationType
ip_type
> ,
policies::relate::segments_direction
<
segment1_type,
segment2_type,
CalculationType
>,
CalculationType
>,
CalculationType
> segment_intersection_strategy_type;
@@ -81,6 +78,8 @@ public:
Tag,
CalculationType
>::type side_strategy_type;
typedef RobustPolicy rescale_policy_type;
};

View File

@@ -16,6 +16,7 @@
#include <cstddef>
namespace boost { namespace geometry
{
@@ -153,13 +154,47 @@ struct de9im_segment : public de9im
#endif
};
template <typename SegmentRatio>
struct fraction_type
{
SegmentRatio robust_ra; // TODO this can be renamed now to "ra"
SegmentRatio robust_rb;
bool initialized;
inline fraction_type()
: initialized(false)
{}
template <typename Point>
template <typename Info>
inline void assign(Info const& info)
{
initialized = true;
robust_ra = info.robust_ra;
robust_rb = info.robust_rb;
}
inline void assign(SegmentRatio const& a, SegmentRatio const& b)
{
initialized = true;
robust_ra = a;
robust_rb = b;
}
};
//
/*!
\brief return-type for segment-intersection
\note Set in intersection_points.hpp, from segment_intersection_info
*/
template <typename Point, typename SegmentRatio>
struct segment_intersection_points
{
std::size_t count;
std::size_t count; // The number of intersection points
// TODO: combine intersections and fractions in one struct
Point intersections[2];
fraction_type<SegmentRatio> fractions[2];
typedef Point point_type;
segment_intersection_points()
@@ -167,6 +202,18 @@ struct segment_intersection_points
{}
};
// All assigned in cart_intersect, passed to intersection_points
template <typename CoordinateType, typename PromotedType, typename SegmentRatio>
struct segment_intersection_info
{
typedef PromotedType promoted_type;
CoordinateType dx_a, dy_a;
CoordinateType dx_b, dy_b; // TODO b can be removed
SegmentRatio robust_ra;
SegmentRatio robust_rb;
};
}} // namespace boost::geometry

View File

@@ -0,0 +1,116 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2014.
// Modifications copyright (c) 2014 Oracle and/or its affiliates.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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_VIEWS_NORMALIZED_VIEW_HPP
#define BOOST_GEOMETRY_VIEWS_NORMALIZED_VIEW_HPP
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/iterator.hpp>
#include <boost/mpl/if.hpp>
#include <boost/type_traits/is_const.hpp>
#include <boost/geometry/views/detail/range_type.hpp>
#include <boost/geometry/views/reversible_view.hpp>
#include <boost/geometry/views/closeable_view.hpp>
namespace boost { namespace geometry {
#ifndef DOXYGEN_NO_DETAIL
namespace detail {
template <typename Geometry>
struct normalized_view
{
static const bool is_const = boost::is_const<Geometry>::value;
//typedef typename ring_type<Geometry>::type ring_type;
typedef typename detail::range_type<Geometry>::type range_type;
typedef typename
boost::mpl::if_c
<
is_const,
range_type const,
range_type
>::type range;
typedef typename
reversible_view
<
range,
order_as_direction
<
geometry::point_order<Geometry>::value
>::value
>::type reversible_type;
typedef typename
boost::mpl::if_c
<
is_const,
reversible_type const,
reversible_type
>::type reversible;
typedef typename
closeable_view
<
reversible,
geometry::closure<Geometry>::value
>::type closeable_type;
typedef typename
boost::mpl::if_c
<
is_const,
closeable_type const,
closeable_type
>::type closeable;
explicit inline normalized_view(range & r)
: m_reversible(r)
, m_closeable(m_reversible)
{}
typedef typename boost::range_iterator<closeable>::type iterator;
typedef typename boost::range_const_iterator<closeable>::type const_iterator;
inline const_iterator begin() const { return boost::begin(m_closeable); }
inline const_iterator end() const { return boost::end(m_closeable); }
inline iterator begin() { return boost::begin(m_closeable); }
inline iterator end() { return boost::end(m_closeable); }
private:
reversible_type m_reversible;
closeable_type m_closeable;
};
} // namespace detail
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_VIEWS_NORMALIZED_VIEW_HPP

View File

@@ -20,7 +20,7 @@ project boost-geometry-index-test
test-suite boost-geometry-index-varray
:
[ run varray_old.cpp ]
[ run varray.cpp ]
[ run varray.cpp : : : <toolset>msvc:<cxxflags>/bigobj ]
;
build-project algorithms ;

View File

@@ -12,7 +12,12 @@ rule test_all
for local fileb in [ glob *.cpp ]
{
all_rules += [ run $(fileb) ] ;
all_rules += [ run $(fileb)
: # additional args
: # test-files
: # requirements
<toolset>msvc:<cxxflags>/bigobj
] ;
}
return $(all_rules) ;

View File

@@ -12,7 +12,12 @@ rule test_all
for local fileb in [ glob *.cpp ]
{
all_rules += [ run $(fileb) ] ;
all_rules += [ run $(fileb)
: # additional args
: # test-files
: # requirements
<toolset>msvc:<cxxflags>/bigobj
] ;
}
return $(all_rules) ;

View File

@@ -18,9 +18,11 @@ rule test_all
: # requirements
<toolset>acc:<linkflags>-lrt
<toolset>acc-pa_risc:<linkflags>-lrt
<toolset>gcc-mingw:<linkflags>"-lole32 -loleaut32 -lpsapi -ladvapi32"
<host-os>hpux,<toolset>gcc:<linkflags>"-Wl,+as,mpas"
# <toolset>gcc-mingw:<linkflags>"-lole32 -loleaut32 -lpsapi -ladvapi32"
<toolset>gcc,<target-os>windows:<linkflags>"-lole32 -loleaut32 -lpsapi -ladvapi32"
<host-os>windows,<toolset>clang:<linkflags>"-lole32 -loleaut32 -lpsapi -ladvapi32"
<toolset>msvc:<cxxflags>/bigobj
] ;
}

View File

@@ -13,8 +13,6 @@
# Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
import testing ;
test-suite boost-geometry-algorithms
:
[ run append.cpp : : : <toolset>msvc:<cxxflags>/bigobj ]
@@ -29,8 +27,8 @@ test-suite boost-geometry-algorithms
[ run covered_by.cpp ]
[ run crosses.cpp ]
[ run difference.cpp : : : <define>BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE <toolset>msvc:<cxxflags>/bigobj ]
[ run difference_linear_linear.cpp /boost/test//boost_unit_test_framework ]
[ run difference_pl_pl.cpp /boost/test//boost_unit_test_framework ]
[ run difference_linear_linear.cpp ]
[ run difference_pl_pl.cpp ]
[ run disjoint.cpp ]
[ run distance.cpp : : : <toolset>msvc:<cxxflags>/bigobj ]
[ run envelope.cpp ]
@@ -38,26 +36,33 @@ test-suite boost-geometry-algorithms
[ run expand.cpp ]
[ run for_each.cpp ]
[ run intersection.cpp : : : <define>BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE <toolset>msvc:<cxxflags>/bigobj ]
[ run intersection_linear_linear.cpp /boost/test//boost_unit_test_framework ]
[ run intersection_pl_pl.cpp /boost/test//boost_unit_test_framework ]
[ run intersection_linear_linear.cpp ]
[ run intersection_pl_pl.cpp ]
[ run intersects.cpp : : : <toolset>msvc:<cxxflags>/bigobj ]
[ run length.cpp ]
[ run make.cpp ]
[ run overlaps.cpp ]
[ run perimeter.cpp ]
[ run point_on_surface.cpp ]
[ run relate.cpp ]
[ run relate_areal_areal.cpp : : : <toolset>msvc:<cxxflags>/bigobj ]
[ run relate_linear_areal.cpp : : : <toolset>msvc:<cxxflags>/bigobj ]
[ run relate_linear_linear.cpp : : : <toolset>msvc:<cxxflags>/bigobj ]
[ run relate_pointlike_xxx.cpp : : : <toolset>msvc:<cxxflags>/bigobj ]
[ run remove_spikes.cpp ]
[ run reverse.cpp ]
[ run simplify.cpp ]
[ run sym_difference_linear_linear.cpp /boost/test//boost_unit_test_framework ]
[ run sym_difference_linear_linear.cpp ]
[ run touches.cpp ]
[ run transform.cpp ]
[ run union.cpp : : : <define>BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE ]
[ run union_linear_linear.cpp /boost/test//boost_unit_test_framework ]
[ run union_pl_pl.cpp /boost/test//boost_unit_test_framework ]
[ run union_linear_linear.cpp ]
[ run union_pl_pl.cpp ]
[ run unique.cpp ]
[ run within.cpp : : : <toolset>msvc:<cxxflags>/bigobj ]
[ run within_areal_areal.cpp : : : <toolset>msvc:<cxxflags>/bigobj ]
[ run within_linear_areal.cpp : : : <toolset>msvc:<cxxflags>/bigobj ]
[ run within_linear_linear.cpp : : : <toolset>msvc:<cxxflags>/bigobj ]
[ run within_pointlike_xxx.cpp : : : <toolset>msvc:<cxxflags>/bigobj ]
;
build-project overlay

View File

@@ -10,6 +10,7 @@
test-suite boost-geometry-algorithms-detail
:
[ run intersection_side.cpp ]
[ run partition.cpp ]
;

View File

@@ -0,0 +1,197 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
//
// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#define BOOST_GEOMETRY_DEFINE_STREAM_OPERATOR_SEGMENT_RATIO
#include <geometry_test_common.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/strategies/cartesian/cart_intersect.hpp>
#include <boost/geometry/strategies/intersection_result.hpp>
#include <boost/geometry/policies/relate/intersection_points.hpp>
#include <boost/geometry/policies/relate/intersection_ratios.hpp>
#include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
#include <boost/geometry/algorithms/detail/intersection_side.hpp>
#include <boost/geometry/algorithms/make.hpp>
#if defined(TEST_WITH_SVG)
# include <boost/geometry/io/svg/svg_mapper.hpp>
#endif
template <typename Point, typename T>
void test_one(std::string const& caseid,
T pi_x, T pi_y, T pj_x, T pj_y, // line p to intersect
T qi_x, T qi_y, T qj_x, T qj_y, // line q to intersect
T si_x, T si_y, T sj_x, T sj_y, // subject line to find side on of IP p/q
int expected_side)
{
typedef bg::detail::no_rescale_policy robust_policy_type;
robust_policy_type robust_policy;
Point pi = bg::make<Point>(pi_x, pi_y);
Point pj = bg::make<Point>(pj_x, pj_y);
Point qi = bg::make<Point>(qi_x, qi_y);
Point qj = bg::make<Point>(qj_x, qj_y);
Point si = bg::make<Point>(si_x, si_y);
Point sj = bg::make<Point>(sj_x, sj_y);
typedef bg::model::referring_segment<const Point> segment_type;
segment_type p(pi, pj);
segment_type q(qi, qj);
segment_type s(si, sj);
int detected_side = bg::detail::intersection_side::intersection_side(pi, pj,
qi, qj, si, sj, robust_policy);
BOOST_CHECK_EQUAL(expected_side, detected_side);
#if defined(TEST_WITH_SVG)
{
std::ostringstream filename;
filename << "intersection_side_" << caseid
<< "_" << string_from_type<typename bg::coordinate_type<Point>::type>::name()
<< ".svg";
std::ofstream svg(filename.str().c_str());
bg::svg_mapper<Point> mapper(svg, 500, 500);
mapper.add(p);
mapper.add(q);
mapper.add(s);
mapper.map(p, "opacity:0.7;stroke:rgb(0,192,0);stroke-width:3");
mapper.map(q, "opacity:0.7;stroke:rgb(0,0,255);stroke-width:3");
mapper.map(s, "opacity:0.7;stroke:rgb(255,0,0);stroke-width:2");
std::string style = ";font-family='Verdana';font-weight:bold";
std::string align = ";text-anchor:end;text-align:end";
int offset = 8;
mapper.text(pi, "pi", "fill:rgb(0,192,0)" + style, offset, offset);
mapper.text(pj, "pj", "fill:rgb(0,192,0)" + style, offset, offset);
mapper.text(qi, "qi", "fill:rgb(0,0,255)" + style + align, -offset, offset);
mapper.text(qj, "qj", "fill:rgb(0,0,255)" + style + align, -offset, offset);
mapper.text(si, "si", "fill:rgb(255,0,0)" + style + align, -offset, offset);
mapper.text(sj, "sj", "fill:rgb(255,0,0)" + style + align, -offset, offset);
// Map the intersection point on the SVG
{
typedef typename bg::segment_ratio_type
<
Point,
robust_policy_type
>::type segment_ratio_type;
// Get the intersection point (or two points)
bg::segment_intersection_points<Point, segment_ratio_type> is
= bg::strategy::intersection::relate_cartesian_segments
<
bg::policies::relate::segments_intersection_points
<
bg::segment_intersection_points<Point, segment_ratio_type>
>
>::apply(p, q, robust_policy);
bg::fraction_type<segment_ratio_type> rs
= bg::strategy::intersection::relate_cartesian_segments
<
bg::policies::relate::segments_intersection_ratios
<
bg::fraction_type<segment_ratio_type>
>
>::apply(p, q, robust_policy);
for (int i = 0; i < is.count; i++)
{
mapper.map(is.intersections[i], "opacity:0.8;stroke:rgb(255,128,0);stroke-width:3", 3);
std::ostringstream out;
out << detected_side << " " << is.fractions[i].robust_ra << " / " << is.fractions[i].robust_rb
<< std::endl
<< rs.robust_ra << " / " << rs.robust_rb;
mapper.text(is.intersections[i], out.str(), "fill:rgb(255,128,0)" + style + align, -2 * offset, offset);
}
}
}
#endif
}
template <typename P>
void test_all()
{
test_one<P, double>("simplex_left",
0, 0, 4, 4, // p
-1, 4, 3, 0, // q
2, 0, 2, 4, // subject
1);
test_one<P, double>("simplex_right",
0, 0, 4, 4, // p
1, 4, 5, 0, // q
2, 0, 2, 4, // subject
-1);
test_one<P, double>("simplex_collinear",
0, 0, 4, 4, // p
0, 4, 4, 0, // q
2, 0, 2, 4, // subject
0);
test_one<P, double>("p_left",
0, 0, 0, 4, // p
1, 4, 5, 0, // q
2, 0, 2, 4, // subject
1);
test_one<P, double>("p_right",
4, 0, 4, 4, // p
1, 4, 5, 0, // q
2, 0, 2, 4, // subject
-1);
test_one<P, double>("p_left",
1, 0, 1, 4, // p
1, 4, 5, 0, // q
2, 0, 2, 4, // subject
1);
test_one<P, double>("p_collinear",
2, -1, 2, 5, // p
1, 4, 5, 0, // q
2, 0, 2, 4, // subject
0);
test_one<P, double>("q_left",
0, 0, 4, 4, // p
1, 4, 1, 0, // q
2, 0, 2, 4, // subject
1);
test_one<P, double>("q_right",
0, 0, 4, 4, // p
3, 4, 3, 0, // q
2, 0, 2, 4, // subject
-1);
test_one<P, double>("q_collinear",
0, 0, 4, 4, // p
2, 1, 2, 3, // q
2, 0, 2, 4, // subject
0);
}
int test_main( int , char* [] )
{
test_all<bg::model::d2::point_xy<double> >();
return 0;
}

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