Merge branch 'develop' into feature/gc3

This commit is contained in:
Adam Wulkiewicz 2021-09-22 23:29:00 +02:00
commit 8c9b11bb85
82 changed files with 2867 additions and 1373 deletions

View File

@ -60,7 +60,7 @@ jobs:
git submodule update --init tools/build
git submodule update --init libs/config
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py geometry
python tools/boostdep/depinst/depinst.py geometry -I index/test
./bootstrap.sh
./b2 headers
- run: mkdir $COVERAGE_DIR

23
LICENSE_1_0.txt Normal file
View File

@ -0,0 +1,23 @@
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

View File

@ -3,6 +3,10 @@
// Copyright (c) 2010-2012 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2021.
// Modifications copyright (c) 2021 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
@ -57,7 +61,7 @@ void test_connect(std::string const& caseid, Geometry const& geometry,
std::size_t count = boost::size(connected_vector);
std::size_t point_count = 0;
BOOST_FOREACH(GeometryOut& connected, connected_vector)
for (GeometryOut& connected : connected_vector)
{
bg::unique(connected);
length += bg::length(connected);
@ -99,7 +103,7 @@ void test_connect(std::string const& caseid, Geometry const& geometry,
mapper.map(geometry, "opacity:0.6;fill:rgb(0,0,255);stroke:rgb(0,0,0);stroke-width:1");
BOOST_FOREACH(GeometryOut& connected, connected_vector)
for (GeometryOut& connected : connected_vector)
{
mapper.map(connected, "opacity:0.6;fill:none;stroke:rgb(255,0,0);stroke-width:5");
}

View File

@ -6,6 +6,10 @@
// Contributed and/or modified by Tinko Bartels,
// as part of Google Summer of Code 2019 program.
// This file was modified by Oracle on 2021.
// Modifications copyright (c) 2021, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
@ -13,7 +17,7 @@
#include <geometry_test_common.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/extensions/triangulation/strategies/cartesian/in_circle_robust.hpp>
#include <boost/geometry/strategy/cartesian/in_circle_robust.hpp>
template <typename P>
void test_all()

View File

@ -24,7 +24,6 @@
#include <boost/geometry/algorithms/comparable_distance.hpp>
#include <boost/geometry/algorithms/equals.hpp>
#include <boost/geometry/algorithms/expand.hpp>
#include <boost/geometry/algorithms/detail/buffer/buffer_box.hpp>
#include <boost/geometry/algorithms/detail/buffer/buffer_policies.hpp>
#include <boost/geometry/algorithms/detail/expand_by_epsilon.hpp>
#include <boost/geometry/strategies/cartesian/turn_in_ring_winding.hpp>

View File

@ -39,7 +39,8 @@
#include <boost/geometry/views/detail/closed_clockwise_view.hpp>
#include <boost/geometry/strategies/cartesian/side_by_triangle.hpp>
#include <boost/geometry/strategy/cartesian/side_by_triangle.hpp>
#include <boost/geometry/strategy/cartesian/side_robust.hpp>
#include <boost/geometry/strategies/spherical/ssf.hpp>
#include <boost/geometry/strategies/normalize.hpp>
@ -61,11 +62,11 @@ struct collected_vector
: nyi::not_implemented_tag
{};
// compatible with side_by_triangle cartesian strategy
// compatible with side_robust cartesian strategy
template <typename T, typename Geometry, typename CT, typename CSTag>
struct collected_vector
<
T, Geometry, strategy::side::side_by_triangle<CT>, CSTag
T, Geometry, strategy::side::side_robust<CT>, CSTag
>
{
typedef T type;
@ -156,6 +157,14 @@ private:
//T dx_0, dy_0;
};
template <typename T, typename Geometry, typename CT, typename CSTag>
struct collected_vector
<
T, Geometry, strategy::side::side_by_triangle<CT>, CSTag
>
: collected_vector<T, Geometry, strategy::side::side_robust<CT>, CSTag>
{};
// Compatible with spherical_side_formula which currently
// is the default spherical_equatorial and geographic strategy
// so CSTag is spherical_equatorial_tag or geographic_tag

View File

@ -0,0 +1,111 @@
// Boost.Geometry
// Copyright (c) 2021 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_CORE_COORDINATE_PROMOTION_HPP
#define BOOST_GEOMETRY_CORE_COORDINATE_PROMOTION_HPP
#include <boost/geometry/core/coordinate_type.hpp>
// TODO: move this to a future headerfile implementing traits for these types
#include <boost/rational.hpp>
#include <boost/multiprecision/cpp_bin_float.hpp>
#include <boost/multiprecision/cpp_int.hpp>
namespace boost { namespace geometry
{
namespace traits
{
// todo
} // namespace traits
/*!
\brief Meta-function converting, if necessary, to "a floating point" type
\details
- if input type is integer, type is double
- else type is input type
\ingroup utility
*/
// TODO: replace with, or call, promoted_to_floating_point
template <typename T, typename PromoteIntegerTo = double>
struct promote_floating_point
{
typedef std::conditional_t
<
std::is_integral<T>::value,
PromoteIntegerTo,
T
> type;
};
// TODO: replace with promoted_to_floating_point
template <typename Geometry>
struct fp_coordinate_type
{
typedef typename promote_floating_point
<
typename coordinate_type<Geometry>::type
>::type type;
};
namespace detail
{
// Promote any integral type to double. Floating point
// and other user defined types stay as they are, unless specialized.
// TODO: we shold add a coordinate_promotion traits for promotion to
// floating point or (larger) integer types.
template <typename Type>
struct promoted_to_floating_point
{
using type = std::conditional_t
<
std::is_integral<Type>::value, double, Type
>;
};
// Boost.Rational goes to double
template <typename T>
struct promoted_to_floating_point<boost::rational<T>>
{
using type = double;
};
// Any Boost.Multiprecision goes to double (for example int128_t),
// unless specialized
template <typename Backend>
struct promoted_to_floating_point<boost::multiprecision::number<Backend>>
{
using type = double;
};
// Boost.Multiprecision binary floating point numbers are used as FP.
template <unsigned Digits>
struct promoted_to_floating_point
<
boost::multiprecision::number
<
boost::multiprecision::cpp_bin_float<Digits>
>
>
{
using type = boost::multiprecision::number
<
boost::multiprecision::cpp_bin_float<Digits>
>;
};
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_CORE_COORDINATE_PROMOTION_HPP

View File

@ -22,7 +22,6 @@
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/static_assert.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/util/promote_floating_point.hpp>
#include <boost/geometry/util/type_traits_std.hpp>
@ -94,15 +93,6 @@ struct coordinate_type
>::type type;
};
template <typename Geometry>
struct fp_coordinate_type
{
typedef typename promote_floating_point
<
typename coordinate_type<Geometry>::type
>::type type;
};
/*!
\brief assert_coordinate_type_equal, a compile-time check for equality of two coordinate types
\ingroup utility

View File

@ -27,8 +27,7 @@
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/coordinate_promotion.hpp>
#include <boost/geometry/util/math.hpp>

View File

@ -5,8 +5,8 @@
// Copyright (c) 2009-2013 Mateusz Loskot, London, UK.
// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2020.
// Modifications copyright (c) 2020, Oracle and/or its affiliates.
// This file was modified by Oracle on 2020-2021.
// Modifications copyright (c) 2020-2021, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
@ -30,10 +30,9 @@
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/strategies/default_distance_result.hpp>
#include <boost/geometry/strategies/distance/cartesian.hpp>
#include <boost/geometry/strategies/cartesian/distance_pythagoras.hpp>
#include <boost/geometry/extensions/strategies/cartesian/distance_info.hpp>
#include <boost/geometry/util/math.hpp>

View File

@ -2,8 +2,8 @@
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2020.
// Modifications copyright (c) 2020, Oracle and/or its affiliates.
// This file was modified by Oracle on 2020-2021.
// Modifications copyright (c) 2020-2021, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
@ -31,7 +31,7 @@
#include <boost/config.hpp>
#include <boost/cstdint.hpp>
#include <boost/static_assert.hpp>
#include <boost/detail/endian.hpp>
#include <boost/predef/other/endian.h>
#if CHAR_BIT != 8
#error Platforms with CHAR_BIT != 8 are not supported
@ -50,10 +50,16 @@ namespace detail { namespace endian
struct big_endian_tag {};
struct little_endian_tag {};
#ifdef BOOST_BIG_ENDIAN
#if defined(BOOST_ENDIAN_BIG_BYTE_AVAILABLE)
typedef big_endian_tag native_endian_tag;
#else
#elif defined(BOOST_ENDIAN_LITTLE_BYTE_AVAILABLE)
typedef little_endian_tag native_endian_tag;
#elif defined(BOOST_ENDIAN_BIG_WORD_BYTE_AVAILABLE)
#error Word-swapped big-endian not supported
#elif defined(BOOST_ENDIAN_LITTLE_WORD_BYTE_AVAILABLE)
#error Word-swapped little-endian not supported
#else
#error Unknown endian memory ordering
#endif
// Unrolled loops for loading and storing streams of bytes.

View File

@ -1,50 +0,0 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_EXTENSIONS_NSPHERE_GEOMETRIES_CONCEPTS_CHECK_HPP
#define BOOST_GEOMETRY_EXTENSIONS_NSPHERE_GEOMETRIES_CONCEPTS_CHECK_HPP
#include <boost/geometry/geometries/concepts/check.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Geometry>
struct check<Geometry, nsphere_tag, true>
: detail::concept_check::check<concepts::ConstNsphere<Geometry> >
{};
template <typename Geometry>
struct check<Geometry, nsphere_tag, false>
: detail::concept_check::check<concepts::Nsphere<Geometry> >
{};
} // namespace dispatch
#endif
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_EXTENSIONS_NSPHERE_GEOMETRIES_CONCEPTS_CHECK_HPP

View File

@ -4,6 +4,10 @@
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2021.
// Modifications copyright (c) 2021, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@ -117,6 +121,18 @@ public :
};
template <typename Geometry>
struct concept_type<Geometry, nsphere_tag>
{
using type = Nsphere<Geometry>;
};
template <typename Geometry>
struct concept_type<Geometry const, nsphere_tag>
{
using type = ConstNsphere<Geometry>;
};
}}} // namespace boost::geometry::concepts

View File

@ -5,6 +5,10 @@
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// Copyright (c) 2011-2015 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2021.
// Modifications copyright (c) 2021, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@ -22,7 +26,6 @@
#include <boost/geometry/extensions/nsphere/core/tags.hpp>
#include <boost/geometry/extensions/nsphere/core/topological_dimension.hpp>
#include <boost/geometry/extensions/nsphere/geometries/concepts/check.hpp>
#include <boost/geometry/extensions/nsphere/geometries/concepts/nsphere_concept.hpp>
#include <boost/geometry/extensions/nsphere/geometries/nsphere.hpp>

View File

@ -0,0 +1,107 @@
// Boost.Geometry
// Copyright (c) 2021, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_INDEX_DETAIL_MAXMIN_HEAP_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_MAXMIN_HEAP_HPP
#include <boost/geometry/index/detail/minmax_heap.hpp>
namespace boost { namespace geometry { namespace index { namespace detail
{
template <typename It, typename Compare>
inline void push_maxmin_heap(It first, It last, Compare comp)
{
using namespace minmax_heap_detail;
minmax_heap_detail::push_heap<max_call, min_call>(first, last, comp);
}
template <typename It>
inline void push_maxmin_heap(It first, It last)
{
using namespace minmax_heap_detail;
minmax_heap_detail::push_heap<max_call, min_call>(first, last, std::less<>());
}
template <typename It, typename Compare>
inline void pop_top_maxmin_heap(It first, It last, Compare comp)
{
using namespace minmax_heap_detail;
pop_heap<max_call, min_call>(first, first, last, comp);
}
template <typename It>
inline void pop_top_maxmin_heap(It first, It last)
{
using namespace minmax_heap_detail;
pop_heap<max_call, min_call>(first, first, last, std::less<>());
}
template <typename It, typename Compare>
inline void pop_bottom_maxmin_heap(It first, It last, Compare comp)
{
using namespace minmax_heap_detail;
It bottom = minmax_heap_detail::bottom_heap<max_call>(first, last, comp);
pop_heap<max_call, min_call>(first, bottom, last, comp);
}
template <typename It>
inline void pop_bottom_maxmin_heap(It first, It last)
{
using namespace minmax_heap_detail;
auto&& comp = std::less<>();
It bottom = minmax_heap_detail::bottom_heap<max_call>(first, last, comp);
pop_heap<max_call, min_call>(first, bottom, last, comp);
}
template <typename It, typename Compare>
inline void make_maxmin_heap(It first, It last, Compare comp)
{
using namespace minmax_heap_detail;
return minmax_heap_detail::make_heap<max_call, min_call>(first, last, comp);
}
template <typename It>
inline void make_maxmin_heap(It first, It last)
{
using namespace minmax_heap_detail;
return minmax_heap_detail::make_heap<max_call, min_call>(first, last, std::less<>());
}
template <typename It, typename Compare>
inline bool is_maxmin_heap(It first, It last, Compare comp)
{
using namespace minmax_heap_detail;
return minmax_heap_detail::is_heap<max_call>(first, last, comp);
}
template <typename It>
inline bool is_maxmin_heap(It first, It last)
{
using namespace minmax_heap_detail;
return minmax_heap_detail::is_heap<max_call>(first, last, std::less<>());
}
template <typename It, typename Compare>
inline decltype(auto) bottom_maxmin_heap(It first, It last, Compare comp)
{
using namespace minmax_heap_detail;
return *minmax_heap_detail::bottom_heap<max_call>(first, last, comp);
}
template <typename It>
inline decltype(auto) bottom_maxmin_heap(It first, It last)
{
using namespace minmax_heap_detail;
return *minmax_heap_detail::bottom_heap<max_call>(first, last, std::less<>());
}
}}}} // namespace boost::geometry::index::detail
#endif // BOOST_GEOMETRY_INDEX_DETAIL_MAXMIN_HEAP_HPP

View File

@ -0,0 +1,519 @@
// Boost.Geometry
// Copyright (c) 2021, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_INDEX_DETAIL_MINMAX_HEAP_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_MINMAX_HEAP_HPP
#include <iterator>
#include <type_traits>
#include <utility>
#ifdef _MSC_VER // msvc and clang-win
#include <intrin.h>
#endif
namespace boost { namespace geometry { namespace index { namespace detail
{
// Resources:
// https://en.wikipedia.org/wiki/Min-max_heap
// http://akira.ruc.dk/~keld/teaching/algoritmedesign_f03/Artikler/02/Atkinson86.pdf
// https://probablydance.com/2020/08/31/on-modern-hardware-the-min-max-heap-beats-a-binary-heap/
// https://stackoverflow.com/questions/6531543/efficient-implementation-of-binary-heaps
// https://stackoverflow.com/questions/994593/how-to-do-an-integer-log2-in-c
namespace minmax_heap_detail
{
template <typename T>
using bitsize = std::integral_constant<std::size_t, sizeof(T) * CHAR_BIT>;
template <typename It>
using diff_t = typename std::iterator_traits<It>::difference_type;
template <typename It>
using val_t = typename std::iterator_traits<It>::value_type;
// TODO: In C++20 use std::bit_width()
template <typename T, std::enable_if_t<!std::is_integral<T>::value || (bitsize<T>::value != 32 && bitsize<T>::value != 64), int> = 0>
inline int level(T i)
{
++i;
int r = 0;
while (i >>= 1) { ++r; }
return r;
}
//template <typename T>
//inline int level(T i)
//{
// using std::log2;
// return int(log2(i + 1));
//}
#ifdef _MSC_VER // msvc and clang-win
template <typename T, std::enable_if_t<std::is_integral<T>::value && bitsize<T>::value == 32, int> = 0>
inline int level(T i)
{
unsigned long r = 0;
_BitScanReverse(&r, (unsigned long)(i + 1));
return int(r);
}
template <typename T, std::enable_if_t<std::is_integral<T>::value && bitsize<T>::value == 64, int> = 0>
inline int level(T i)
{
unsigned long r = 0;
#ifdef _WIN64
_BitScanReverse64(&r, (unsigned long long)(i + 1));
#else
if (_BitScanReverse(&r, (unsigned long)((i + 1) >> 32))) { r += 32; }
else { _BitScanReverse(&r, (unsigned long)(i + 1)); }
#endif
return int(r);
}
#elif defined(__clang__) || defined(__GNUC__)
// Only available in gcc-10 and clang-10
//#elif defined(__has_builtin) && __has_builtin(__builtin_clzl) && __has_builtin(__builtin_clzll)
template <typename T, std::enable_if_t<std::is_integral<T>::value && bitsize<T>::value == 32, int> = 0>
inline int level(T i)
{
return 31 - __builtin_clzl((unsigned long)(i + 1));
}
template <typename T, std::enable_if_t<std::is_integral<T>::value && bitsize<T>::value == 64, int> = 0>
inline int level(T i)
{
return 63 - __builtin_clzll((unsigned long long)(i + 1));
}
#else
template <typename T, std::enable_if_t<std::is_integral<T>::value && bitsize<T>::value == 32, int> = 0>
inline int level(T i)
{
++i;
int r = 0;
if (i >= 65536) { r += 16; i >>= 16; }
if (i >= 256) { r += 8; i >>= 8; }
if (i >= 16) { r += 4; i >>= 4; }
if (i >= 4) { r += 2; i >>= 2; }
if (i >= 2) { r += 1; i >>= 1; }
return r;
}
template <typename T, std::enable_if_t<std::is_integral<T>::value && bitsize<T>::value == 64, int> = 0>
inline int level(T i)
{
++i;
int r = 0;
if (i >= 4294967296ll) { r += 32; i >>= 32; }
if (i >= 65536ll) { r += 16; i >>= 16; }
if (i >= 256ll) { r += 8; i >>= 8; }
if (i >= 16ll) { r += 4; i >>= 4; }
if (i >= 4ll) { r += 2; i >>= 2; }
if (i >= 2ll) { r += 1; i >>= 1; }
return r;
}
#endif
// min/max functions only differ in the order of arguments in comp
struct min_call
{
template <typename Compare, typename T1, typename T2>
bool operator()(Compare&& comp, T1 const& v1, T2 const& v2) const
{
return comp(v1, v2);
}
};
struct max_call
{
template <typename Compare, typename T1, typename T2>
bool operator()(Compare&& comp, T1 const& v1, T2 const& v2) const
{
return comp(v2, v1);
}
};
template <typename Call, typename It, typename Compare>
inline void push_heap2(It first, diff_t<It> c, val_t<It> val, Compare comp)
{
while (c > 2)
{
diff_t<It> const g = (c - 3) >> 2; // grandparent index
if (! Call()(comp, val, *(first + g)))
{
break;
}
*(first + c) = std::move(*(first + g));
c = g;
}
*(first + c) = std::move(val);
}
template <typename MinCall, typename MaxCall, typename It, typename Compare>
inline void push_heap1(It first, diff_t<It> c, val_t<It> val, Compare comp)
{
diff_t<It> const p = (c - 1) >> 1; // parent index
if (MinCall()(comp, *(first + p), val))
{
*(first + c) = std::move(*(first + p));
return push_heap2<MaxCall>(first, p, std::move(val), comp);
}
else
{
return push_heap2<MinCall>(first, c, std::move(val), comp);
}
}
template <typename MinCall, typename MaxCall, typename It, typename Compare>
inline void push_heap(It first, It last, Compare comp)
{
diff_t<It> const size = last - first;
if (size < 2)
{
return;
}
diff_t<It> c = size - 1; // back index
val_t<It> val = std::move(*(first + c));
if (level(c) % 2 == 0) // is min level
{
push_heap1<MinCall, MaxCall>(first, c, std::move(val), comp);
}
else
{
push_heap1<MaxCall, MinCall>(first, c, std::move(val), comp);
}
}
template <typename Call, typename It, typename Compare>
inline diff_t<It> pick_grandchild4(It first, diff_t<It> f, Compare comp)
{
It it = first + f;
diff_t<It> m1 = Call()(comp, *(it), *(it + 1)) ? f : f + 1;
diff_t<It> m2 = Call()(comp, *(it + 2), *(it + 3)) ? f + 2 : f + 3;
return Call()(comp, *(first + m1), *(first + m2)) ? m1 : m2;
}
//template <typename Call, typename It, typename Compare>
//inline diff_t<It> pick_descendant(It first, diff_t<It> f, diff_t<It> l, Compare comp)
//{
// diff_t<It> m = f;
// for (++f; f != l; ++f)
// {
// if (Call()(comp, *(first + f), *(first + m)))
// {
// m = f;
// }
// }
// return m;
//}
template <typename Call, typename It, typename Compare>
inline void pop_heap1(It first, diff_t<It> p, diff_t<It> size, val_t<It> val, Compare comp)
{
if (size >= 7) // grandparent of 4 grandchildren is possible
{
diff_t<It> const last_g = (size - 3) >> 2; // grandparent of the element behind back
while (p < last_g) // p is grandparent of 4 grandchildren
{
diff_t<It> const ll = 4 * p + 3;
diff_t<It> const m = pick_grandchild4<Call>(first, ll, comp);
if (! Call()(comp, *(first + m), val))
{
break;
}
*(first + p) = std::move(*(first + m));
diff_t<It> par = (m - 1) >> 1;
if (Call()(comp, *(first + par), val))
{
using std::swap;
swap(*(first + par), val);
}
p = m;
}
}
if (size >= 2 && p <= ((size - 2) >> 1)) // at least one child
{
diff_t<It> const l = 2 * p + 1;
diff_t<It> m = l; // left child
if (size >= 3 && p <= ((size - 3) >> 1)) // at least two children
{
// m = left child
diff_t<It> m2 = l + 1; // right child
if (size >= 4 && p <= ((size - 4) >> 2)) // at least two children and one grandchild
{
diff_t<It> const ll = 2 * l + 1;
m = ll; // left most grandchild
// m2 = right child
if (size >= 5 && p <= ((size - 5) >> 2)) // at least two children and two grandchildren
{
m = Call()(comp, *(first + ll), *(first + ll + 1)) ? ll : (ll + 1); // greater of the left grandchildren
// m2 = right child
if (size >= 6 && p <= ((size - 6) >> 2)) // at least two children and three grandchildren
{
// m = greater of the left grandchildren
m2 = ll + 2; // third grandchild
}
}
}
m = Call()(comp, *(first + m), *(first + m2)) ? m : m2;
}
if (Call()(comp, *(first + m), val))
{
*(first + p) = std::move(*(first + m));
if (m >= 3 && p <= ((m - 3) >> 2)) // is p grandparent of m
{
diff_t<It> par = (m - 1) >> 1;
if (Call()(comp, *(first + par), val))
{
using std::swap;
swap(*(first + par), val);
}
}
p = m;
}
}
*(first + p) = std::move(val);
}
template <typename MinCall, typename MaxCall, typename It, typename Compare>
inline void pop_heap(It first, It el, It last, Compare comp)
{
diff_t<It> size = last - first;
if (size < 2)
{
return;
}
--last;
val_t<It> val = std::move(*last);
*last = std::move(*el);
// Ignore the last element
--size;
diff_t<It> p = el - first;
if (level(p) % 2 == 0) // is min level
{
pop_heap1<MinCall>(first, p, size, std::move(val), comp);
}
else
{
pop_heap1<MaxCall>(first, p, size, std::move(val), comp);
}
}
template <typename MinCall, typename MaxCall, typename It, typename Compare>
inline void make_heap(It first, It last, Compare comp)
{
diff_t<It> size = last - first;
diff_t<It> p = size / 2;
if (p <= 0)
{
return;
}
int level_p = level(p - 1);
diff_t<It> level_f = (diff_t<It>(1) << level_p) - 1;
while (p > 0)
{
--p;
val_t<It> val = std::move(*(first + p));
if (level_p % 2 == 0) // is min level
{
pop_heap1<MinCall>(first, p, size, std::move(val), comp);
}
else
{
pop_heap1<MaxCall>(first, p, size, std::move(val), comp);
}
if (p == level_f)
{
--level_p;
level_f >>= 1;
}
}
}
template <typename Call, typename It, typename Compare>
inline bool is_heap(It first, It last, Compare comp)
{
diff_t<It> const size = last - first;
diff_t<It> pow2 = 4;
bool is_min_level = false;
for (diff_t<It> i = 1; i < size; ++i)
{
if (i == pow2 - 1)
{
pow2 *= 2;
is_min_level = ! is_min_level;
}
diff_t<It> const p = (i - 1) >> 1;
if (is_min_level)
{
if (Call()(comp, *(first + p), *(first + i)))
{
return false;
}
}
else
{
if (Call()(comp, *(first + i), *(first + p)))
{
return false;
}
}
if (i >= 3)
{
diff_t<It> const g = (p - 1) >> 1;
if (is_min_level)
{
if (Call()(comp, *(first + i), *(first + g)))
{
return false;
}
}
else
{
if (Call()(comp, *(first + g), *(first + i)))
{
return false;
}
}
}
}
return true;
}
template <typename Call, typename It, typename Compare>
inline It bottom_heap(It first, It last, Compare comp)
{
diff_t<It> const size = last - first;
return size <= 1 ? first :
size == 2 ? (first + 1) :
Call()(comp, *(first + 1), *(first + 2)) ? (first + 2) : (first + 1);
}
} // namespace minmax_heap_detail
template <typename It, typename Compare>
inline void push_minmax_heap(It first, It last, Compare comp)
{
using namespace minmax_heap_detail;
minmax_heap_detail::push_heap<min_call, max_call>(first, last, comp);
}
template <typename It>
inline void push_minmax_heap(It first, It last)
{
using namespace minmax_heap_detail;
minmax_heap_detail::push_heap<min_call, max_call>(first, last, std::less<>());
}
template <typename It, typename Compare>
inline void pop_top_minmax_heap(It first, It last, Compare comp)
{
using namespace minmax_heap_detail;
pop_heap<min_call, max_call>(first, first, last, comp);
}
template <typename It>
inline void pop_top_minmax_heap(It first, It last)
{
using namespace minmax_heap_detail;
pop_heap<min_call, max_call>(first, first, last, std::less<>());
}
template <typename It, typename Compare>
inline void pop_bottom_minmax_heap(It first, It last, Compare comp)
{
using namespace minmax_heap_detail;
It bottom = minmax_heap_detail::bottom_heap<min_call>(first, last, comp);
pop_heap<min_call, max_call>(first, bottom, last, comp);
}
template <typename It>
inline void pop_bottom_minmax_heap(It first, It last)
{
using namespace minmax_heap_detail;
auto&& comp = std::less<>();
It bottom = minmax_heap_detail::bottom_heap<min_call>(first, last, comp);
pop_heap<min_call, max_call>(first, bottom, last, comp);
}
template <typename It, typename Compare>
inline void make_minmax_heap(It first, It last, Compare comp)
{
using namespace minmax_heap_detail;
return minmax_heap_detail::make_heap<min_call, max_call>(first, last, comp);
}
template <typename It>
inline void make_minmax_heap(It first, It last)
{
using namespace minmax_heap_detail;
return minmax_heap_detail::make_heap<min_call, max_call>(first, last, std::less<>());
}
template <typename It, typename Compare>
inline bool is_minmax_heap(It first, It last, Compare comp)
{
using namespace minmax_heap_detail;
return minmax_heap_detail::is_heap<min_call>(first, last, comp);
}
template <typename It>
inline bool is_minmax_heap(It first, It last)
{
using namespace minmax_heap_detail;
return minmax_heap_detail::is_heap<min_call>(first, last, std::less<>());
}
template <typename It, typename Compare>
inline decltype(auto) bottom_minmax_heap(It first, It last, Compare comp)
{
using namespace minmax_heap_detail;
return *minmax_heap_detail::bottom_heap<min_call>(first, last, comp);
}
template <typename It>
inline decltype(auto) bottom_minmax_heap(It first, It last)
{
using namespace minmax_heap_detail;
return *minmax_heap_detail::bottom_heap<min_call>(first, last, std::less<>());
}
}}}} // namespace boost::geometry::index::detail
#endif // BOOST_GEOMETRY_INDEX_DETAIL_MINMAX_HEAP_HPP

View File

@ -622,11 +622,13 @@ struct predicates_check_impl<std::tuple<Ts...>, Tag, First, Last>
}
};
template <typename Tag, std::size_t First, std::size_t Last, typename Predicates, typename Value, typename Indexable, typename Strategy>
template <typename Tag, typename Predicates, typename Value, typename Indexable, typename Strategy>
inline bool predicates_check(Predicates const& p, Value const& v, Indexable const& i, Strategy const& s)
{
return detail::predicates_check_impl<Predicates, Tag, First, Last>
::apply(p, v, i, s);
return detail::predicates_check_impl
<
Predicates, Tag, 0, predicates_length<Predicates>::value
>::apply(p, v, i, s);
}
// ------------------------------------------------------------------ //

View File

@ -0,0 +1,150 @@
// Boost.Geometry
// Copyright (c) 2021, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_INDEX_DETAIL_PRIORITY_DEQUEUE_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_PRIORITY_DEQUEUE_HPP
#include <vector>
#include <boost/geometry/index/detail/maxmin_heap.hpp>
namespace boost { namespace geometry { namespace index { namespace detail
{
template
<
typename T,
typename Container = std::vector<T>,
typename Compare = std::less<typename Container::value_type>
>
class priority_dequeue
{
public:
using container_type = Container;
using value_compare = Compare;
using value_type = typename Container::value_type;
using size_type = typename Container::size_type;
using reference = typename Container::reference;
using const_reference = typename Container::const_reference;
priority_dequeue()
: c(), comp()
{}
explicit priority_dequeue(Compare const& compare)
: c(), comp(compare)
{}
priority_dequeue(Compare const& compare, Container const& cont)
: c(cont), comp(compare)
{
make_maxmin_heap(c.begin(), c.end(), comp);
}
priority_dequeue(Compare const& compare, Container&& cont)
: c(std::move(cont)), comp(compare)
{
make_maxmin_heap(c.begin(), c.end(), comp);
}
template <typename It>
priority_dequeue(It first, It last)
: c(first, last), comp()
{
make_maxmin_heap(c.begin(), c.end(), comp);
}
template <typename It>
priority_dequeue(It first, It last, Compare const& compare)
: c(first, last), comp(compare)
{
make_maxmin_heap(c.begin(), c.end(), comp);
}
template <typename It>
priority_dequeue(It first, It last, Compare const& compare, Container const& cont)
: c(cont), comp(compare)
{
c.insert(first, last);
make_maxmin_heap(c.begin(), c.end(), comp);
}
template <typename It>
priority_dequeue(It first, It last, Compare const& compare, Container&& cont)
: c(std::move(cont)), comp(compare)
{
c.insert(first, last);
make_maxmin_heap(c.begin(), c.end(), comp);
}
const_reference top() const
{
return *c.begin();
}
const_reference bottom() const
{
return bottom_maxmin_heap(c.begin(), c.end(), comp);
}
void push(const value_type& value)
{
c.push_back(value);
push_maxmin_heap(c.begin(), c.end(), comp);
}
void push(value_type&& value)
{
c.push_back(std::move(value));
push_maxmin_heap(c.begin(), c.end(), comp);
}
template <typename ...Args>
void emplace(Args&& ...args)
{
c.emplace_back(std::forward<Args>(args)...);
push_maxmin_heap(c.begin(), c.end(), comp);
}
void pop_top()
{
pop_top_maxmin_heap(c.begin(), c.end(), comp);
c.pop_back();
}
void pop_bottom()
{
pop_bottom_maxmin_heap(c.begin(), c.end(), comp);
c.pop_back();
}
bool empty() const
{
return c.empty();
}
size_t size() const
{
return c.size();
}
void swap(priority_dequeue& other)
{
using std::swap;
std::swap(c, other.c);
std::swap(comp, other.comp);
}
protected:
Container c;
Compare comp;
};
}}}} // namespace boost::geometry::index::detail
#endif // BOOST_GEOMETRY_INDEX_DETAIL_PRIORITY_DEQUEUE_HPP

View File

@ -21,8 +21,6 @@
#include <boost/geometry/index/detail/rtree/visitors/distance_query.hpp>
#include <boost/geometry/index/detail/rtree/visitors/spatial_query.hpp>
//#define BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_MOVE
namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { namespace iterators {
template <typename Value, typename Allocators>
@ -69,13 +67,8 @@ struct end_query_iterator
template <typename MembersHolder, typename Predicates>
class spatial_query_iterator
{
typedef typename MembersHolder::parameters_type parameters_type;
typedef typename MembersHolder::translator_type translator_type;
typedef typename MembersHolder::allocators_type allocators_type;
typedef visitors::spatial_query_incremental<MembersHolder, Predicates> visitor_type;
typedef typename visitor_type::node_pointer node_pointer;
public:
typedef std::forward_iterator_tag iterator_category;
typedef typename MembersHolder::value_type value_type;
@ -83,32 +76,31 @@ public:
typedef typename allocators_type::difference_type difference_type;
typedef typename allocators_type::const_pointer pointer;
inline spatial_query_iterator()
spatial_query_iterator() = default;
explicit spatial_query_iterator(Predicates const& pred)
: m_impl(pred)
{}
inline spatial_query_iterator(parameters_type const& par, translator_type const& t, Predicates const& p)
: m_visitor(par, t, p)
{}
inline spatial_query_iterator(node_pointer root, parameters_type const& par, translator_type const& t, Predicates const& p)
: m_visitor(par, t, p)
spatial_query_iterator(MembersHolder const& members, Predicates const& pred)
: m_impl(members, pred)
{
m_visitor.initialize(root);
m_impl.initialize(members);
}
reference operator*() const
{
return m_visitor.dereference();
return m_impl.dereference();
}
const value_type * operator->() const
{
return boost::addressof(m_visitor.dereference());
return boost::addressof(m_impl.dereference());
}
spatial_query_iterator & operator++()
{
m_visitor.increment();
m_impl.increment();
return *this;
}
@ -121,33 +113,28 @@ public:
friend bool operator==(spatial_query_iterator const& l, spatial_query_iterator const& r)
{
return l.m_visitor == r.m_visitor;
return l.m_impl == r.m_impl;
}
friend bool operator==(spatial_query_iterator const& l, end_query_iterator<value_type, allocators_type> const& /*r*/)
{
return l.m_visitor.is_end();
return l.m_impl.is_end();
}
friend bool operator==(end_query_iterator<value_type, allocators_type> const& /*l*/, spatial_query_iterator const& r)
{
return r.m_visitor.is_end();
return r.m_impl.is_end();
}
private:
visitor_type m_visitor;
visitors::spatial_query_incremental<MembersHolder, Predicates> m_impl;
};
template <typename MembersHolder, typename Predicates, unsigned NearestPredicateIndex>
template <typename MembersHolder, typename Predicates>
class distance_query_iterator
{
typedef typename MembersHolder::parameters_type parameters_type;
typedef typename MembersHolder::translator_type translator_type;
typedef typename MembersHolder::allocators_type allocators_type;
typedef visitors::distance_query_incremental<MembersHolder, Predicates, NearestPredicateIndex> visitor_type;
typedef typename visitor_type::node_pointer node_pointer;
public:
typedef std::forward_iterator_tag iterator_category;
typedef typename MembersHolder::value_type value_type;
@ -155,32 +142,31 @@ public:
typedef typename allocators_type::difference_type difference_type;
typedef typename allocators_type::const_pointer pointer;
inline distance_query_iterator()
distance_query_iterator() = default;
explicit distance_query_iterator(Predicates const& pred)
: m_impl(pred)
{}
inline distance_query_iterator(parameters_type const& par, translator_type const& t, Predicates const& p)
: m_visitor(par, t, p)
{}
inline distance_query_iterator(node_pointer root, parameters_type const& par, translator_type const& t, Predicates const& p)
: m_visitor(par, t, p)
distance_query_iterator(MembersHolder const& members, Predicates const& pred)
: m_impl(members, pred)
{
m_visitor.initialize(root);
m_impl.initialize(members);
}
reference operator*() const
{
return m_visitor.dereference();
return m_impl.dereference();
}
const value_type * operator->() const
{
return boost::addressof(m_visitor.dereference());
return boost::addressof(m_impl.dereference());
}
distance_query_iterator & operator++()
{
m_visitor.increment();
m_impl.increment();
return *this;
}
@ -193,21 +179,21 @@ public:
friend bool operator==(distance_query_iterator const& l, distance_query_iterator const& r)
{
return l.m_visitor == r.m_visitor;
return l.m_impl == r.m_impl;
}
friend bool operator==(distance_query_iterator const& l, end_query_iterator<value_type, allocators_type> const& /*r*/)
{
return l.m_visitor.is_end();
return l.m_impl.is_end();
}
friend bool operator==(end_query_iterator<value_type, allocators_type> const& /*l*/, distance_query_iterator const& r)
{
return r.m_visitor.is_end();
return r.m_impl.is_end();
}
private:
visitor_type m_visitor;
visitors::distance_query_incremental<MembersHolder, Predicates> m_impl;
};
@ -284,8 +270,7 @@ public:
typedef typename Allocators::difference_type difference_type;
typedef typename Allocators::const_pointer pointer;
query_iterator()
{}
query_iterator() = default;
template <typename It>
query_iterator(It const& it)
@ -300,7 +285,6 @@ public:
: m_ptr(o.m_ptr.get() ? o.m_ptr->clone() : 0)
{}
#ifndef BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_MOVE
query_iterator & operator=(query_iterator const& o)
{
if ( this != boost::addressof(o) )
@ -309,12 +293,13 @@ public:
}
return *this;
}
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
query_iterator(query_iterator && o)
: m_ptr(0)
{
m_ptr.swap(o.m_ptr);
}
query_iterator & operator=(query_iterator && o)
{
if ( this != boost::addressof(o) )
@ -324,34 +309,6 @@ public:
}
return *this;
}
#endif
#else // !BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_MOVE
private:
BOOST_COPYABLE_AND_MOVABLE(query_iterator)
public:
query_iterator & operator=(BOOST_COPY_ASSIGN_REF(query_iterator) o)
{
if ( this != boost::addressof(o) )
{
m_ptr.reset(o.m_ptr.get() ? o.m_ptr->clone() : 0);
}
return *this;
}
query_iterator(BOOST_RV_REF(query_iterator) o)
: m_ptr(0)
{
m_ptr.swap(o.m_ptr);
}
query_iterator & operator=(BOOST_RV_REF(query_iterator) o)
{
if ( this != boost::addressof(o) )
{
m_ptr.swap(o.m_ptr);
o.m_ptr.reset();
}
return *this;
}
#endif // BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_MOVE
reference operator*() const
{

View File

@ -15,8 +15,11 @@
#ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_DISTANCE_QUERY_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_DISTANCE_QUERY_HPP
#include <queue>
#include <boost/geometry/index/detail/distance_predicates.hpp>
#include <boost/geometry/index/detail/predicates.hpp>
#include <boost/geometry/index/detail/priority_dequeue.hpp>
#include <boost/geometry/index/detail/rtree/node/node_elements.hpp>
#include <boost/geometry/index/detail/translator.hpp>
#include <boost/geometry/index/parameters.hpp>
@ -46,90 +49,114 @@ struct pair_first_greater
}
};
template <typename T, typename Comp>
struct priority_dequeue : index::detail::priority_dequeue<T, std::vector<T>, Comp>
{
priority_dequeue() = default;
//void reserve(typename std::vector<T>::size_type n)
//{
// this->c.reserve(n);
//}
//void clear()
//{
// this->c.clear();
//}
};
template <typename Value, typename Translator, typename DistanceType, typename OutIt>
template <typename T, typename Comp>
struct priority_queue : std::priority_queue<T, std::vector<T>, Comp>
{
priority_queue() = default;
//void reserve(typename std::vector<T>::size_type n)
//{
// this->c.reserve(n);
//}
void clear()
{
this->c.clear();
}
};
struct branch_data_comp
{
template <typename BranchData>
bool operator()(BranchData const& b1, BranchData const& b2) const
{
return b1.distance > b2.distance || (b1.distance == b2.distance && b1.reverse_level > b2.reverse_level);
}
};
template <typename DistanceType, typename Value>
class distance_query_result
{
using neighbor_data = std::pair<DistanceType, const Value *>;
using neighbors_type = std::vector<neighbor_data>;
using size_type = typename neighbors_type::size_type;
public:
typedef DistanceType distance_type;
inline explicit distance_query_result(size_t k, OutIt out_it)
: m_count(k), m_out_it(out_it)
inline distance_query_result(size_type k)
: m_count(k)
{
BOOST_GEOMETRY_INDEX_ASSERT(0 < m_count, "Number of neighbors should be greater than 0");
m_neighbors.reserve(m_count);
}
inline void store(Value const& val, distance_type const& curr_comp_dist)
// NOTE: Do not call if max_count() == 0
inline void store(DistanceType const& distance, const Value * value_ptr)
{
if ( m_neighbors.size() < m_count )
if (m_neighbors.size() < m_count)
{
m_neighbors.push_back(std::make_pair(curr_comp_dist, val));
m_neighbors.push_back(std::make_pair(distance, value_ptr));
if ( m_neighbors.size() == m_count )
std::make_heap(m_neighbors.begin(), m_neighbors.end(), pair_first_less());
}
else
{
if ( curr_comp_dist < m_neighbors.front().first )
if (m_neighbors.size() == m_count)
{
std::pop_heap(m_neighbors.begin(), m_neighbors.end(), pair_first_less());
m_neighbors.back().first = curr_comp_dist;
m_neighbors.back().second = val;
std::push_heap(m_neighbors.begin(), m_neighbors.end(), pair_first_less());
std::make_heap(m_neighbors.begin(), m_neighbors.end(), pair_first_less());
}
}
else if (distance < m_neighbors.front().first)
{
std::pop_heap(m_neighbors.begin(), m_neighbors.end(), pair_first_less());
m_neighbors.back().first = distance;
m_neighbors.back().second = value_ptr;
std::push_heap(m_neighbors.begin(), m_neighbors.end(), pair_first_less());
}
}
inline bool has_enough_neighbors() const
// NOTE: Do not call if max_count() == 0
inline bool ignore_branch(DistanceType const& distance) const
{
return m_count <= m_neighbors.size();
return m_neighbors.size() == m_count
&& m_neighbors.front().first <= distance;
}
inline distance_type greatest_comparable_distance() const
template <typename OutIt>
inline size_type finish(OutIt out_it) const
{
// greatest distance is in the first neighbor only
// if there is at least m_count values found
// this is just for safety reasons since is_comparable_distance_valid() is checked earlier
// TODO - may be replaced by ASSERT
return m_neighbors.size() < m_count
? (std::numeric_limits<distance_type>::max)()
: m_neighbors.front().first;
}
inline size_t finish()
{
typedef typename std::vector< std::pair<distance_type, Value> >::const_iterator neighbors_iterator;
for ( neighbors_iterator it = m_neighbors.begin() ; it != m_neighbors.end() ; ++it, ++m_out_it )
*m_out_it = it->second;
for (auto const& p : m_neighbors)
{
*out_it = *(p.second);
++out_it;
}
return m_neighbors.size();
}
private:
size_t m_count;
OutIt m_out_it;
size_type max_count() const
{
return m_count;
}
std::vector< std::pair<distance_type, Value> > m_neighbors;
private:
size_type m_count;
neighbors_type m_neighbors;
};
template
<
typename MembersHolder,
typename Predicates,
std::size_t DistancePredicateIndex,
typename OutIter
>
template <typename MembersHolder, typename Predicates>
class distance_query
: public MembersHolder::visitor_const
{
public:
typedef typename MembersHolder::value_type value_type;
typedef typename MembersHolder::box_type box_type;
typedef typename MembersHolder::parameters_type parameters_type;
typedef typename MembersHolder::translator_type translator_type;
typedef typename MembersHolder::allocators_type allocators_type;
typedef typename index::detail::strategy_type<parameters_type>::type strategy_type;
@ -137,7 +164,10 @@ public:
typedef typename MembersHolder::internal_node internal_node;
typedef typename MembersHolder::leaf leaf;
typedef index::detail::predicates_element<DistancePredicateIndex, Predicates> nearest_predicate_access;
typedef index::detail::predicates_element
<
index::detail::predicates_find_distance<Predicates>::value, Predicates
> nearest_predicate_access;
typedef typename nearest_predicate_access::type nearest_predicate_type;
typedef typename indexable_type<translator_type>::type indexable_type;
@ -146,147 +176,141 @@ public:
typedef typename calculate_value_distance::result_type value_distance_type;
typedef typename calculate_node_distance::result_type node_distance_type;
static const std::size_t predicates_len = index::detail::predicates_length<Predicates>::value;
typedef typename MembersHolder::size_type size_type;
typedef typename MembersHolder::node_pointer node_pointer;
inline distance_query(parameters_type const& parameters, translator_type const& translator, Predicates const& pred, OutIter out_it)
: m_parameters(parameters), m_translator(translator)
using neighbor_data = std::pair<value_distance_type, const value_type *>;
using neighbors_type = std::vector<neighbor_data>;
struct branch_data
{
branch_data(node_distance_type d, size_type rl, node_pointer p)
: distance(d), reverse_level(rl), ptr(p)
{}
node_distance_type distance;
size_type reverse_level;
node_pointer ptr;
};
using branches_type = priority_queue<branch_data, branch_data_comp>;
public:
distance_query(MembersHolder const& members, Predicates const& pred)
: m_tr(members.translator())
, m_strategy(index::detail::get_strategy(members.parameters()))
, m_pred(pred)
, m_result(nearest_predicate_access::get(m_pred).count, out_it)
, m_strategy(index::detail::get_strategy(parameters))
{}
inline void operator()(internal_node const& n)
{
typedef typename rtree::elements_type<internal_node>::type elements_type;
// array of active nodes
typedef typename index::detail::rtree::container_from_elements_type<
elements_type,
std::pair<node_distance_type, typename allocators_type::node_pointer>
>::type active_branch_list_type;
active_branch_list_type active_branch_list;
active_branch_list.reserve(m_parameters.get_max_elements());
elements_type const& elements = rtree::elements(n);
// fill array of nodes meeting predicates
for (typename elements_type::const_iterator it = elements.begin();
it != elements.end(); ++it)
{
// if current node meets predicates
// 0 - dummy value
if ( index::detail::predicates_check
<
index::detail::bounds_tag, 0, predicates_len
>(m_pred, 0, it->first, m_strategy) )
{
// calculate node's distance(s) for distance predicate
node_distance_type node_distance;
// if distance isn't ok - move to the next node
if ( !calculate_node_distance::apply(predicate(), it->first,
m_strategy, node_distance) )
{
continue;
}
// if current node is further than found neighbors - don't analyze it
if ( m_result.has_enough_neighbors() &&
is_node_prunable(m_result.greatest_comparable_distance(), node_distance) )
{
continue;
}
// add current node's data into the list
active_branch_list.push_back( std::make_pair(node_distance, it->second) );
}
}
// if there aren't any nodes in ABL - return
if ( active_branch_list.empty() )
return;
// sort array
std::sort(active_branch_list.begin(), active_branch_list.end(), pair_first_less());
// recursively visit nodes
for ( typename active_branch_list_type::const_iterator it = active_branch_list.begin();
it != active_branch_list.end() ; ++it )
{
// if current node is further than furthest neighbor, the rest of nodes also will be further
if ( m_result.has_enough_neighbors() &&
is_node_prunable(m_result.greatest_comparable_distance(), it->first) )
break;
rtree::apply_visitor(*this, *(it->second));
}
// ALTERNATIVE VERSION - use heap instead of sorted container
// It seems to be faster for greater MaxElements and slower otherwise
// CONSIDER: using one global container/heap for active branches
// instead of a sorted container per level
// This would also change the way how branches are traversed!
// The same may be applied to the iterative version which btw suffers
// from the copying of the whole containers on resize of the ABLs container
//// make a heap
//std::make_heap(active_branch_list.begin(), active_branch_list.end(), pair_first_greater());
//// recursively visit nodes
//while ( !active_branch_list.empty() )
//{
// //if current node is further than furthest neighbor, the rest of nodes also will be further
// if ( m_result.has_enough_neighbors()
// && is_node_prunable(m_result.greatest_comparable_distance(), active_branch_list.front().first) )
// {
// break;
// }
// rtree::apply_visitor(*this, *(active_branch_list.front().second));
// std::pop_heap(active_branch_list.begin(), active_branch_list.end(), pair_first_greater());
// active_branch_list.pop_back();
//}
m_neighbors.reserve((std::min)(members.values_count, size_type(max_count())));
//m_branches.reserve(members.parameters().get_min_elements() * members.leafs_level); ?
// min, max or average?
}
inline void operator()(leaf const& n)
template <typename OutIter>
size_type apply(MembersHolder const& members, OutIter out_it)
{
typedef typename rtree::elements_type<leaf>::type elements_type;
elements_type const& elements = rtree::elements(n);
// search leaf for closest value meeting predicates
for (typename elements_type::const_iterator it = elements.begin();
it != elements.end(); ++it)
{
// if value meets predicates
if ( index::detail::predicates_check
<
index::detail::value_tag, 0, predicates_len
>(m_pred, *it, m_translator(*it), m_strategy) )
{
// calculate values distance for distance predicate
value_distance_type value_distance;
// if distance is ok
if ( calculate_value_distance::apply(predicate(), m_translator(*it),
m_strategy, value_distance) )
{
// store value
m_result.store(*it, value_distance);
}
}
}
}
inline size_t finish()
{
return m_result.finish();
return apply(members.root, members.leafs_level, out_it);
}
private:
template <typename Distance>
static inline bool is_node_prunable(Distance const& greatest_dist, node_distance_type const& d)
template <typename OutIter>
size_type apply(node_pointer ptr, size_type reverse_level, OutIter out_it)
{
return greatest_dist <= d;
namespace id = index::detail;
if (max_count() <= 0)
{
return 0;
}
for (;;)
{
if (reverse_level > 0)
{
internal_node& n = rtree::get<internal_node>(*ptr);
// fill array of nodes meeting predicates
for (auto const& p : rtree::elements(n))
{
node_distance_type node_distance; // for distance predicate
// if current node meets predicates (0 is dummy value)
if (id::predicates_check<id::bounds_tag>(m_pred, 0, p.first, m_strategy)
// and if distance is ok
&& calculate_node_distance::apply(predicate(), p.first, m_strategy, node_distance)
// and if current node is closer than the furthest neighbor
&& ! ignore_branch(node_distance))
{
// add current node's data into the list
m_branches.push(branch_data(node_distance, reverse_level - 1, p.second));
}
}
}
else
{
leaf& n = rtree::get<leaf>(*ptr);
// search leaf for closest value meeting predicates
for (auto const& v : rtree::elements(n))
{
value_distance_type value_distance; // for distance predicate
// if value meets predicates
if (id::predicates_check<id::value_tag>(m_pred, v, m_tr(v), m_strategy)
// and if distance is ok
&& calculate_value_distance::apply(predicate(), m_tr(v), m_strategy, value_distance))
{
// store value
store_value(value_distance, boost::addressof(v));
}
}
}
if (m_branches.empty()
|| ignore_branch(m_branches.top().distance))
{
break;
}
ptr = m_branches.top().ptr;
reverse_level = m_branches.top().reverse_level;
m_branches.pop();
}
for (auto const& p : m_neighbors)
{
*out_it = *(p.second);
++out_it;
}
return m_neighbors.size();
}
bool ignore_branch(node_distance_type const& node_distance) const
{
return m_neighbors.size() == max_count()
&& m_neighbors.front().first <= node_distance;
}
void store_value(value_distance_type value_distance, const value_type * value_ptr)
{
if (m_neighbors.size() < max_count())
{
m_neighbors.push_back(std::make_pair(value_distance, value_ptr));
if (m_neighbors.size() == max_count())
{
std::make_heap(m_neighbors.begin(), m_neighbors.end(), pair_first_less());
}
}
else if (value_distance < m_neighbors.front().first)
{
std::pop_heap(m_neighbors.begin(), m_neighbors.end(), pair_first_less());
m_neighbors.back() = std::make_pair(value_distance, value_ptr);
std::push_heap(m_neighbors.begin(), m_neighbors.end(), pair_first_less());
}
}
std::size_t max_count() const
{
return nearest_predicate_access::get(m_pred).count;
}
nearest_predicate_type const& predicate() const
@ -294,24 +318,18 @@ private:
return nearest_predicate_access::get(m_pred);
}
parameters_type const& m_parameters;
translator_type const& m_translator;
Predicates m_pred;
distance_query_result<value_type, translator_type, value_distance_type, OutIter> m_result;
translator_type const& m_tr;
strategy_type m_strategy;
Predicates const& m_pred;
branches_type m_branches;
neighbors_type m_neighbors;
};
template <
typename MembersHolder,
typename Predicates,
std::size_t DistancePredicateIndex
>
template <typename MembersHolder, typename Predicates>
class distance_query_incremental
: public MembersHolder::visitor_const
{
public:
typedef typename MembersHolder::value_type value_type;
typedef typename MembersHolder::box_type box_type;
typedef typename MembersHolder::parameters_type parameters_type;
@ -324,7 +342,10 @@ public:
typedef typename MembersHolder::internal_node internal_node;
typedef typename MembersHolder::leaf leaf;
typedef index::detail::predicates_element<DistancePredicateIndex, Predicates> nearest_predicate_access;
typedef index::detail::predicates_element
<
index::detail::predicates_find_distance<Predicates>::value, Predicates
> nearest_predicate_access;
typedef typename nearest_predicate_access::type nearest_predicate_type;
typedef typename indexable_type<translator_type>::type indexable_type;
@ -337,90 +358,114 @@ public:
typedef typename allocators_type::const_reference const_reference;
typedef typename allocators_type::node_pointer node_pointer;
static const std::size_t predicates_len = index::detail::predicates_length<Predicates>::value;
typedef typename rtree::elements_type<internal_node>::type internal_elements;
typedef typename internal_elements::const_iterator internal_iterator;
typedef typename rtree::elements_type<leaf>::type leaf_elements;
typedef std::pair<node_distance_type, node_pointer> branch_data;
typedef std::vector<branch_data> internal_heap_type;
using neighbor_data = std::pair<value_distance_type, const value_type *>;
using neighbors_type = priority_dequeue<neighbor_data, pair_first_greater>;
struct branch_data
{
branch_data(node_distance_type d, size_type rl, node_pointer p)
: distance(d), reverse_level(rl), ptr(p)
{}
node_distance_type distance;
size_type reverse_level;
node_pointer ptr;
};
using branches_type = priority_queue<branch_data, branch_data_comp>;
public:
inline distance_query_incremental()
: m_translator(NULL)
: m_tr(nullptr)
// , m_strategy()
// , m_pred()
, current_neighbor((std::numeric_limits<size_type>::max)())
// , m_strategy_type()
, m_neighbors_count(0)
, m_neighbor_ptr(nullptr)
{}
inline distance_query_incremental(parameters_type const& params, translator_type const& translator, Predicates const& pred)
: m_translator(::boost::addressof(translator))
inline distance_query_incremental(Predicates const& pred)
: m_tr(nullptr)
// , m_strategy()
, m_pred(pred)
, current_neighbor((std::numeric_limits<size_type>::max)())
, m_strategy(index::detail::get_strategy(params))
{
BOOST_GEOMETRY_INDEX_ASSERT(0 < max_count(), "k must be greather than 0");
}
, m_neighbors_count(0)
, m_neighbor_ptr(nullptr)
{}
inline distance_query_incremental(MembersHolder const& members, Predicates const& pred)
: m_tr(::boost::addressof(members.translator()))
, m_strategy(index::detail::get_strategy(members.parameters()))
, m_pred(pred)
, m_neighbors_count(0)
, m_neighbor_ptr(nullptr)
{}
const_reference dereference() const
{
return *(neighbors[current_neighbor].second);
return *m_neighbor_ptr;
}
void initialize(node_pointer root)
void initialize(MembersHolder const& members)
{
rtree::apply_visitor(*this, *root);
increment();
if (0 < max_count())
{
apply(members.root, members.leafs_level);
increment();
}
}
void increment()
{
for (;;)
{
size_type new_neighbor = current_neighbor == (std::numeric_limits<size_type>::max)() ? 0 : current_neighbor + 1;
if ( internal_heap.empty() )
if (m_branches.empty())
{
if ( new_neighbor < neighbors.size() )
current_neighbor = new_neighbor;
// there exists a next closest neighbor so we can increment
if (! m_neighbors.empty())
{
m_neighbor_ptr = m_neighbors.top().second;
++m_neighbors_count;
m_neighbors.pop_top();
}
else
{
current_neighbor = (std::numeric_limits<size_type>::max)();
// clear() is used to disable the condition above
neighbors.clear();
// there aren't any neighbors left, end
m_neighbor_ptr = nullptr;
m_neighbors_count = max_count();
}
return;
}
else
{
branch_data const& closest_branch = internal_heap.front();
node_distance_type const& closest_distance = closest_branch.first;
branch_data const& closest_branch = m_branches.top();
// if there are no nodes which can have closer values, set new value
if ( new_neighbor < neighbors.size() &&
// NOTE: In order to use <= current neighbor can't be sorted again
neighbors[new_neighbor].first <= closest_distance )
// if next neighbor is closer or as close as the closest branch, set next neighbor
if (! m_neighbors.empty() && m_neighbors.top().first <= closest_branch.distance )
{
current_neighbor = new_neighbor;
m_neighbor_ptr = m_neighbors.top().second;
++m_neighbors_count;
m_neighbors.pop_top();
return;
}
// if node is further than the furthest neighbor, following nodes will also be further
BOOST_GEOMETRY_INDEX_ASSERT(neighbors.size() <= max_count(), "unexpected neighbors count");
if ( max_count() <= neighbors.size() &&
neighbors.back().first <= closest_distance )
BOOST_GEOMETRY_INDEX_ASSERT(m_neighbors_count + m_neighbors.size() <= max_count(), "unexpected neighbors count");
// if there is enough neighbors and there is no closer branch
if (ignore_branch_or_value(closest_branch.distance))
{
internal_heap.clear();
m_branches.clear();
continue;
}
else
{
node_pointer ptr = closest_branch.second;
std::pop_heap(internal_heap.begin(), internal_heap.end(), pair_first_greater());
internal_heap.pop_back();
node_pointer ptr = closest_branch.ptr;
size_type reverse_level = closest_branch.reverse_level;
m_branches.pop();
rtree::apply_visitor(*this, *ptr);
apply(ptr, reverse_level);
}
}
}
@ -428,112 +473,80 @@ public:
bool is_end() const
{
return (std::numeric_limits<size_type>::max)() == current_neighbor;
return m_neighbor_ptr == nullptr;
}
friend bool operator==(distance_query_incremental const& l, distance_query_incremental const& r)
{
BOOST_GEOMETRY_INDEX_ASSERT(l.current_neighbor != r.current_neighbor ||
(std::numeric_limits<size_type>::max)() == l.current_neighbor ||
(std::numeric_limits<size_type>::max)() == r.current_neighbor ||
l.neighbors[l.current_neighbor].second == r.neighbors[r.current_neighbor].second,
"not corresponding iterators");
return l.current_neighbor == r.current_neighbor;
return l.m_neighbors_count == r.m_neighbors_count;
}
// Put node's elements into the list of active branches if those elements meets predicates
// and distance predicates(currently not used)
// and aren't further than found neighbours (if there is enough neighbours)
inline void operator()(internal_node const& n)
private:
void apply(node_pointer ptr, size_type reverse_level)
{
typedef typename rtree::elements_type<internal_node>::type elements_type;
elements_type const& elements = rtree::elements(n);
// fill active branch list array of nodes meeting predicates
for ( typename elements_type::const_iterator it = elements.begin() ; it != elements.end() ; ++it )
namespace id = index::detail;
// Put node's elements into the list of active branches if those elements meets predicates
// and distance predicates(currently not used)
// and aren't further than found neighbours (if there is enough neighbours)
if (reverse_level > 0)
{
// if current node meets predicates
// 0 - dummy value
if ( index::detail::predicates_check
<
index::detail::bounds_tag, 0, predicates_len
>(m_pred, 0, it->first, m_strategy) )
internal_node& n = rtree::get<internal_node>(*ptr);
// fill active branch list array of nodes meeting predicates
for (auto const& p : rtree::elements(n))
{
// calculate node's distance(s) for distance predicate
node_distance_type node_distance;
// if distance isn't ok - move to the next node
if ( !calculate_node_distance::apply(predicate(), it->first,
m_strategy, node_distance) )
{
continue;
}
node_distance_type node_distance; // for distance predicate
// if current node is further than found neighbors - don't analyze it
if ( max_count() <= neighbors.size() &&
neighbors.back().first <= node_distance )
// if current node meets predicates (0 is dummy value)
if (id::predicates_check<id::bounds_tag>(m_pred, 0, p.first, m_strategy)
// and if distance is ok
&& calculate_node_distance::apply(predicate(), p.first, m_strategy, node_distance)
// and if current node is closer than the furthest neighbor
&& ! ignore_branch_or_value(node_distance))
{
continue;
// add current node into the queue
m_branches.push(branch_data(node_distance, reverse_level - 1, p.second));
}
// add current node's data into the queue
internal_heap.push_back(std::make_pair(node_distance, it->second));
std::push_heap(internal_heap.begin(), internal_heap.end(), pair_first_greater());
}
}
}
// Put values into the list of neighbours if those values meets predicates
// and distance predicates(currently not used)
// and aren't further than already found neighbours (if there is enough neighbours)
inline void operator()(leaf const& n)
{
typedef typename rtree::elements_type<leaf>::type elements_type;
elements_type const& elements = rtree::elements(n);
// store distance to the furthest neighbour
bool not_enough_neighbors = neighbors.size() < max_count();
value_distance_type greatest_distance = !not_enough_neighbors ? neighbors.back().first : (std::numeric_limits<value_distance_type>::max)();
// search leaf for closest value meeting predicates
for ( typename elements_type::const_iterator it = elements.begin() ; it != elements.end() ; ++it)
// Put values into the list of neighbours if those values meets predicates
// and distance predicates(currently not used)
// and aren't further than already found neighbours (if there is enough neighbours)
else
{
// if value meets predicates
if ( index::detail::predicates_check
<
index::detail::value_tag, 0, predicates_len
>(m_pred, *it, (*m_translator)(*it), m_strategy) )
leaf& n = rtree::get<leaf>(*ptr);
// search leaf for closest value meeting predicates
for (auto const& v : rtree::elements(n))
{
// calculate values distance for distance predicate
value_distance_type value_distance;
// if distance is ok
if ( calculate_value_distance::apply(predicate(), (*m_translator)(*it),
m_strategy, value_distance) )
value_distance_type value_distance; // for distance predicate
// if value meets predicates
if (id::predicates_check<id::value_tag>(m_pred, v, (*m_tr)(v), m_strategy)
// and if distance is ok
&& calculate_value_distance::apply(predicate(), (*m_tr)(v), m_strategy, value_distance)
// and if current value is closer than the furthest neighbor
&& ! ignore_branch_or_value(value_distance))
{
// if there is not enough values or current value is closer than furthest neighbour
if ( not_enough_neighbors || value_distance < greatest_distance )
// add current value into the queue
m_neighbors.push(std::make_pair(value_distance, boost::addressof(v)));
// remove unneeded value
if (m_neighbors_count + m_neighbors.size() > max_count())
{
neighbors.push_back(std::make_pair(value_distance, boost::addressof(*it)));
m_neighbors.pop_bottom();
}
}
}
}
// TODO: sort is probably suboptimal.
// An alternative would be std::set, but it'd probably add constant cost.
// Ideally replace this with double-ended priority queue, e.g. min-max heap.
// NOTE: A condition in increment() relies on the fact that current neighbor doesn't
// participate in sorting anymore.
// sort array
size_type sort_first = current_neighbor == (std::numeric_limits<size_type>::max)() ? 0 : current_neighbor + 1;
std::sort(neighbors.begin() + sort_first, neighbors.end(), pair_first_less());
// remove furthest values
if ( max_count() < neighbors.size() )
neighbors.resize(max_count());
}
private:
inline std::size_t max_count() const
template <typename Distance>
bool ignore_branch_or_value(Distance const& distance)
{
return m_neighbors_count + m_neighbors.size() == max_count()
&& (m_neighbors.empty() || m_neighbors.bottom().first <= distance);
}
std::size_t max_count() const
{
return nearest_predicate_access::get(m_pred).count;
}
@ -543,15 +556,15 @@ private:
return nearest_predicate_access::get(m_pred);
}
const translator_type * m_translator;
const translator_type * m_tr;
strategy_type m_strategy;
Predicates m_pred;
internal_heap_type internal_heap;
std::vector< std::pair<value_distance_type, const value_type *> > neighbors;
size_type current_neighbor;
strategy_type m_strategy;
branches_type m_branches;
neighbors_type m_neighbors;
size_type m_neighbors_count;
const value_type * m_neighbor_ptr;
};
}}} // namespace detail::rtree::visitors

View File

@ -25,7 +25,6 @@ namespace detail { namespace rtree { namespace visitors {
template <typename MembersHolder, typename Predicates, typename OutIter>
struct spatial_query
: public MembersHolder::visitor_const
{
typedef typename MembersHolder::parameters_type parameters_type;
typedef typename MembersHolder::translator_type translator_type;
@ -37,71 +36,69 @@ struct spatial_query
typedef typename MembersHolder::internal_node internal_node;
typedef typename MembersHolder::leaf leaf;
typedef typename allocators_type::node_pointer node_pointer;
typedef typename allocators_type::size_type size_type;
static const std::size_t predicates_len = index::detail::predicates_length<Predicates>::value;
inline spatial_query(parameters_type const& par, translator_type const& t, Predicates const& p, OutIter out_it)
: tr(t), pred(p), out_iter(out_it), found_count(0), strategy(index::detail::get_strategy(par))
spatial_query(MembersHolder const& members, Predicates const& p, OutIter out_it)
: m_tr(members.translator())
, m_strategy(index::detail::get_strategy(members.parameters()))
, m_pred(p)
, m_out_iter(out_it)
, m_found_count(0)
{}
inline void operator()(internal_node const& n)
size_type apply(node_pointer ptr, size_type reverse_level)
{
typedef typename rtree::elements_type<internal_node>::type elements_type;
elements_type const& elements = rtree::elements(n);
// traverse nodes meeting predicates
for (typename elements_type::const_iterator it = elements.begin();
it != elements.end(); ++it)
namespace id = index::detail;
if (reverse_level > 0)
{
// if node meets predicates
// 0 - dummy value
if ( index::detail::predicates_check
<
index::detail::bounds_tag, 0, predicates_len
>(pred, 0, it->first, strategy) )
internal_node& n = rtree::get<internal_node>(*ptr);
// traverse nodes meeting predicates
for (auto const& p : rtree::elements(n))
{
rtree::apply_visitor(*this, *it->second);
// if node meets predicates (0 is dummy value)
if (id::predicates_check<id::bounds_tag>(m_pred, 0, p.first, m_strategy))
{
apply(p.second, reverse_level - 1);
}
}
}
}
inline void operator()(leaf const& n)
{
typedef typename rtree::elements_type<leaf>::type elements_type;
elements_type const& elements = rtree::elements(n);
// get all values meeting predicates
for (typename elements_type::const_iterator it = elements.begin();
it != elements.end(); ++it)
else
{
// if value meets predicates
if ( index::detail::predicates_check
<
index::detail::value_tag, 0, predicates_len
>(pred, *it, tr(*it), strategy) )
leaf& n = rtree::get<leaf>(*ptr);
// get all values meeting predicates
for (auto const& v : rtree::elements(n))
{
*out_iter = *it;
++out_iter;
++found_count;
// if value meets predicates
if (id::predicates_check<id::value_tag>(m_pred, v, m_tr(v), m_strategy))
{
*m_out_iter = v;
++m_out_iter;
++m_found_count;
}
}
}
return m_found_count;
}
translator_type const& tr;
size_type apply(MembersHolder const& members)
{
return apply(members.root, members.leafs_level);
}
Predicates pred;
private:
translator_type const& m_tr;
strategy_type m_strategy;
OutIter out_iter;
size_type found_count;
Predicates const& m_pred;
OutIter m_out_iter;
strategy_type strategy;
size_type m_found_count;
};
template <typename MembersHolder, typename Predicates>
class spatial_query_incremental
: public MembersHolder::visitor_const
{
typedef typename MembersHolder::value_type value_type;
typedef typename MembersHolder::parameters_type parameters_type;
@ -110,7 +107,6 @@ class spatial_query_incremental
typedef typename index::detail::strategy_type<parameters_type>::type strategy_type;
public:
typedef typename MembersHolder::node node;
typedef typename MembersHolder::internal_node internal_node;
typedef typename MembersHolder::leaf leaf;
@ -123,37 +119,40 @@ public:
typedef typename rtree::elements_type<leaf>::type leaf_elements;
typedef typename rtree::elements_type<leaf>::type::const_iterator leaf_iterator;
static const std::size_t predicates_len = index::detail::predicates_length<Predicates>::value;
struct internal_data
{
internal_data(internal_iterator f, internal_iterator l, size_type rl)
: first(f), last(l), reverse_level(rl)
{}
internal_iterator first;
internal_iterator last;
size_type reverse_level;
};
inline spatial_query_incremental()
: m_translator(NULL)
// , m_pred()
, m_values(NULL)
, m_current()
public:
spatial_query_incremental()
: m_translator(nullptr)
// , m_strategy()
{}
inline spatial_query_incremental(parameters_type const& params, translator_type const& t, Predicates const& p)
: m_translator(::boost::addressof(t))
, m_pred(p)
, m_values(NULL)
// , m_pred()
, m_values(nullptr)
, m_current()
, m_strategy(index::detail::get_strategy(params))
{}
inline void operator()(internal_node const& n)
{
typedef typename rtree::elements_type<internal_node>::type elements_type;
elements_type const& elements = rtree::elements(n);
spatial_query_incremental(Predicates const& p)
: m_translator(nullptr)
// , m_strategy()
, m_pred(p)
, m_values(nullptr)
, m_current()
{}
m_internal_stack.push_back(std::make_pair(elements.begin(), elements.end()));
}
inline void operator()(leaf const& n)
{
m_values = ::boost::addressof(rtree::elements(n));
m_current = rtree::elements(n).begin();
}
spatial_query_incremental(MembersHolder const& members, Predicates const& p)
: m_translator(::boost::addressof(members.translator()))
, m_strategy(index::detail::get_strategy(members.parameters()))
, m_pred(p)
, m_values(nullptr)
, m_current()
{}
const_reference dereference() const
{
@ -161,9 +160,9 @@ public:
return *m_current;
}
void initialize(node_pointer root)
void initialize(MembersHolder const& members)
{
rtree::apply_visitor(*this, *root);
apply(members.root, members.leafs_level);
search_value();
}
@ -173,8 +172,38 @@ public:
search_value();
}
bool is_end() const
{
return 0 == m_values;
}
friend bool operator==(spatial_query_incremental const& l, spatial_query_incremental const& r)
{
return (l.m_values == r.m_values) && (0 == l.m_values || l.m_current == r.m_current);
}
private:
void apply(node_pointer ptr, size_type reverse_level)
{
namespace id = index::detail;
if (reverse_level > 0)
{
internal_node& n = rtree::get<internal_node>(*ptr);
auto const& elements = rtree::elements(n);
m_internal_stack.push_back(internal_data(elements.begin(), elements.end(), reverse_level - 1));
}
else
{
leaf& n = rtree::get<leaf>(*ptr);
m_values = ::boost::addressof(rtree::elements(n));
m_current = rtree::elements(n).begin();
}
}
void search_value()
{
namespace id = index::detail;
for (;;)
{
// if leaf is choosen, move to the next value in leaf
@ -184,10 +213,7 @@ public:
{
// return if next value is found
value_type const& v = *m_current;
if (index::detail::predicates_check
<
index::detail::value_tag, 0, predicates_len
>(m_pred, v, (*m_translator)(v), m_strategy))
if (id::predicates_check<id::value_tag>(m_pred, v, (*m_translator)(v), m_strategy))
{
return;
}
@ -204,52 +230,40 @@ public:
else
{
// return if there is no more nodes to traverse
if ( m_internal_stack.empty() )
if (m_internal_stack.empty())
{
return;
}
// no more children in current node, remove it from stack
if ( m_internal_stack.back().first == m_internal_stack.back().second )
internal_data& current_data = m_internal_stack.back();
// no more children in current node, remove it from stack
if (current_data.first == current_data.last)
{
m_internal_stack.pop_back();
continue;
}
internal_iterator it = m_internal_stack.back().first;
++m_internal_stack.back().first;
internal_iterator it = current_data.first;
++current_data.first;
// next node is found, push it to the stack
if (index::detail::predicates_check
<
index::detail::bounds_tag, 0, predicates_len
>(m_pred, 0, it->first, m_strategy))
if (id::predicates_check<id::bounds_tag>(m_pred, 0, it->first, m_strategy))
{
rtree::apply_visitor(*this, *(it->second));
apply(it->second, current_data.reverse_level);
}
}
}
}
bool is_end() const
{
return 0 == m_values;
}
friend bool operator==(spatial_query_incremental const& l, spatial_query_incremental const& r)
{
return (l.m_values == r.m_values) && (0 == l.m_values || l.m_current == r.m_current );
}
private:
const translator_type * m_translator;
strategy_type m_strategy;
Predicates m_pred;
std::vector< std::pair<internal_iterator, internal_iterator> > m_internal_stack;
std::vector<internal_data> m_internal_stack;
const leaf_elements * m_values;
leaf_iterator m_current;
strategy_type m_strategy;
};
}}} // namespace detail::rtree::visitors

View File

@ -1079,17 +1079,9 @@ public:
template <typename Predicates, typename OutIter>
size_type query(Predicates const& predicates, OutIter out_it) const
{
if ( !m_members.root )
return 0;
static const std::size_t distance_predicates_count = detail::predicates_count_distance<Predicates>::value;
static const bool is_distance_predicate = 0 < distance_predicates_count;
BOOST_GEOMETRY_STATIC_ASSERT((distance_predicates_count <= 1),
"Only one distance predicate can be passed.",
Predicates);
return query_dispatch(predicates, out_it,
std::integral_constant<bool, is_distance_predicate>());
return m_members.root
? query_dispatch(predicates, out_it)
: 0;
}
/*!
@ -1183,6 +1175,15 @@ public:
return const_query_iterator();
}
private:
template <typename Predicates>
using query_iterator_t = std::conditional_t
<
detail::predicates_count_distance<Predicates>::value == 0,
detail::rtree::iterators::spatial_query_iterator<members_holder, Predicates>,
detail::rtree::iterators::distance_query_iterator<members_holder, Predicates>
>;
#ifndef BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL
private:
#endif
@ -1240,38 +1241,15 @@ private:
\return The iterator pointing at the begin of the query range.
*/
template <typename Predicates>
std::conditional_t
<
detail::predicates_count_distance<Predicates>::value == 0,
detail::rtree::iterators::spatial_query_iterator<members_holder, Predicates>,
detail::rtree::iterators::distance_query_iterator
<
members_holder, Predicates,
detail::predicates_find_distance<Predicates>::value
>
>
qbegin_(Predicates const& predicates) const
query_iterator_t<Predicates> qbegin_(Predicates const& predicates) const
{
static const std::size_t distance_predicates_count = detail::predicates_count_distance<Predicates>::value;
BOOST_GEOMETRY_STATIC_ASSERT((distance_predicates_count <= 1),
BOOST_GEOMETRY_STATIC_ASSERT((detail::predicates_count_distance<Predicates>::value <= 1),
"Only one distance predicate can be passed.",
Predicates);
typedef std::conditional_t
<
detail::predicates_count_distance<Predicates>::value == 0,
detail::rtree::iterators::spatial_query_iterator<members_holder, Predicates>,
detail::rtree::iterators::distance_query_iterator
<
members_holder, Predicates,
detail::predicates_find_distance<Predicates>::value
>
> iterator_type;
if ( !m_members.root )
return iterator_type(m_members.parameters(), m_members.translator(), predicates);
return iterator_type(m_members.root, m_members.parameters(), m_members.translator(), predicates);
return m_members.root
? query_iterator_t<Predicates>(m_members, predicates)
: query_iterator_t<Predicates>(predicates);
}
/*!
@ -1307,35 +1285,13 @@ private:
\return The iterator pointing at the end of the query range.
*/
template <typename Predicates>
std::conditional_t
<
detail::predicates_count_distance<Predicates>::value == 0,
detail::rtree::iterators::spatial_query_iterator<members_holder, Predicates>,
detail::rtree::iterators::distance_query_iterator
<
members_holder, Predicates,
detail::predicates_find_distance<Predicates>::value
>
>
qend_(Predicates const& predicates) const
query_iterator_t<Predicates> qend_(Predicates const& predicates) const
{
static const std::size_t distance_predicates_count = detail::predicates_count_distance<Predicates>::value;
BOOST_GEOMETRY_STATIC_ASSERT((distance_predicates_count <= 1),
BOOST_GEOMETRY_STATIC_ASSERT((detail::predicates_count_distance<Predicates>::value <= 1),
"Only one distance predicate can be passed.",
Predicates);
typedef std::conditional_t
<
detail::predicates_count_distance<Predicates>::value == 0,
detail::rtree::iterators::spatial_query_iterator<members_holder, Predicates>,
detail::rtree::iterators::distance_query_iterator
<
members_holder, Predicates,
detail::predicates_find_distance<Predicates>::value
>
> iterator_type;
return iterator_type(m_members.parameters(), m_members.translator(), predicates);
return query_iterator_t<Predicates>(m_members.parameters(), m_members.translator(), predicates);
}
/*!
@ -1436,10 +1392,9 @@ public:
*/
const_iterator begin() const
{
if ( !m_members.root )
return const_iterator();
return const_iterator(m_members.root);
return m_members.root
? const_iterator(m_members.root)
: const_iterator();
}
/*!
@ -1894,15 +1849,16 @@ private:
\par Exception-safety
strong
*/
template <typename Predicates, typename OutIter>
size_type query_dispatch(Predicates const& predicates, OutIter out_it, std::false_type /*is_distance_predicate*/) const
template
<
typename Predicates, typename OutIter,
std::enable_if_t<(detail::predicates_count_distance<Predicates>::value == 0), int> = 0
>
size_type query_dispatch(Predicates const& predicates, OutIter out_it) const
{
detail::rtree::visitors::spatial_query<members_holder, Predicates, OutIter>
find_v(m_members.parameters(), m_members.translator(), predicates, out_it);
detail::rtree::apply_visitor(find_v, *m_members.root);
return find_v.found_count;
query(m_members, predicates, out_it);
return query.apply(m_members);
}
/*!
@ -1911,22 +1867,21 @@ private:
\par Exception-safety
strong
*/
template <typename Predicates, typename OutIter>
size_type query_dispatch(Predicates const& predicates, OutIter out_it, std::true_type /*is_distance_predicate*/) const
template
<
typename Predicates, typename OutIter,
std::enable_if_t<(detail::predicates_count_distance<Predicates>::value > 0), int> = 0
>
size_type query_dispatch(Predicates const& predicates, OutIter out_it) const
{
BOOST_GEOMETRY_INDEX_ASSERT(m_members.root, "The root must exist");
BOOST_GEOMETRY_STATIC_ASSERT((detail::predicates_count_distance<Predicates>::value == 1),
"Only one distance predicate can be passed.",
Predicates);
static const std::size_t distance_predicate_index = detail::predicates_find_distance<Predicates>::value;
detail::rtree::visitors::distance_query<
members_holder,
Predicates,
distance_predicate_index,
OutIter
> distance_v(m_members.parameters(), m_members.translator(), predicates, out_it);
detail::rtree::visitors::distance_query<members_holder, Predicates>
distance_v(m_members, predicates);
detail::rtree::apply_visitor(distance_v, *m_members.root);
return distance_v.finish();
return distance_v.apply(m_members, out_it);
}
/*!

View File

@ -24,6 +24,7 @@
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/core/config.hpp>
#include <boost/geometry/core/coordinate_promotion.hpp>
#include <boost/geometry/core/tag_cast.hpp>
#include <boost/geometry/algorithms/envelope.hpp>
@ -37,7 +38,6 @@
#include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
#include <boost/geometry/policies/robustness/rescale_policy.hpp>
#include <boost/geometry/policies/robustness/robust_type.hpp>
#include <boost/geometry/util/promote_floating_point.hpp>
#include <boost/geometry/util/type_traits.hpp>
// TEMP

View File

@ -19,8 +19,8 @@
#include <boost/rational.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/core/coordinate_promotion.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/promote_floating_point.hpp>
namespace boost { namespace geometry
{
@ -135,11 +135,15 @@ struct possibly_collinear<Type, false>
template <typename Type>
class segment_ratio
{
public :
typedef Type numeric_type;
// Type used for the approximation (a helper value)
// and for the edge value (0..1) (a helper function).
using floating_point_type =
typename detail::promoted_to_floating_point<Type>::type;
// Type-alias for the type itself
typedef segment_ratio<Type> thistype;
using thistype = segment_ratio<Type>;
public :
inline segment_ratio()
: m_numerator(0)
@ -221,8 +225,8 @@ public :
m_approximation =
m_denominator == 0 ? 0
: (
boost::numeric_cast<fp_type>(m_numerator) * scale()
/ boost::numeric_cast<fp_type>(m_denominator)
boost::numeric_cast<floating_point_type>(m_numerator) * scale()
/ boost::numeric_cast<floating_point_type>(m_denominator)
);
}
@ -254,21 +258,16 @@ public :
return m_numerator > m_denominator;
}
inline bool near_end() const
//! Returns a value between 0.0 and 1.0
//! 0.0 means: exactly in the middle
//! 1.0 means: exactly on one of the edges (or even over it)
inline floating_point_type edge_value() const
{
if (left() || right())
{
return false;
}
static fp_type const small_part_of_scale = scale() / 100;
return m_approximation < small_part_of_scale
|| m_approximation > scale() - small_part_of_scale;
}
inline bool close_to(thistype const& other) const
{
return geometry::math::abs(m_approximation - other.m_approximation) < 50;
using fp = floating_point_type;
fp const one{1.0};
floating_point_type const result
= fp(2) * geometry::math::abs(fp(0.5) - m_approximation / scale());
return result > one ? one : result;
}
template <typename Threshold>
@ -313,19 +312,7 @@ public :
}
#endif
private :
// NOTE: if this typedef is used then fp_type is non-fundamental type
// if Type is non-fundamental type
//typedef typename promote_floating_point<Type>::type fp_type;
// TODO: What with user-defined numeric types?
// Shouldn't here is_integral be checked?
typedef std::conditional_t
<
std::is_floating_point<Type>::value, Type, double
> fp_type;
Type m_numerator;
Type m_denominator;
@ -335,12 +322,19 @@ private :
// 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.
fp_type m_approximation;
floating_point_type m_approximation;
static inline fp_type scale()
inline bool close_to(thistype const& other) const
{
return 1000000.0;
static floating_point_type const threshold{50.0};
return geometry::math::abs(m_approximation - other.m_approximation)
< threshold;
}
static inline floating_point_type scale()
{
static floating_point_type const fp_scale{1000000.0};
return fp_scale;
}
};

View File

@ -20,12 +20,16 @@
#include <boost/array.hpp>
#include <boost/core/ignore_unused.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/strategy/cartesian/side_robust.hpp>
#include <boost/geometry/strategies/covered_by.hpp>
#include <boost/geometry/strategies/within.hpp>
#include <boost/geometry/strategies/cartesian/side_by_triangle.hpp>
#include <boost/geometry/strategies/geographic/side.hpp>
#include <boost/geometry/strategies/spherical/ssf.hpp>
@ -118,7 +122,7 @@ struct cartesian_point_box_by_side
<
within::detail::decide_within
>(point, box,
strategy::side::side_by_triangle<CalculationType>());
strategy::side::side_robust<CalculationType>());
}
};
@ -189,7 +193,7 @@ struct cartesian_point_box_by_side
<
within::detail::decide_covered_by
>(point, box,
strategy::side::side_by_triangle<CalculationType>());
strategy::side::side_robust<CalculationType>());
}
};

View File

@ -14,10 +14,10 @@
#include <cmath>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/coordinate_promotion.hpp>
#include <boost/geometry/strategies/azimuth.hpp>
#include <boost/geometry/util/promote_floating_point.hpp>
#include <boost/geometry/util/select_most_precise.hpp>
namespace boost { namespace geometry

View File

@ -17,7 +17,6 @@
#include <boost/geometry/strategies/cartesian/distance_pythagoras.hpp>
#include <boost/geometry/strategies/cartesian/distance_pythagoras_point_box.hpp>
#include <boost/geometry/strategies/cartesian/point_in_point.hpp>
#include <boost/geometry/strategies/cartesian/side_by_triangle.hpp>
namespace boost { namespace geometry
{

View File

@ -38,13 +38,13 @@
#include <boost/geometry/strategy/cartesian/envelope.hpp>
#include <boost/geometry/strategy/cartesian/expand_box.hpp>
#include <boost/geometry/strategy/cartesian/expand_segment.hpp>
#include <boost/geometry/strategy/cartesian/side_robust.hpp>
#include <boost/geometry/strategies/cartesian/disjoint_box_box.hpp>
#include <boost/geometry/strategies/cartesian/disjoint_segment_box.hpp>
#include <boost/geometry/strategies/cartesian/distance_pythagoras.hpp>
#include <boost/geometry/strategies/cartesian/point_in_point.hpp>
#include <boost/geometry/strategies/cartesian/point_in_poly_winding.hpp>
#include <boost/geometry/strategies/cartesian/side_by_triangle.hpp>
#include <boost/geometry/strategies/covered_by.hpp>
#include <boost/geometry/strategies/intersection.hpp>
#include <boost/geometry/strategies/intersection_result.hpp>
@ -68,6 +68,61 @@ namespace boost { namespace geometry
namespace strategy { namespace intersection
{
namespace detail_usage
{
// When calculating the intersection, the information of "a" or "b" can be used.
// Theoretically this gives equal results, but due to floating point precision
// there might be tiny differences. These are edge cases.
// This structure is to determine if "a" or "b" should be used.
// Prefer the segment closer to the endpoint.
// If both are about equally close, then prefer the longer segment
// To avoid hard thresholds, behavior is made fluent.
// Calculate comparable length indications,
// the longer the segment (relatively), the lower the value
// such that the shorter lengths are evaluated higher and will
// be preferred.
template <bool IsArithmetic>
struct use_a
{
template <typename Ct, typename Ev>
static bool apply(Ct const& cla, Ct const& clb, Ev const& eva, Ev const& evb)
{
auto const clm = (std::max)(cla, clb);
if (clm <= 0)
{
return true;
}
// Relative comparible length
auto const rcla = Ct(1.0) - cla / clm;
auto const rclb = Ct(1.0) - clb / clm;
// Multipliers for edgevalue (ev) and relative comparible length (rcl)
// They determine the balance between edge value (should be larger)
// and segment length. In 99.9xx% of the cases there is no difference
// at all (if either a or b is used). Therefore the values of the
// constants are not sensitive for the majority of the situations.
// One known case is #mysql_23023665_6 (difference) which needs mev >= 2
Ev const mev = 5;
Ev const mrcl = 1;
return mev * eva + mrcl * rcla > mev * evb + mrcl * rclb;
}
};
// Specialization for non arithmetic types. They will always use "a"
template <>
struct use_a<false>
{
template <typename Ct, typename Ev>
static bool apply(Ct const& , Ct const& , Ev const& , Ev const& )
{
return true;
}
};
}
/*!
\see http://mathworld.wolfram.com/Line-LineIntersection.html
@ -180,30 +235,12 @@ struct cartesian_segments
template <typename Point, typename Segment1, typename Segment2>
void calculate(Point& point, Segment1 const& a, Segment2 const& b) const
{
bool use_a = true;
// Prefer one segment if one is on or near an endpoint
bool const a_near_end = robust_ra.near_end();
bool const b_near_end = robust_rb.near_end();
if (a_near_end && ! b_near_end)
{
use_a = true;
}
else if (b_near_end && ! a_near_end)
{
use_a = false;
}
else
{
// Prefer shorter segment
promoted_type const len_a = comparable_length_a();
promoted_type const len_b = comparable_length_b();
if (len_b < len_a)
{
use_a = false;
}
// else use_a is true but was already assigned like that
}
bool const use_a
= detail_usage::use_a
<
std::is_arithmetic<CoordinateType>::value
>::apply(comparable_length_a(), comparable_length_b(),
robust_ra.edge_value(), robust_rb.edge_value());
if (use_a)
{
@ -402,7 +439,7 @@ struct cartesian_segments
return Policy::disjoint();
}
typedef side::side_by_triangle<CalculationType> side_strategy_type;
typedef side::side_robust<CalculationType> side_strategy_type;
side_info sides;
sides.set<0>(side_strategy_type::apply(q1, q2, p1),
side_strategy_type::apply(q1, q2, p2));

View File

@ -24,10 +24,10 @@
#include <boost/geometry/util/select_calculation_type.hpp>
#include <boost/geometry/strategy/cartesian/expand_point.hpp>
#include <boost/geometry/strategy/cartesian/side_robust.hpp>
#include <boost/geometry/strategies/cartesian/point_in_box.hpp>
#include <boost/geometry/strategies/cartesian/disjoint_box_box.hpp>
#include <boost/geometry/strategies/cartesian/side_by_triangle.hpp>
#include <boost/geometry/strategies/covered_by.hpp>
#include <boost/geometry/strategies/within.hpp>
@ -116,7 +116,7 @@ public:
else // count == 2 || count == -2
{
// 1 left, -1 right
typedef side::side_by_triangle<CalculationType> side_strategy_type;
typedef side::side_robust<CalculationType> side_strategy_type;
side = side_strategy_type::apply(s1, s2, point);
}

View File

@ -1,275 +1,21 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Boost.Geometry
// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// Copyright (c) 2021, Oracle and/or its affiliates.
// This file was modified by Oracle on 2015-2021.
// Modifications copyright (c) 2015-2021, Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// 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)
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_SIDE_BY_TRIANGLE_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_SIDE_BY_TRIANGLE_HPP
#include <type_traits>
#include <boost/geometry/arithmetic/determinant.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/strategies/cartesian/disjoint_segment_box.hpp>
#include <boost/geometry/strategies/cartesian/point_in_point.hpp>
#include <boost/geometry/strategies/compare.hpp>
#include <boost/geometry/strategies/side.hpp>
#include <boost/geometry/strategy/cartesian/envelope.hpp>
#include <boost/geometry/util/select_most_precise.hpp>
#include <boost/config/pragma_message.hpp>
BOOST_PRAGMA_MESSAGE("This include file is deprecated and will be removed in the future.")
namespace boost { namespace geometry
{
namespace strategy { namespace side
{
/*!
\brief Check at which side of a segment a point lies:
left of segment (> 0), right of segment (< 0), on segment (0)
\ingroup strategies
\tparam CalculationType \tparam_calculation
*/
template <typename CalculationType = void>
class side_by_triangle
{
template <typename Policy>
struct eps_policy
{
eps_policy() {}
template <typename Type>
eps_policy(Type const& a, Type const& b, Type const& c, Type const& d)
: policy(a, b, c, d)
{}
Policy policy;
};
struct eps_empty
{
eps_empty() {}
template <typename Type>
eps_empty(Type const&, Type const&, Type const&, Type const&) {}
};
public :
typedef cartesian_tag cs_tag;
// 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"
template
<
typename CoordinateType,
typename PromotedType,
typename P1,
typename P2,
typename P,
typename EpsPolicy
>
static inline
PromotedType side_value(P1 const& p1, P2 const& p2, P const& p, EpsPolicy & eps_policy)
{
CoordinateType const x = get<0>(p);
CoordinateType const y = get<1>(p);
CoordinateType const sx1 = get<0>(p1);
CoordinateType const sy1 = get<1>(p1);
CoordinateType const sx2 = get<0>(p2);
CoordinateType const sy2 = get<1>(p2);
PromotedType const dx = sx2 - sx1;
PromotedType const dy = sy2 - sy1;
PromotedType const dpx = x - sx1;
PromotedType const dpy = y - sy1;
eps_policy = EpsPolicy(dx, dy, dpx, dpy);
return geometry::detail::determinant<PromotedType>
(
dx, dy,
dpx, dpy
);
}
template
<
typename CoordinateType,
typename PromotedType,
typename P1,
typename P2,
typename P
>
static inline
PromotedType side_value(P1 const& p1, P2 const& p2, P const& p)
{
eps_empty dummy;
return side_value<CoordinateType, PromotedType>(p1, p2, p, dummy);
}
template
<
typename CoordinateType,
typename PromotedType,
bool AreAllIntegralCoordinates
>
struct compute_side_value
{
template <typename P1, typename P2, typename P, typename EpsPolicy>
static inline PromotedType apply(P1 const& p1, P2 const& p2, P const& p, EpsPolicy & epsp)
{
return side_value<CoordinateType, PromotedType>(p1, p2, p, epsp);
}
};
template <typename CoordinateType, typename PromotedType>
struct compute_side_value<CoordinateType, PromotedType, false>
{
template <typename P1, typename P2, typename P, typename EpsPolicy>
static inline PromotedType apply(P1 const& p1, P2 const& p2, P const& p, EpsPolicy & epsp)
{
// For robustness purposes, first check if any two points are
// the same; in this case simply return that the points are
// collinear
if (equals_point_point(p1, p2)
|| equals_point_point(p1, p)
|| equals_point_point(p2, p))
{
return PromotedType(0);
}
// The side_by_triangle strategy computes the signed area of
// the point triplet (p1, p2, p); as such it is (in theory)
// invariant under cyclic permutations of its three arguments.
//
// In the context of numerical errors that arise in
// floating-point computations, and in order to make the strategy
// consistent with respect to cyclic permutations of its three
// arguments, we cyclically permute them so that the first
// argument is always the lexicographically smallest point.
typedef compare::cartesian<compare::less> less;
if (less::apply(p, p1))
{
if (less::apply(p, p2))
{
// p is the lexicographically smallest
return side_value<CoordinateType, PromotedType>(p, p1, p2, epsp);
}
else
{
// p2 is the lexicographically smallest
return side_value<CoordinateType, PromotedType>(p2, p, p1, epsp);
}
}
if (less::apply(p1, p2))
{
// p1 is the lexicographically smallest
return side_value<CoordinateType, PromotedType>(p1, p2, p, epsp);
}
else
{
// p2 is the lexicographically smallest
return side_value<CoordinateType, PromotedType>(p2, p, p1, epsp);
}
}
};
template <typename P1, typename P2, typename P>
static inline int apply(P1 const& p1, P2 const& p2, P const& p)
{
typedef typename coordinate_type<P1>::type coordinate_type1;
typedef typename coordinate_type<P2>::type coordinate_type2;
typedef typename coordinate_type<P>::type coordinate_type3;
typedef std::conditional_t
<
std::is_void<CalculationType>::value,
typename select_most_precise
<
coordinate_type1,
coordinate_type2,
coordinate_type3
>::type,
CalculationType
> coordinate_type;
// Promote float->double, small int->int
typedef typename select_most_precise
<
coordinate_type,
double
>::type promoted_type;
bool const are_all_integral_coordinates =
std::is_integral<coordinate_type1>::value
&& std::is_integral<coordinate_type2>::value
&& std::is_integral<coordinate_type3>::value;
eps_policy< math::detail::equals_factor_policy<promoted_type> > epsp;
promoted_type s = compute_side_value
<
coordinate_type, promoted_type, are_all_integral_coordinates
>::apply(p1, p2, p, epsp);
promoted_type const zero = promoted_type();
return math::detail::equals_by_policy(s, zero, epsp.policy) ? 0
: s > zero ? 1
: -1;
}
private:
template <typename P1, typename P2>
static inline bool equals_point_point(P1 const& p1, P2 const& p2)
{
return strategy::within::cartesian_point_point::apply(p1, p2);
}
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template <typename CalculationType>
struct default_strategy<cartesian_tag, CalculationType>
{
typedef side_by_triangle<CalculationType> type;
};
}
#endif
}} // namespace strategy::side
}} // namespace boost::geometry
#include <boost/geometry/strategy/cartesian/side_by_triangle.hpp>
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_SIDE_BY_TRIANGLE_HPP

View File

@ -17,6 +17,7 @@
#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_DISTANCE_HPP
#include <boost/geometry/core/coordinate_promotion.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/radian_access.hpp>
#include <boost/geometry/core/radius.hpp>
@ -32,7 +33,6 @@
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/normalize_spheroidal_coordinates.hpp>
#include <boost/geometry/util/promote_floating_point.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
#include <boost/geometry/geometries/point_xy.hpp>

View File

@ -21,6 +21,7 @@
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_promotion.hpp>
#include <boost/geometry/core/radian_access.hpp>
#include <boost/geometry/core/tags.hpp>
@ -37,7 +38,6 @@
#include <boost/geometry/formulas/vincenty_direct.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/promote_floating_point.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
#include <boost/geometry/util/normalize_spheroidal_coordinates.hpp>

View File

@ -13,6 +13,8 @@
#include <boost/geometry/srs/spheroid.hpp>
#include <boost/geometry/core/coordinate_promotion.hpp>
#include <boost/geometry/algorithms/detail/distance/segment_to_box.hpp>
#include <boost/geometry/strategies/distance.hpp>
@ -26,7 +28,6 @@
#include <boost/geometry/strategies/spherical/distance_segment_box.hpp>
#include <boost/geometry/strategies/spherical/point_in_point.hpp>
#include <boost/geometry/util/promote_floating_point.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
namespace boost { namespace geometry

View File

@ -17,10 +17,10 @@
#include <boost/core/ignore_unused.hpp>
#include <boost/geometry/core/coordinate_promotion.hpp>
#include <boost/geometry/core/radius.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/promote_floating_point.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
#include <boost/geometry/strategies/side.hpp>

View File

@ -16,6 +16,7 @@
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_promotion.hpp>
#include <boost/geometry/core/radian_access.hpp>
#include <boost/geometry/core/radius.hpp>
@ -32,7 +33,6 @@
#include <boost/geometry/strategy/geographic/envelope.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/promote_floating_point.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
namespace boost { namespace geometry

View File

@ -19,12 +19,12 @@
#include <boost/geometry/policies/relate/intersection_policy.hpp>
#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
#include <boost/geometry/strategy/cartesian/side_robust.hpp>
#include <boost/geometry/strategies/intersection.hpp>
#include <boost/geometry/strategies/intersection_result.hpp>
#include <boost/geometry/strategies/side.hpp>
#include <boost/geometry/strategies/cartesian/intersection.hpp>
#include <boost/geometry/strategies/cartesian/side_by_triangle.hpp>
#include <boost/geometry/strategies/spherical/intersection.hpp>
#include <boost/geometry/strategies/spherical/ssf.hpp>

View File

@ -11,10 +11,10 @@
#define BOOST_GEOMETRY_STRATEGIES_IS_CONVEX_CARTESIAN_HPP
#include <boost/geometry/strategies/cartesian/side_by_triangle.hpp>
#include <boost/geometry/strategies/convex_hull/cartesian.hpp>
#include <boost/geometry/strategies/detail.hpp>
#include <boost/geometry/strategies/is_convex/services.hpp>
#include <boost/geometry/strategy/cartesian/side_by_triangle.hpp>
namespace boost { namespace geometry

View File

@ -26,6 +26,8 @@
#include <boost/geometry/strategies/detail.hpp>
#include <boost/geometry/strategy/cartesian/area.hpp>
#include <boost/geometry/strategy/cartesian/side_robust.hpp>
#include <boost/geometry/strategy/cartesian/side_by_triangle.hpp>
#include <boost/geometry/strategy/cartesian/area_box.hpp>
#include <boost/geometry/util/type_traits.hpp>
@ -156,7 +158,7 @@ public:
static auto side()
{
return strategy::side::side_by_triangle<CalculationType>();
return strategy::side::side_robust<CalculationType>();
}
// within
@ -381,6 +383,15 @@ struct strategy_converter<strategy::side::side_by_triangle<CalculationType>>
}
};
template <typename CalculationType>
struct strategy_converter<strategy::side::side_robust<CalculationType>>
{
static auto get(strategy::side::side_robust<CalculationType> const&)
{
return strategies::relate::cartesian<CalculationType>();
}
};
} // namespace services

View File

@ -24,6 +24,7 @@
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_promotion.hpp>
#include <boost/geometry/core/radian_access.hpp>
#include <boost/geometry/core/tags.hpp>
@ -36,7 +37,6 @@
#include <boost/geometry/strategies/spherical/intersection.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/promote_floating_point.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
#ifdef BOOST_GEOMETRY_DEBUG_CROSS_TRACK

View File

@ -17,6 +17,7 @@
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_promotion.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/radian_access.hpp>
@ -26,7 +27,6 @@
#include <boost/geometry/strategies/spherical/get_radius.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/promote_floating_point.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>

View File

@ -28,6 +28,7 @@
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/radian_access.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/core/coordinate_promotion.hpp>
#include <boost/geometry/core/coordinate_system.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/cs.hpp>

View File

@ -16,6 +16,7 @@
#define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_SIDE_BY_CROSS_TRACK_HPP
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_promotion.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/radian_access.hpp>
@ -26,7 +27,6 @@
#include <boost/geometry/strategies/spherical/point_in_point.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/promote_floating_point.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
namespace boost { namespace geometry

View File

@ -16,10 +16,10 @@
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_promotion.hpp>
#include <boost/geometry/core/radian_access.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/promote_floating_point.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
#include <boost/geometry/strategy/spherical/envelope.hpp>

View File

@ -67,7 +67,6 @@
#include <boost/geometry/strategies/cartesian/point_in_poly_crossings_multiply.hpp>
#include <boost/geometry/strategies/cartesian/point_in_poly_winding.hpp>
#include <boost/geometry/strategies/cartesian/line_interpolate.hpp>
#include <boost/geometry/strategies/cartesian/side_by_triangle.hpp>
#include <boost/geometry/strategies/spherical/azimuth.hpp>
#include <boost/geometry/strategies/spherical/densify.hpp>
@ -135,6 +134,8 @@
#include <boost/geometry/strategy/cartesian/expand_box.hpp>
#include <boost/geometry/strategy/cartesian/expand_point.hpp>
#include <boost/geometry/strategy/cartesian/expand_segment.hpp>
#include <boost/geometry/strategy/cartesian/side_by_triangle.hpp>
#include <boost/geometry/strategy/cartesian/side_robust.hpp>
#include <boost/geometry/strategy/geographic/area.hpp>
#include <boost/geometry/strategy/geographic/envelope.hpp>

View File

@ -30,10 +30,10 @@
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/radian_access.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/core/coordinate_promotion.hpp>
#include <boost/geometry/strategies/transform.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/promote_floating_point.hpp>
#include <boost/geometry/util/select_coordinate_type.hpp>
namespace boost { namespace geometry

View File

@ -33,9 +33,9 @@
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/core/coordinate_promotion.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/promote_floating_point.hpp>
#include <boost/geometry/util/select_coordinate_type.hpp>
#include <boost/geometry/util/select_most_precise.hpp>

View File

@ -0,0 +1,262 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2015-2021.
// Modifications copyright (c) 2015-2021, Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_STRATEGY_CARTESIAN_SIDE_BY_TRIANGLE_HPP
#define BOOST_GEOMETRY_STRATEGY_CARTESIAN_SIDE_BY_TRIANGLE_HPP
#include <type_traits>
#include <boost/geometry/arithmetic/determinant.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/strategies/cartesian/disjoint_segment_box.hpp>
#include <boost/geometry/strategies/cartesian/point_in_point.hpp>
#include <boost/geometry/strategies/compare.hpp>
#include <boost/geometry/strategies/side.hpp>
#include <boost/geometry/strategy/cartesian/envelope.hpp>
#include <boost/geometry/util/select_most_precise.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace side
{
/*!
\brief Check at which side of a segment a point lies:
left of segment (> 0), right of segment (< 0), on segment (0)
\ingroup strategies
\tparam CalculationType \tparam_calculation
*/
template <typename CalculationType = void>
class side_by_triangle
{
template <typename Policy>
struct eps_policy
{
eps_policy() {}
template <typename Type>
eps_policy(Type const& a, Type const& b, Type const& c, Type const& d)
: policy(a, b, c, d)
{}
Policy policy;
};
struct eps_empty
{
eps_empty() {}
template <typename Type>
eps_empty(Type const&, Type const&, Type const&, Type const&) {}
};
public :
typedef cartesian_tag cs_tag;
// 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"
template
<
typename CoordinateType,
typename PromotedType,
typename P1,
typename P2,
typename P,
typename EpsPolicy
>
static inline
PromotedType side_value(P1 const& p1, P2 const& p2, P const& p, EpsPolicy & eps_policy)
{
CoordinateType const x = get<0>(p);
CoordinateType const y = get<1>(p);
CoordinateType const sx1 = get<0>(p1);
CoordinateType const sy1 = get<1>(p1);
CoordinateType const sx2 = get<0>(p2);
CoordinateType const sy2 = get<1>(p2);
PromotedType const dx = sx2 - sx1;
PromotedType const dy = sy2 - sy1;
PromotedType const dpx = x - sx1;
PromotedType const dpy = y - sy1;
eps_policy = EpsPolicy(dx, dy, dpx, dpy);
return geometry::detail::determinant<PromotedType>
(
dx, dy,
dpx, dpy
);
}
template
<
typename CoordinateType,
typename PromotedType,
typename P1,
typename P2,
typename P
>
static inline
PromotedType side_value(P1 const& p1, P2 const& p2, P const& p)
{
eps_empty dummy;
return side_value<CoordinateType, PromotedType>(p1, p2, p, dummy);
}
template
<
typename CoordinateType,
typename PromotedType,
bool AreAllIntegralCoordinates
>
struct compute_side_value
{
template <typename P1, typename P2, typename P, typename EpsPolicy>
static inline PromotedType apply(P1 const& p1, P2 const& p2, P const& p, EpsPolicy & epsp)
{
return side_value<CoordinateType, PromotedType>(p1, p2, p, epsp);
}
};
template <typename CoordinateType, typename PromotedType>
struct compute_side_value<CoordinateType, PromotedType, false>
{
template <typename P1, typename P2, typename P, typename EpsPolicy>
static inline PromotedType apply(P1 const& p1, P2 const& p2, P const& p, EpsPolicy & epsp)
{
// For robustness purposes, first check if any two points are
// the same; in this case simply return that the points are
// collinear
if (equals_point_point(p1, p2)
|| equals_point_point(p1, p)
|| equals_point_point(p2, p))
{
return PromotedType(0);
}
// The side_by_triangle strategy computes the signed area of
// the point triplet (p1, p2, p); as such it is (in theory)
// invariant under cyclic permutations of its three arguments.
//
// In the context of numerical errors that arise in
// floating-point computations, and in order to make the strategy
// consistent with respect to cyclic permutations of its three
// arguments, we cyclically permute them so that the first
// argument is always the lexicographically smallest point.
typedef compare::cartesian<compare::less> less;
if (less::apply(p, p1))
{
if (less::apply(p, p2))
{
// p is the lexicographically smallest
return side_value<CoordinateType, PromotedType>(p, p1, p2, epsp);
}
else
{
// p2 is the lexicographically smallest
return side_value<CoordinateType, PromotedType>(p2, p, p1, epsp);
}
}
if (less::apply(p1, p2))
{
// p1 is the lexicographically smallest
return side_value<CoordinateType, PromotedType>(p1, p2, p, epsp);
}
else
{
// p2 is the lexicographically smallest
return side_value<CoordinateType, PromotedType>(p2, p, p1, epsp);
}
}
};
template <typename P1, typename P2, typename P>
static inline int apply(P1 const& p1, P2 const& p2, P const& p)
{
typedef typename coordinate_type<P1>::type coordinate_type1;
typedef typename coordinate_type<P2>::type coordinate_type2;
typedef typename coordinate_type<P>::type coordinate_type3;
typedef std::conditional_t
<
std::is_void<CalculationType>::value,
typename select_most_precise
<
coordinate_type1,
coordinate_type2,
coordinate_type3
>::type,
CalculationType
> coordinate_type;
// Promote float->double, small int->int
typedef typename select_most_precise
<
coordinate_type,
double
>::type promoted_type;
bool const are_all_integral_coordinates =
std::is_integral<coordinate_type1>::value
&& std::is_integral<coordinate_type2>::value
&& std::is_integral<coordinate_type3>::value;
eps_policy< math::detail::equals_factor_policy<promoted_type> > epsp;
promoted_type s = compute_side_value
<
coordinate_type, promoted_type, are_all_integral_coordinates
>::apply(p1, p2, p, epsp);
promoted_type const zero = promoted_type();
return math::detail::equals_by_policy(s, zero, epsp.policy) ? 0
: s > zero ? 1
: -1;
}
private:
template <typename P1, typename P2>
static inline bool equals_point_point(P1 const& p1, P2 const& p2)
{
return strategy::within::cartesian_point_point::apply(p1, p2);
}
};
}} // namespace strategy::side
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGY_CARTESIAN_SIDE_BY_TRIANGLE_HPP

View File

@ -1,6 +1,6 @@
// Boost.Geometry
// Copyright (c) 2020, Oracle and/or its affiliates.
// Copyright (c) 2020-2021, Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
@ -14,6 +14,8 @@
#include <boost/geometry/util/select_calculation_type.hpp>
#include <boost/geometry/util/precise_math.hpp>
#include <boost/geometry/arithmetic/determinant.hpp>
namespace boost { namespace geometry
{
@ -21,7 +23,7 @@ namespace strategy { namespace side
{
/*!
\brief Adaptive precision predicate to check at which side of a segment a point lies:
\brief Predicate to check at which side of a segment a point lies:
left of segment (>0), right of segment (< 0), on segment (0).
\ingroup strategies
\tparam CalculationType \tparam_calculation
@ -35,8 +37,6 @@ struct side_non_robust
{
public:
//! \brief Computes double the signed area of the CCW triangle p1, p2, p
#ifndef DOXYGEN_SHOULD_SKIP_THIS
template
<
typename P1,
@ -51,21 +51,44 @@ public:
P1,
P2,
P
>::type coordinate_type;
>::type CoordinateType;
typedef typename select_most_precise
<
coordinate_type,
CoordinateType,
double
>::type promoted_type;
>::type PromotedType;
auto detleft = (promoted_type(get<0>(p1)) - promoted_type(get<0>(p)))
* (promoted_type(get<1>(p2)) - promoted_type(get<1>(p)));
auto detright = (promoted_type(get<1>(p1)) - promoted_type(get<1>(p)))
* (promoted_type(get<0>(p2)) - promoted_type(get<0>(p)));
return detleft > detright ? 1 : (detleft < detright ? -1 : 0 );
CoordinateType const x = get<0>(p);
CoordinateType const y = get<1>(p);
CoordinateType const sx1 = get<0>(p1);
CoordinateType const sy1 = get<1>(p1);
CoordinateType const sx2 = get<0>(p2);
CoordinateType const sy2 = get<1>(p2);
//non-robust 1
//the following is 2x slower in some generic cases when compiled with g++
//(tested versions 9 and 10)
//
//auto detleft = (sx1 - x) * (sy2 - y);
//auto detright = (sy1 - y) * (sx2 - x);
//return detleft > detright ? 1 : (detleft < detright ? -1 : 0 );
//non-robust 2
PromotedType const dx = sx2 - sx1;
PromotedType const dy = sy2 - sy1;
PromotedType const dpx = x - sx1;
PromotedType const dpy = y - sy1;
PromotedType sv = geometry::detail::determinant<PromotedType>
(
dx, dy,
dpx, dpy
);
PromotedType const zero = PromotedType();
return sv == 0 ? 0 : sv > zero ? 1 : -1;
}
#endif
};

View File

@ -7,6 +7,7 @@
// This file was modified by Oracle on 2021.
// Modifications copyright (c) 2021, Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@ -17,9 +18,14 @@
#ifndef BOOST_GEOMETRY_STRATEGY_CARTESIAN_SIDE_ROBUST_HPP
#define BOOST_GEOMETRY_STRATEGY_CARTESIAN_SIDE_ROBUST_HPP
#include <boost/geometry/strategy/cartesian/side_non_robust.hpp>
#include <boost/geometry/strategies/side.hpp>
#include <boost/geometry/util/select_most_precise.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
#include <boost/geometry/util/precise_math.hpp>
#include <boost/geometry/util/math.hpp>
namespace boost { namespace geometry
{
@ -27,6 +33,27 @@ namespace boost { namespace geometry
namespace strategy { namespace side
{
struct epsilon_equals_policy
{
public:
template <typename Policy, typename T1, typename T2>
static bool apply(T1 const& a, T2 const& b, Policy const& policy)
{
return boost::geometry::math::detail::equals_by_policy(a, b, policy);
}
};
struct fp_equals_policy
{
public:
template <typename Policy, typename T1, typename T2>
static bool apply(T1 const& a, T2 const& b, Policy const&)
{
return a == b;
}
};
/*!
\brief Adaptive precision predicate to check at which side of a segment a point lies:
left of segment (>0), right of segment (< 0), on segment (0).
@ -38,21 +65,52 @@ namespace strategy { namespace side
template
<
typename CalculationType = void,
typename EqualsPolicy = epsilon_equals_policy,
std::size_t Robustness = 3
>
struct side_robust
{
template <typename CT>
struct epsilon_policy
{
using Policy = boost::geometry::math::detail::equals_factor_policy<CT>;
epsilon_policy() {}
template <typename Type>
epsilon_policy(Type const& a, Type const& b, Type const& c, Type const& d)
: m_policy(a, b, c, d)
{}
Policy m_policy;
public:
template <typename T1, typename T2>
bool apply(T1 a, T2 b) const
{
return EqualsPolicy::apply(a, b, m_policy);
}
};
public:
//! \brief Computes double the signed area of the CCW triangle p1, p2, p
typedef cartesian_tag cs_tag;
//! \brief Computes the sign of the CCW triangle p1, p2, p
template
<
typename PromotedType,
typename P1,
typename P2,
typename P
typename P,
typename EpsPolicyInternal,
std::enable_if_t<std::is_fundamental<PromotedType>::value, int> = 0
>
static inline PromotedType side_value(P1 const& p1, P2 const& p2,
P const& p)
static inline PromotedType side_value(P1 const& p1,
P2 const& p2,
P const& p,
EpsPolicyInternal& eps_policy)
{
using vec2d = ::boost::geometry::detail::precise_math::vec2d<PromotedType>;
vec2d pa;
@ -65,7 +123,22 @@ public:
pc.x = get<0>(p);
pc.y = get<1>(p);
return ::boost::geometry::detail::precise_math::orient2d
<PromotedType, Robustness>(pa, pb, pc);
<PromotedType, Robustness>(pa, pb, pc, eps_policy);
}
template
<
typename PromotedType,
typename P1,
typename P2,
typename P,
typename EpsPolicyInternal,
std::enable_if_t<!std::is_fundamental<PromotedType>::value, int> = 0
>
static inline auto side_value(P1 const& p1, P2 const& p2, P const& p,
EpsPolicyInternal&)
{
return side_non_robust<>::apply(p1, p2, p);
}
#ifndef DOXYGEN_SHOULD_SKIP_THIS
@ -77,28 +150,48 @@ public:
>
static inline int apply(P1 const& p1, P2 const& p2, P const& p)
{
typedef typename select_calculation_type_alt
using coordinate_type = typename select_calculation_type_alt
<
CalculationType,
P1,
P2,
P
>::type coordinate_type;
typedef typename select_most_precise
>::type;
using promoted_type = typename select_most_precise
<
coordinate_type,
double
>::type promoted_type;
>::type;
promoted_type sv = side_value<promoted_type>(p1, p2, p);
return sv > 0 ? 1
: sv < 0 ? -1
: 0;
epsilon_policy<promoted_type> epsp;
promoted_type sv = side_value<promoted_type>(p1, p2, p, epsp);
promoted_type const zero = promoted_type();
return epsp.apply(sv, zero) ? 0
: sv > zero ? 1
: -1;
}
#endif
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template <typename CalculationType>
struct default_strategy<cartesian_tag, CalculationType>
{
typedef side_robust<CalculationType> type;
};
}
#endif
}} // namespace strategy::side
}} // namespace boost::geometry

View File

@ -5,6 +5,10 @@
// Contributed and/or modified by Tinko Bartels,
// as part of Google Summer of Code 2019 program.
// This file was modified by Oracle on 2021.
// Modifications copyright (c) 2021, Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fisikopoulos, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
@ -157,7 +161,9 @@ inline int fast_expansion_sum_zeroelim(
int n = InSize2)
{
std::array<RealNumber, 2> Qh;
int i_e = 0, i_f = 0, i_h = 0;
int i_e = 0;
int i_f = 0;
int i_h = 0;
if (std::abs(f[0]) > std::abs(e[0]))
{
Qh[0] = e[i_e++];
@ -282,14 +288,16 @@ inline RealNumber orient2dtail(vec2d<RealNumber> const& p1,
std::array<RealNumber, 2>& t4,
std::array<RealNumber, 2>& t5_01,
std::array<RealNumber, 2>& t6_01,
RealNumber const& magnitude
)
RealNumber const& magnitude)
{
t5_01[1] = two_product_tail(t1[0], t2[0], t5_01[0]);
t6_01[1] = two_product_tail(t3[0], t4[0], t6_01[0]);
std::array<RealNumber, 4> tA_03 = two_two_expansion_diff(t5_01, t6_01);
RealNumber det = std::accumulate(tA_03.begin(), tA_03.end(), static_cast<RealNumber>(0));
if(Robustness == 1) return det;
if (Robustness == 1)
{
return det;
}
// see p.39, mind the different definition of epsilon for error bound
RealNumber B_relative_bound =
(1 + 3 * std::numeric_limits<RealNumber>::epsilon())
@ -347,29 +355,37 @@ inline RealNumber orient2dtail(vec2d<RealNumber> const& p1,
return(D[D_nz - 1]);
}
// see page 38, Figure 21 for the calculations, notation follows the notation in the figure.
// see page 38, Figure 21 for the calculations, notation follows the notation
// in the figure.
template
<
typename RealNumber,
std::size_t Robustness = 3
std::size_t Robustness = 3,
typename EpsPolicy
>
inline RealNumber orient2d(vec2d<RealNumber> const& p1,
vec2d<RealNumber> const& p2,
vec2d<RealNumber> const& p3)
vec2d<RealNumber> const& p3,
EpsPolicy& eps_policy)
{
if(Robustness == 0)
{
return (p1.x - p3.x) * (p2.y - p3.y) - (p1.y - p3.y) * (p2.x - p3.x);
}
std::array<RealNumber, 2> t1, t2, t3, t4;
t1[0] = p1.x - p3.x;
t2[0] = p2.y - p3.y;
t3[0] = p1.y - p3.y;
t4[0] = p2.x - p3.x;
eps_policy = EpsPolicy(t1[0], t2[0], t3[0], t4[0]);
std::array<RealNumber, 2> t5_01, t6_01;
t5_01[0] = t1[0] * t2[0];
t6_01[0] = t3[0] * t4[0];
RealNumber det = t5_01[0] - t6_01[0];
if (Robustness == 0)
{
return det;
}
RealNumber const magnitude = std::abs(t5_01[0]) + std::abs(t6_01[0]);
// see p.39, mind the different definition of epsilon for error bound
@ -388,7 +404,8 @@ inline RealNumber orient2d(vec2d<RealNumber> const& p1,
//obvious
return det;
}
return orient2dtail<RealNumber, Robustness>(p1, p2, p3, t1, t2, t3, t4, t5_01, t6_01, magnitude);
return orient2dtail<RealNumber, Robustness>(p1, p2, p3, t1, t2, t3, t4,
t5_01, t6_01, magnitude);
}
// This method adaptively computes increasingly precise approximations of the following

View File

@ -18,35 +18,9 @@
#ifndef BOOST_GEOMETRY_UTIL_PROMOTE_FLOATING_POINT_HPP
#define BOOST_GEOMETRY_UTIL_PROMOTE_FLOATING_POINT_HPP
#include <boost/config/header_deprecated.hpp>
BOOST_HEADER_DEPRECATED("boost/geometry/core/coordinate_promotion.hpp")
#include <type_traits>
namespace boost { namespace geometry
{
/*!
\brief Meta-function converting, if necessary, to "a floating point" type
\details
- if input type is integer, type is double
- else type is input type
\ingroup utility
*/
template <typename T, typename PromoteIntegerTo = double>
struct promote_floating_point
{
typedef std::conditional_t
<
std::is_integral<T>::value,
PromoteIntegerTo,
T
> type;
};
}} // namespace boost::geometry
#include <boost/geometry/core/coordinate_promotion.hpp>
#endif // BOOST_GEOMETRY_UTIL_PROMOTE_FLOATING_POINT_HPP

View File

@ -2,6 +2,10 @@
#
# Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
#
# This file was modified by Oracle on 2021.
# Modifications copyright (c) 2021 Oracle and/or its affiliates.
# Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
#
# Use, modification and distribution is subject to the Boost Software License,
# Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
@ -16,12 +20,12 @@ project boost-geometry-index-test
<toolset>msvc:<asynch-exceptions>on
<toolset>msvc:<cxxflags>/bigobj
<host-os>windows,<toolset>intel:<cxxflags>/bigobj
<define>BOOST_NO_AUTO_PTR # disable the deprecated std::auto_ptr support in SmartPtr and Core
<library>/boost/timer//boost_timer
;
test-suite boost-geometry-index-varray
test-suite boost-geometry-index-detail
:
[ run minmax_heap.cpp ]
[ run varray_old.cpp ]
[ run varray.cpp ]
;

282
index/test/minmax_heap.cpp Normal file
View File

@ -0,0 +1,282 @@
// Boost.Geometry
// Copyright (c) 2021, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#include <boost/test/included/test_exec_monitor.hpp>
#include <boost/test/impl/execution_monitor.ipp>
#include <algorithm>
#include <vector>
#include <map>
#include <boost/geometry/index/detail/minmax_heap.hpp>
#include <boost/geometry/index/detail/maxmin_heap.hpp>
using namespace boost::geometry::index::detail;
struct noncopyable
{
noncopyable(int i_) : i(i_) {}
noncopyable(noncopyable const&) = delete;
noncopyable& operator=(noncopyable const&) = delete;
noncopyable(noncopyable&&) = default;
noncopyable& operator=(noncopyable&&) = default;
bool operator<(noncopyable const& other) const { return i < other.i; }
operator int() const { return i; }
int i;
};
template <typename T>
struct minmax_default
{
minmax_default() = default;
minmax_default(std::vector<int> const& vec)
: heap(vec.begin(), vec.end())
{
make_minmax_heap(heap.begin(), heap.end());
}
T const& top() const
{
return heap[0];
}
T const& bottom() const
{
return bottom_minmax_heap(heap.begin(), heap.end());
}
void push(int i)
{
heap.push_back(T(i));
push_minmax_heap(heap.begin(), heap.end());
}
void pop_top()
{
pop_top_minmax_heap(heap.begin(), heap.end());
heap.pop_back();
}
void pop_bottom()
{
pop_bottom_minmax_heap(heap.begin(), heap.end());
heap.pop_back();
}
bool is_heap() const
{
return is_minmax_heap(heap.begin(), heap.end());
}
bool empty() const
{
return heap.empty();
}
std::vector<T> heap;
};
template <typename T>
struct minmax_less
{
minmax_less() = default;
minmax_less(std::vector<int> const& vec)
: heap(vec.begin(), vec.end())
{
make_minmax_heap(heap.begin(), heap.end(), std::less<>());
}
T const& top() const
{
return heap[0];
}
T const& bottom() const
{
return bottom_minmax_heap(heap.begin(), heap.end(), std::less<>());
}
void push(int i)
{
heap.push_back(T(i));
push_minmax_heap(heap.begin(), heap.end(), std::less<>());
}
void pop_top()
{
pop_top_minmax_heap(heap.begin(), heap.end(), std::less<>());
heap.pop_back();
}
void pop_bottom()
{
pop_bottom_minmax_heap(heap.begin(), heap.end(), std::less<>());
heap.pop_back();
}
bool is_heap() const
{
return is_minmax_heap(heap.begin(), heap.end(), std::less<>());
}
bool empty() const
{
return heap.empty();
}
std::vector<T> heap;
};
template <typename T>
struct maxmin_greater
{
maxmin_greater() = default;
maxmin_greater(std::vector<int> const& vec)
: heap(vec.begin(), vec.end())
{
make_maxmin_heap(heap.begin(), heap.end(), std::greater<>());
}
T const& top() const
{
return heap[0];
}
T const& bottom() const
{
return bottom_maxmin_heap(heap.begin(), heap.end(), std::greater<>());
}
void push(int i)
{
heap.push_back(T(i));
push_maxmin_heap(heap.begin(), heap.end(), std::greater<>());
}
void pop_top()
{
pop_top_maxmin_heap(heap.begin(), heap.end(), std::greater<>());
heap.pop_back();
}
void pop_bottom()
{
pop_bottom_maxmin_heap(heap.begin(), heap.end(), std::greater<>());
heap.pop_back();
}
bool is_heap() const
{
return is_maxmin_heap(heap.begin(), heap.end(), std::greater<>());
}
bool empty() const
{
return heap.empty();
}
std::vector<T> heap;
};
template <typename T>
struct maxmin_default_switch
{
maxmin_default_switch() = default;
maxmin_default_switch(std::vector<int> const& vec)
: heap(vec.begin(), vec.end())
{
make_maxmin_heap(heap.begin(), heap.end());
}
T const& bottom() const
{
return heap[0];
}
T const& top() const
{
return bottom_maxmin_heap(heap.begin(), heap.end());
}
void push(int i)
{
heap.push_back(T(i));
push_maxmin_heap(heap.begin(), heap.end());
}
void pop_top()
{
pop_bottom_maxmin_heap(heap.begin(), heap.end());
heap.pop_back();
}
void pop_bottom()
{
pop_top_maxmin_heap(heap.begin(), heap.end());
heap.pop_back();
}
bool is_heap() const
{
return is_maxmin_heap(heap.begin(), heap.end());
}
bool empty() const
{
return heap.empty();
}
std::vector<T> heap;
};
template <typename Heap>
void test()
{
std::vector<int> vec;
int const n = 20;
for (int i = 0; i < n; ++i)
{
vec.push_back(rand() % n);
}
{
std::map<int, int> map;
Heap heap;
for (int i : vec)
{
heap.push(i);
BOOST_CHECK(heap.is_heap());
map[i]++;
BOOST_CHECK_EQUAL(heap.top(), map.begin()->first);
BOOST_CHECK_EQUAL(heap.bottom(), (--map.end())->first);
}
while (! heap.empty())
{
int i = heap.top();
BOOST_CHECK_EQUAL(i, map.begin()->first);
BOOST_CHECK_EQUAL(heap.bottom(), (--map.end())->first);
BOOST_CHECK(map[i] > 0);
map[i]--;
if (map[i] <= 0)
map.erase(i);
heap.pop_top();
BOOST_CHECK(heap.is_heap());
}
BOOST_CHECK(map.empty());
}
{
Heap heap(vec);
BOOST_CHECK(heap.is_heap());
std::map<int, int> map;
for (int i : vec)
map[i]++;
BOOST_CHECK_EQUAL(heap.top(), map.begin()->first);
BOOST_CHECK_EQUAL(heap.bottom(), (--map.end())->first);
while (! heap.empty())
{
int i = heap.bottom();
BOOST_CHECK_EQUAL(heap.top(), map.begin()->first);
BOOST_CHECK_EQUAL(i, (--map.end())->first);
BOOST_CHECK(map[i] > 0);
map[i]--;
if (map[i] <= 0)
map.erase(i);
heap.pop_bottom();
BOOST_CHECK(heap.is_heap());
}
BOOST_CHECK(map.empty());
}
}
int test_main(int, char* [])
{
test<minmax_default<int>>();
test<minmax_default<noncopyable>>();
test<minmax_less<int>>();
test<maxmin_greater<int>>();
test<maxmin_default_switch<int>>();
return 0;
}

View File

@ -3,6 +3,10 @@
// Copyright (c) 2016 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2021.
// Modifications copyright (c) 2021, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
@ -101,7 +105,7 @@ void test_ticket_12413()
size_t num_removed = rtree.remove(std::make_pair(point_t(-0.127592, 51.503407), 796));
BOOST_CHECK_EQUAL(num_removed, 1);
BOOST_CHECK_EQUAL(num_removed, 1u);
}
template <typename Point>

View File

@ -3,6 +3,10 @@
// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2021.
// Modifications copyright (c) 2021, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
@ -10,7 +14,6 @@
#include <fstream>
#include <vector>
#include <string>
#include <boost/foreach.hpp>
#include <boost/assert.hpp>
#include <boost/tuple/tuple.hpp>
@ -46,13 +49,13 @@ int main()
testsets.push_back(std::make_pair("testset::queries", "que"));
testsets.push_back(std::make_pair("testset::additional", "add"));
BOOST_FOREACH(P const& p, parameters)
for (P const& p : parameters)
{
BOOST_FOREACH(TS const& ts, testsets)
for (TS const& ts : testsets)
{
BOOST_FOREACH(std::string const& i, indexables)
for (std::string const& i : indexables)
{
BOOST_FOREACH(std::string const& d, dimensions)
for (std::string const& d : dimensions)
{
// If the I is Segment, generate only for 2d
if ( i == "s" && d != "2" )
@ -60,7 +63,7 @@ int main()
continue;
}
BOOST_FOREACH(CT const& c, coordinate_types)
for (CT const& c : coordinate_types)
{
std::string filename = std::string() +
"rtree_" + boost::get<1>(p) + '_' + ts.second + '_' + i + d + boost::get<1>(c) + ".cpp";

View File

@ -14,7 +14,6 @@
#ifndef BOOST_GEOMETRY_INDEX_TEST_RTREE_HPP
#define BOOST_GEOMETRY_INDEX_TEST_RTREE_HPP
#include <boost/foreach.hpp>
#include <vector>
#include <algorithm>
@ -415,6 +414,8 @@ struct counting_value
counting_value(counting_value const& c) : indexable(c.indexable) { counter()++; }
~counting_value() { counter()--; }
counting_value& operator=(counting_value const& c) = default;
static size_t & counter() { static size_t c = 0; return c; }
Indexable indexable;
};
@ -681,15 +682,16 @@ void rtree(Rtree & tree, Elements & input, Box & qbox)
} // namespace generate
namespace basictest {
namespace basictest
{
// low level test functions
template <typename Rtree, typename Iter, typename Value>
Iter find(Rtree const& rtree, Iter first, Iter last, Value const& value)
{
for ( ; first != last ; ++first )
if ( rtree.value_eq()(value, *first) )
for (; first != last; ++first)
if (rtree.value_eq()(value, *first))
return first;
return first;
}
@ -698,12 +700,12 @@ template <typename Rtree, typename Value>
void compare_outputs(Rtree const& rtree, std::vector<Value> const& output, std::vector<Value> const& expected_output)
{
bool are_sizes_ok = (expected_output.size() == output.size());
BOOST_CHECK( are_sizes_ok );
if ( are_sizes_ok )
BOOST_CHECK(are_sizes_ok);
if (are_sizes_ok)
{
BOOST_FOREACH(Value const& v, expected_output)
for (Value const& v : expected_output)
{
BOOST_CHECK(find(rtree, output.begin(), output.end(), v) != output.end() );
BOOST_CHECK(find(rtree, output.begin(), output.end(), v) != output.end());
}
}
}
@ -715,13 +717,13 @@ void exactly_the_same_outputs(Rtree const& rtree, Range1 const& output, Range2 c
size_t s2 = std::distance(expected_output.begin(), expected_output.end());
BOOST_CHECK(s1 == s2);
if ( s1 == s2 )
if (s1 == s2)
{
typename Range1::const_iterator it1 = output.begin();
typename Range2::const_iterator it2 = expected_output.begin();
for ( ; it1 != output.end() && it2 != expected_output.end() ; ++it1, ++it2 )
for (; it1 != output.end() && it2 != expected_output.end(); ++it1, ++it2)
{
if ( !rtree.value_eq()(*it1, *it2) )
if (!rtree.value_eq()(*it1, *it2))
{
BOOST_CHECK(false && "rtree.translator().equals(*it1, *it2)");
break;
@ -734,7 +736,7 @@ void exactly_the_same_outputs(Rtree const& rtree, Range1 const& output, Range2 c
template <typename First, typename Last, typename Out>
void copy_alt(First first, Last last, Out out)
{
for ( ; first != last ; ++first, ++out )
for (; first != last; ++first, ++out)
*out = *first;
}
@ -759,7 +761,7 @@ void check_fwd_iterators(QItF first, QItL last)
#endif
QItF it = first;
for ( ; it != last && first != last ; ++it, ++first)
for (; it != last && first != last; ++it, ++first)
{
BOOST_CHECK(it == first);
@ -775,20 +777,20 @@ void check_fwd_iterators(QItF first, QItL last)
template <typename Rtree, typename Value, typename Predicates>
void spatial_query(Rtree & rtree, Predicates const& pred, std::vector<Value> const& expected_output)
{
BOOST_CHECK( bgi::detail::rtree::utilities::are_levels_ok(rtree) );
if ( !rtree.empty() )
BOOST_CHECK( bgi::detail::rtree::utilities::are_boxes_ok(rtree) );
BOOST_CHECK(bgi::detail::rtree::utilities::are_levels_ok(rtree));
if (!rtree.empty())
BOOST_CHECK(bgi::detail::rtree::utilities::are_boxes_ok(rtree));
std::vector<Value> output;
size_t n = rtree.query(pred, std::back_inserter(output));
BOOST_CHECK( expected_output.size() == n );
BOOST_CHECK(expected_output.size() == n);
compare_outputs(rtree, output, expected_output);
std::vector<Value> output2;
size_t n2 = query(rtree, pred, std::back_inserter(output2));
BOOST_CHECK( n == n2 );
BOOST_CHECK(n == n2);
exactly_the_same_outputs(rtree, output, output2);
exactly_the_same_outputs(rtree, output, rtree | bgi::adaptors::queried(pred));
@ -827,9 +829,13 @@ void intersects(Rtree const& tree, std::vector<Value> const& input, Box const& q
{
std::vector<Value> expected_output;
BOOST_FOREACH(Value const& v, input)
if ( bg::intersects(tree.indexable_get()(v), qbox) )
for (Value const& v : input)
{
if (bg::intersects(tree.indexable_get()(v), qbox))
{
expected_output.push_back(v);
}
}
//spatial_query(tree, qbox, expected_output);
spatial_query(tree, bgi::intersects(qbox), expected_output);
@ -851,9 +857,13 @@ void disjoint(Rtree const& tree, std::vector<Value> const& input, Box const& qbo
{
std::vector<Value> expected_output;
BOOST_FOREACH(Value const& v, input)
if ( bg::disjoint(tree.indexable_get()(v), qbox) )
for (Value const& v : input)
{
if (bg::disjoint(tree.indexable_get()(v), qbox))
{
expected_output.push_back(v);
}
}
spatial_query(tree, bgi::disjoint(qbox), expected_output);
spatial_query(tree, !bgi::intersects(qbox), expected_output);
@ -875,9 +885,13 @@ struct contains_impl
{
std::vector<Value> expected_output;
BOOST_FOREACH(Value const& v, input)
if ( bg::within(qbox, tree.indexable_get()(v)) )
for (Value const& v : input)
{
if (bg::within(qbox, tree.indexable_get()(v)))
{
expected_output.push_back(v);
}
}
spatial_query(tree, bgi::contains(qbox), expected_output);
@ -912,7 +926,7 @@ void contains(Rtree const& tree, std::vector<Value> const& input, Box const& qbo
{
contains_impl<
typename bg::tag<
typename Rtree::indexable_type
typename Rtree::indexable_type
>::type
>::apply(tree, input, qbox);
}
@ -925,12 +939,12 @@ struct covered_by_impl
{
std::vector<Value> expected_output;
BOOST_FOREACH(Value const& v, input)
for (Value const& v : input)
{
if ( bgi::detail::covered_by_bounds(
tree.indexable_get()(v),
qbox,
bgi::detail::get_strategy(tree.parameters())) )
if (bgi::detail::covered_by_bounds(
tree.indexable_get()(v),
qbox,
bgi::detail::get_strategy(tree.parameters())))
{
expected_output.push_back(v);
}
@ -961,7 +975,7 @@ void covered_by(Rtree const& tree, std::vector<Value> const& input, Box const& q
{
covered_by_impl<
typename bg::tag<
typename Rtree::indexable_type
typename Rtree::indexable_type
>::type
>::apply(tree, input, qbox);
}
@ -974,9 +988,13 @@ struct covers_impl
{
std::vector<Value> expected_output;
BOOST_FOREACH(Value const& v, input)
if ( bg::covered_by(qbox, tree.indexable_get()(v)) )
for (Value const& v : input)
{
if (bg::covered_by(qbox, tree.indexable_get()(v)))
{
expected_output.push_back(v);
}
}
spatial_query(tree, bgi::covers(qbox), expected_output);
@ -1011,7 +1029,7 @@ void covers(Rtree const& tree, std::vector<Value> const& input, Box const& qbox)
{
covers_impl<
typename bg::tag<
typename Rtree::indexable_type
typename Rtree::indexable_type
>::type
>::apply(tree, input, qbox);
}
@ -1024,9 +1042,13 @@ struct overlaps_impl
{
std::vector<Value> expected_output;
BOOST_FOREACH(Value const& v, input)
if ( bg::overlaps(tree.indexable_get()(v), qbox) )
for (Value const& v : input)
{
if (bg::overlaps(tree.indexable_get()(v), qbox))
{
expected_output.push_back(v);
}
}
spatial_query(tree, bgi::overlaps(qbox), expected_output);
@ -1061,7 +1083,7 @@ void overlaps(Rtree const& tree, std::vector<Value> const& input, Box const& qbo
{
overlaps_impl<
typename bg::tag<
typename Rtree::indexable_type
typename Rtree::indexable_type
>::type
>::apply(tree, input, qbox);
}
@ -1082,9 +1104,13 @@ void overlaps(Rtree const& tree, std::vector<Value> const& input, Box const& qbo
// {
// std::vector<Value> expected_output;
//
// BOOST_FOREACH(Value const& v, input)
// if ( bg::touches(tree.translator()(v), qbox) )
// for (Value const& v : input)
// {
// if (bg::touches(tree.translator()(v), qbox))
// {
// expected_output.push_back(v);
// }
// }
//
// spatial_query(tree, bgi::touches(qbox), expected_output);
// }
@ -1107,9 +1133,13 @@ struct within_impl
{
std::vector<Value> expected_output;
BOOST_FOREACH(Value const& v, input)
if ( bg::within(tree.indexable_get()(v), qbox) )
for (Value const& v : input)
{
if (bg::within(tree.indexable_get()(v), qbox))
{
expected_output.push_back(v);
}
}
spatial_query(tree, bgi::within(qbox), expected_output);
@ -1172,15 +1202,15 @@ inline void compare_nearest_outputs(Rtree const& rtree, std::vector<Value> const
{
// check output
bool are_sizes_ok = (expected_output.size() == output.size());
BOOST_CHECK( are_sizes_ok );
if ( are_sizes_ok )
BOOST_CHECK(are_sizes_ok);
if (are_sizes_ok)
{
BOOST_FOREACH(Value const& v, output)
for (Value const& v : output)
{
// TODO - perform explicit check here?
// should all objects which are closest be checked and should exactly the same be found?
if ( find(rtree, expected_output.begin(), expected_output.end(), v) == expected_output.end() )
if (find(rtree, expected_output.begin(), expected_output.end(), v) == expected_output.end())
{
Distance d = bg::comparable_distance(pt, rtree.indexable_get()(v));
BOOST_CHECK(d == greatest_distance);
@ -1195,7 +1225,7 @@ inline void check_sorted_by_distance(Rtree const& rtree, std::vector<Value> cons
typedef typename bg::default_distance_result<Point, typename Rtree::indexable_type>::type D;
D prev_dist = 0;
BOOST_FOREACH(Value const& v, output)
for (Value const& v : output)
{
D d = bg::comparable_distance(pt, rtree.indexable_get()(v));
BOOST_CHECK(prev_dist <= d);
@ -1214,25 +1244,31 @@ inline void nearest_query_k(Rtree const& rtree, std::vector<Value> const& input,
std::vector< std::pair<D, Value> > test_output;
// calculate test output - k closest values pairs
BOOST_FOREACH(Value const& v, input)
for (Value const& v : input)
{
D d = bg::comparable_distance(pt, rtree.indexable_get()(v));
if ( test_output.size() < k )
if (test_output.size() < k)
{
test_output.push_back(std::make_pair(d, v));
}
else
{
std::sort(test_output.begin(), test_output.end(), NearestKLess<Rtree, Point>());
if ( d < test_output.back().first )
if (d < test_output.back().first)
{
test_output.back() = std::make_pair(d, v);
}
}
}
// caluclate biggest distance
std::sort(test_output.begin(), test_output.end(), NearestKLess<Rtree, Point>());
D greatest_distance = 0;
if ( !test_output.empty() )
if (! test_output.empty())
{
greatest_distance = test_output.back().first;
}
// transform test output to vector of values
std::vector<Value> expected_output(test_output.size(), generate::value_default<Value>::apply());
@ -1441,8 +1477,10 @@ void create_insert(Rtree const& tree, std::vector<Value> const& input, Box const
{
Rtree t(tree.parameters(), tree.indexable_get(), tree.value_eq(), tree.get_allocator());
BOOST_FOREACH(Value const& v, input)
for (Value const& v : input)
{
t.insert(v);
}
BOOST_CHECK(tree.size() == t.size());
std::vector<Value> output;
t.query(bgi::intersects(qbox), std::back_inserter(output));
@ -1490,8 +1528,10 @@ void create_insert(Rtree const& tree, std::vector<Value> const& input, Box const
{
Rtree t(tree.parameters(), tree.indexable_get(), tree.value_eq(), tree.get_allocator());
BOOST_FOREACH(Value const& v, input)
for (Value const& v : input)
{
bgi::insert(t, v);
}
BOOST_CHECK(tree.size() == t.size());
std::vector<Value> output;
bgi::query(t, bgi::intersects(qbox), std::back_inserter(output));
@ -1538,8 +1578,10 @@ void remove(Rtree const& tree, Box const& qbox)
{
Rtree t(tree);
size_t r = 0;
BOOST_FOREACH(Value const& v, values_to_remove)
for (Value const& v : values_to_remove)
{
r += t.remove(v);
}
BOOST_CHECK( r == expected_removed_count );
std::vector<Value> output;
t.query(bgi::disjoint(qbox), std::back_inserter(output));
@ -1571,8 +1613,10 @@ void remove(Rtree const& tree, Box const& qbox)
{
Rtree t(tree);
size_t r = 0;
BOOST_FOREACH(Value const& v, values_to_remove)
for (Value const& v : values_to_remove)
{
r += bgi::remove(t, v);
}
BOOST_CHECK( r == expected_removed_count );
std::vector<Value> output;
bgi::query(t, bgi::disjoint(qbox), std::back_inserter(output));
@ -1643,7 +1687,7 @@ void range(Rtree & tree, std::vector<Value> const& input)
BOOST_CHECK(count == tree.size());
count = 0;
BOOST_FOREACH(Value const& v, tree)
for (Value const& v : tree)
{
boost::ignore_unused(v);
++count;
@ -1777,7 +1821,7 @@ void test_count_rtree_values(Parameters const& parameters, Allocator const& allo
size_t values_count = Value::counter();
BOOST_FOREACH(Value const& v, values_to_remove)
for (Value const& v : values_to_remove)
{
size_t r = t.remove(v);
--values_count;

View File

@ -4,6 +4,10 @@
// Copyright (c) 2012-2014 Adam Wulkiewicz, Lodz, Poland.
// Copyright (c) 2012-2013 Andrew Hundt.
// This file was modified by Oracle on 2021.
// Modifications copyright (c) 2021, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
@ -55,11 +59,11 @@ void test_ctor_nc(size_t n)
if ( 1 < n )
{
T val10(10);
s[0] = val10;
s[0] = std::move(val10);
BOOST_CHECK(T(10) == s[0]);
BOOST_CHECK(T(10) == s.at(0));
T val20(20);
s.at(1) = val20;
s.at(1) = std::move(val20);
BOOST_CHECK(T(20) == s[1]);
BOOST_CHECK(T(20) == s.at(1));
}
@ -103,11 +107,11 @@ void test_resize_nc(size_t n)
if ( 1 < n )
{
T val10(10);
s[0] = val10;
s[0] = std::move(val10);
BOOST_CHECK(T(10) == s[0]);
BOOST_CHECK(T(10) == s.at(0));
T val20(20);
s.at(1) = val20;
s.at(1) = std::move(val20);
BOOST_CHECK(T(20) == s[1]);
BOOST_CHECK(T(20) == s.at(1));
}

View File

@ -4,6 +4,10 @@
// Copyright (c) 2012-2013 Adam Wulkiewicz, Lodz, Poland.
// Copyright (c) 2012-2013 Andrew Hundt.
// This file was modified by Oracle on 2021.
// Modifications copyright (c) 2021, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
@ -23,9 +27,11 @@ public:
~value_ndc() {}
bool operator==(value_ndc const& v) const { return aa == v.aa; }
bool operator<(value_ndc const& v) const { return aa < v.aa; }
value_ndc(value_ndc const&) = delete;
value_ndc & operator=(value_ndc const&) = delete;
value_ndc(value_ndc&&) = default;
value_ndc & operator=(value_ndc&&) = default;
private:
value_ndc(value_ndc const&) {}
value_ndc & operator=(value_ndc const&) { return *this; }
size_t aa;
};
@ -47,9 +53,11 @@ public:
~value_nc() {}
bool operator==(value_nc const& v) const { return aa == v.aa; }
bool operator<(value_nc const& v) const { return aa < v.aa; }
value_nc(value_nc const&) = delete;
value_nc & operator=(value_nc const&) = delete;
value_nc(value_nc&&) = default;
value_nc & operator=(value_nc&&) = default;
private:
value_nc(value_nc const&) {}
value_nc & operator=(value_ndc const&) { return *this; }
size_t aa;
};

View File

@ -430,7 +430,7 @@ int test_main(int, char* [])
#endif
#if defined(BOOST_GEOMETRY_TEST_FAILURES)
BoostGeometryWriteExpectedFailures(2, 4, 9, 4);
BoostGeometryWriteExpectedFailures(2, 4, 11, 3);
#endif
return 0;

View File

@ -686,7 +686,7 @@ int test_main(int, char* [])
#endif
#if defined(BOOST_GEOMETRY_TEST_FAILURES)
BoostGeometryWriteExpectedFailures(5, 1, 3, 4);
BoostGeometryWriteExpectedFailures(3, 1, 3, 3);
#endif
return 0;

View File

@ -6,6 +6,7 @@
// This file was modified by Oracle on 2014-2021.
// Modifications copyright (c) 2014-2021 Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
@ -31,8 +32,10 @@
#include <boost/geometry/strategies/strategies.hpp>
#include <boost/geometry/strategies/spherical/side_by_cross_track.hpp>
#include <boost/geometry/strategy/cartesian/side_robust.hpp>
#include <boost/geometry/strategy/cartesian/precise_area.hpp>
#include <boost/geometry/strategy/cartesian/side_by_triangle.hpp>
#include <boost/geometry/strategy/cartesian/side_non_robust.hpp>
#include <boost/geometry/strategy/cartesian/side_robust.hpp>
#include <boost/geometry/strategy/cartesian/precise_area.hpp>
#include <boost/geometry/io/wkt/wkt.hpp>
@ -44,7 +47,11 @@ struct robust_cartesian : boost::geometry::strategies::convex_hull::cartesian<>
{
static auto side()
{
return boost::geometry::strategy::side::side_robust<>();
return boost::geometry::strategy::side::side_robust
<
double,
boost::geometry::strategy::side::fp_equals_policy
>();
}
};
@ -75,6 +82,7 @@ struct sphrerical_side_by_cross_track : boost::geometry::strategies::convex_hull
struct precise_cartesian : boost::geometry::strategies::area::cartesian<>
{
// Technically this should be enabled only for non-boxes
template <typename Geometry>
static auto area(Geometry const&)
{
@ -147,6 +155,7 @@ struct test_convex_hull
check_convex_hull(geometry, hull, size_original, size_hull,
expected_area, expected_perimeter, false, AreaStrategy());
bg::clear(hull);
bg::convex_hull(geometry, hull, Strategy());
using point_t = typename bg::point_type<Hull>::type;
@ -207,7 +216,34 @@ struct test_convex_hull<Hull, robust_cartesian, AreaStrategy>
bg::convex_hull(geometry, hull.outer(), robust_cartesian());
check_convex_hull(geometry, hull, size_original, size_hull, expected_area,
expected_perimeter, false, AreaStrategy());
}
};
template
<
typename Hull
>
struct test_convex_hull<Hull, robust_cartesian, precise_cartesian>
{
template <typename Geometry>
static void apply(Geometry const& geometry,
std::size_t size_original,
std::size_t size_hull_closed,
double expected_area,
double expected_perimeter,
bool )
{
static bool const is_hull_closed = bg::closure<Hull>::value != bg::open;
std::size_t const size_hull = is_hull_closed ? size_hull_closed :
size_hull_closed - 1;
// Test version with strategy
Hull hull;
bg::convex_hull(geometry, hull.outer(), robust_cartesian());
check_convex_hull(geometry, hull, size_original, size_hull, expected_area,
expected_perimeter, false, precise_cartesian());
}
};
@ -236,7 +272,6 @@ void test_geometry_order(std::string const& wkt,
Geometry geometry;
bg::read_wkt(wkt, geometry);
test_convex_hull<hull_type, Strategy, AreaStrategy>::apply(geometry, size_original,
size_hull_closed, expected_area, expected_perimeter, !Clockwise);
@ -307,5 +342,4 @@ void test_empty_input()
}
#endif

View File

@ -284,21 +284,12 @@ void test_all()
"LINESTRING(2 8,4 0.4,8 1,0 5)",
expected("iuu++")("mui=+")("tiu+="));
#if ! ( defined(BOOST_CLANG) && defined(BOOST_GEOMETRY_COMPILER_MODE_RELEASE) )
// In clang/release mode this testcase gives other results
// assertion failure in 1.57
// FAILING - no assertion failure but the result is not very good
test_geometry<ls, ls>("LINESTRING(-2305843009213693956 4611686018427387906, -33 -92, 78 83)",
"LINESTRING(31 -97, -46 57, -20 -4)",
expected("")(""));
expected("iuu++"));
test_geometry<ls, ls>("LINESTRING(31 -97, -46 57, -20 -4)",
"LINESTRING(-2305843009213693956 4611686018427387906, -33 -92, 78 83)",
expected("")(""));
#endif
expected("iuu++"));
}
// In 1.57 the results of those combinations was different for MinGW

View File

@ -27,9 +27,11 @@
# include <boost/geometry/io/svg/svg_mapper.hpp>
#endif
#include <boost/geometry/strategy/cartesian/side_robust.hpp>
#include <boost/geometry/strategies/cartesian/side_by_triangle.hpp>
#include <boost/geometry/strategies/side.hpp>
#include <boost/geometry/strategies/side.hpp>
template <typename P, typename T>
void test_with_point(std::string const& /*caseid*/,

View File

@ -46,8 +46,6 @@ void test_all()
{
typedef bg::model::polygon<P> polygon;
typedef typename bg::coordinate_type<P>::type ct;
test_one<polygon, polygon, polygon>("simplex_normal",
simplex_normal[0], simplex_normal[1],
3, 12, 2.52636706856656,
@ -68,10 +66,15 @@ void test_all()
1, 5, 8.0,
1, 5, 8.0);
test_one<polygon, polygon, polygon>("star_comb_15",
star_comb_15[0], star_comb_15[1],
30, -1, 227.658275102812,
30, -1, 480.485775259312);
{
ut_settings settings;
settings.validity_false_negative_sym = true;
test_one<polygon, polygon, polygon>("star_comb_15",
star_comb_15[0], star_comb_15[1],
30, -1, 227.658275102812,
30, -1, 480.485775259312,
settings);
}
test_one<polygon, polygon, polygon>("new_hole",
new_hole[0], new_hole[1],
@ -106,7 +109,7 @@ void test_all()
{
ut_settings settings;
settings.sym_difference_validity = BG_IF_RESCALED(true, false);
settings.validity_false_negative_sym = true;
test_one<polygon, polygon, polygon>("only_hole_intersections1",
only_hole_intersections[0], only_hole_intersections[1],
@ -114,7 +117,7 @@ void test_all()
4, 16, 10.9090909,
settings);
test_one<polygon, polygon, polygon>("only_hole_intersection2",
test_one<polygon, polygon, polygon>("only_hole_intersections2",
only_hole_intersections[0], only_hole_intersections[2],
3, 20, 30.9090909,
4, 16, 10.9090909,
@ -144,7 +147,7 @@ void test_all()
{
ut_settings settings;
settings.sym_difference_validity = BG_IF_RESCALED(false, true);
settings.validity_of_sym = BG_IF_RESCALED(false, true);
test_one<polygon, polygon, polygon>("intersect_holes_intersect_and_disjoint",
intersect_holes_intersect_and_disjoint[0], intersect_holes_intersect_and_disjoint[1],
2, 16, 15.75,
@ -180,7 +183,6 @@ void test_all()
{
ut_settings settings;
settings.sym_difference_validity = BG_IF_RESCALED(false, true);
test_one<polygon, polygon, polygon>("intersect_holes_intersect",
intersect_holes_intersect[0], intersect_holes_intersect[1],
2, 16, 15.75,
@ -295,10 +297,9 @@ void test_all()
1, 61, 10.2717,
1, 61, 10.2717);
if ( BOOST_GEOMETRY_CONDITION((std::is_same<ct, double>::value)) )
{
ut_settings settings;
settings.sym_difference_validity = BG_IF_RESCALED(true, false);
settings.validity_false_negative_sym = true;
TEST_DIFFERENCE_WITH(buffer_mp2, 1, 12.09857, 1, 24.19714,
count_set(1, 2), settings);
}
@ -319,7 +320,7 @@ void test_all()
ut_settings settings;
settings.percentage = BG_IF_RESCALED(0.001, 0.1);
settings.set_test_validity(BG_IF_RESCALED(true, false));
settings.sym_difference = BG_IF_RESCALED(true, false);
settings.sym_difference = false;
// Isovist - the # output polygons differ per compiler/pointtype, (very) small
// rings might be discarded. We check area only
@ -330,18 +331,24 @@ void test_all()
test_one<polygon, polygon, polygon>("isovist",
isovist1[0], isovist1[1],
ignore_count(), -1, 0.279132,
ignore_count(), -1, expectation_limits(0.279128, 0.279132),
ignore_count(), -1, 224.8892,
settings);
}
#if ! defined(BOOST_GEOMETRY_USE_RESCALING) || defined(BOOST_GEOMETRY_TEST_FAILURES)
// SQL Server gives: 0.28937764436705 and 0.000786406897532288 with 44/35 rings
// PostGIS gives: 0.30859375 and 0.033203125 with 35/35 rings
TEST_DIFFERENCE_WITH(geos_1,
ignore_count(), expectation_limits(0.20705, 0.29172),
ignore_count(), expectation_limits(0.00060440758, 0.00076856),
ignore_count(), ut_settings(0.1, false));
{
ut_settings settings(0.1);
settings.set_test_validity(BG_IF_RESCALED(false, true));
settings.validity_false_negative_sym = BG_IF_RESCALED(true, false);
// SQL Server gives: 0.28937764436705 and 0.000786406897532288 with 44/35 rings
// PostGIS gives: 0.30859375 and 0.033203125 with 35/35 rings
TEST_DIFFERENCE_WITH(geos_1,
ignore_count(), expectation_limits(0.20705, 0.29172),
ignore_count(), expectation_limits(0.00060440758, 0.00076856),
ignore_count(), settings);
}
#endif
{
@ -425,7 +432,7 @@ void test_all()
// With rescaling, difference of output a-b and a sym b is invalid
ut_settings settings;
settings.set_test_validity(BG_IF_RESCALED(false, true));
settings.sym_difference_validity = BG_IF_RESCALED(false, true);
settings.validity_of_sym = BG_IF_RESCALED(false, true);
TEST_DIFFERENCE_WITH(ggl_list_20190307_matthieu_1,
count_set(1, 2), 0.18461532,
count_set(1, 2), 0.617978,
@ -563,6 +570,7 @@ void test_all()
{
ut_settings settings;
settings.set_test_validity(BG_IF_RESCALED(true, false));
settings.validity_false_negative_a = true;
TEST_DIFFERENCE_WITH(issue_838,
count_set(1, 2), expectation_limits(0.000026, 0.0002823),
count_set(1, 2), expectation_limits(0.67257, 0.67499),
@ -583,12 +591,16 @@ void test_all()
TEST_DIFFERENCE(mysql_23023665_3, 1, 225.0, 1, 66.0, 2);
TEST_DIFFERENCE(mysql_23023665_5, 2, 165.23735, 2, 105.73735, 4);
{
// Without recaling it is invalid
// Without rescaling it is invalid
ut_settings settings;
settings.set_test_validity(BG_IF_RESCALED(true, false));
settings.set_test_validity(true);
TEST_DIFFERENCE_WITH(mysql_23023665_6, 2, 105.68756, 3, 10.18756, 5, settings);
}
TEST_DIFFERENCE(mysql_23023665_13, 3, 99.74526, 3, 37.74526, 6);
{
ut_settings settings;
settings.validity_false_negative_sym = true;
TEST_DIFFERENCE_WITH(mysql_23023665_13, 3, 99.74526, 3, 37.74526, 6, settings);
}
}
@ -633,7 +645,7 @@ int test_main(int, char* [])
// Not yet fully tested for float and long double.
// The difference algorithm can generate (additional) slivers
// Many of the failures are self-intersection points.
BoostGeometryWriteExpectedFailures(19, 10, 17, 12);
BoostGeometryWriteExpectedFailures(15, 5, 17, 10);
#endif
return 0;

View File

@ -240,8 +240,8 @@ int test_main(int, char* [])
test_all<bg::model::d2::point_xy<double> >();
test_ticket_10835<int>
("MULTILINESTRING((5239 2113,5233 2114),(4794 2205,1020 2986))",
"MULTILINESTRING((5239 2113,5233 2114),(4794 2205,1460 2895))");
("MULTILINESTRING((5239 2113,5232 2115),(4794 2205,1020 2986))",
"MULTILINESTRING((5239 2113,5232 2115),(4794 2205,1460 2895))");
test_ticket_10835<double>
("MULTILINESTRING((5239 2113,5232.52 2114.34),(4794.39 2205,1020 2986))",

View File

@ -155,10 +155,12 @@ void test_areal()
#if ! defined(BOOST_GEOMETRY_USE_RESCALING) || defined(BOOST_GEOMETRY_TEST_FAILURES)
{
// 1: Very small sliver for B (discarded when rescaling)
// 2: sym difference is not considered as valid
// 2: sym difference is not considered as valid (without rescaling
// this is a false negative)
// 3: with rescaling A is considered as invalid (robustness problem)
ut_settings settings;
settings.sym_difference_validity = false;
settings.validity_of_sym = BG_IF_RESCALED(false, true);
settings.validity_false_negative_sym = true;
TEST_DIFFERENCE_WITH(0, 1, bug_21155501,
(count_set(1, 4)), expectation_limits(3.75893, 3.75894),
(count_set(1, 4)), (expectation_limits(1.776357e-15, 7.661281e-15)),
@ -172,7 +174,7 @@ void test_areal()
// Without rescaling, one ring is missing (for a and s)
ut_settings settings;
settings.set_test_validity(BG_IF_RESCALED(false, true));
settings.sym_difference_validity = BG_IF_RESCALED(false, true);
settings.validity_of_sym = BG_IF_RESCALED(false, true);
TEST_DIFFERENCE_WITH(0, 1, ticket_9081,
2, 0.0907392476356186,
4, 0.126018011439877,
@ -211,9 +213,12 @@ void test_areal()
TEST_DIFFERENCE(issue_888_34, 22, 0.2506824, 6, 0.0253798, 28); // a went wrong
TEST_DIFFERENCE(issue_888_37, 15, 0.0451408, 65, 0.3014843, 80); // b went wrong
#if defined(BOOST_GEOMETRY_TEST_FAILURES)
TEST_DIFFERENCE(issue_888_53, 117, 0.2973268, 17, 0.0525798, 134); // a goes wrong
#endif
{
ut_settings settings;
settings.validity_false_negative_a = true;
settings.validity_false_negative_sym = true;
TEST_DIFFERENCE_WITH(0, 1, issue_888_53, 117, 0.2973268, 17, 0.0525798, 134);
}
// Areas and #clips correspond with POSTGIS (except sym case)
test_one<Polygon, MultiPolygon, MultiPolygon>("case_101_multi",
@ -472,24 +477,29 @@ void test_specific_areal()
{
const std::string a_min_b =
TEST_DIFFERENCE(ticket_10661, 2, 1441632.5, 2, 13167454, 4);
test_one<Polygon, MultiPolygon, MultiPolygon>("ticket_10661",
ticket_10661[0], ticket_10661[1],
2, -1, expectation_limits(1441632, 1441855),
2, -1, expectation_limits(13167454, 13182415),
count_set(3, 4));
test_one<Polygon, MultiPolygon, MultiPolygon>("ticket_10661_2",
a_min_b, ticket_10661[2],
1, 8, 825192.0,
1, 10, expectation_limits(27226370, 27842812),
1, -1, 825192.0 + 27226370.5);
1, 10, expectation_limits(27226148, 27842812),
count_set(1, 2));
}
{
ut_settings settings;
settings.sym_difference = false;
TEST_DIFFERENCE_WITH(0, 1, ticket_9942, 4, expectation_limits(7427727.5), 4,
expectation_limits(130083, 131507), 4);
TEST_DIFFERENCE_WITH(0, 1, ticket_9942, 4,
expectation_limits(7427727, 7428108), 4,
expectation_limits(130083, 131823), 4);
TEST_DIFFERENCE_WITH(0, 1, ticket_9942a, 2,
expectation_limits(412676, 413184), 2,
expectation_limits(76779, 76925), 4);
expectation_limits(412676, 413469), 2,
expectation_limits(76779, 77038), 4);
}
}
@ -516,7 +526,7 @@ int test_main(int, char* [])
#if defined(BOOST_GEOMETRY_TEST_FAILURES)
// Not yet fully tested for float.
// The difference algorithm can generate (additional) slivers
BoostGeometryWriteExpectedFailures(28, 15, 19, 10);
BoostGeometryWriteExpectedFailures(24, 11, 21, 7);
#endif
return 0;

View File

@ -20,6 +20,7 @@ void test_spikes_in_ticket_8364()
{
ut_settings ignore_validity;
ignore_validity.set_test_validity(false);
ignore_validity.validity_of_sym = false;
// See: https://svn.boost.org/trac/boost/ticket/8364
//_TPolygon<T> polygon( "MULTIPOLYGON(((1031 1056,3232 1056,3232 2856,1031 2856)))" );
@ -30,44 +31,27 @@ void test_spikes_in_ticket_8364()
//polygon -= _TPolygon<T>( "MULTIPOLYGON(((1032 2556,1032 2130,1778 2556)),((3234 2580,2136 2760,1778 2556,3234 2556)))" ); USED IN STEP 4
// NOTE: polygons below are closed and clockwise
typedef typename bg::coordinate_type<P>::type ct;
typedef bg::model::polygon<P, ClockWise, Closed> polygon;
typedef bg::model::multi_polygon<polygon> multi_polygon;
// The difference of polygons below result in a spike. The spike should be there, it was also generated in ttmath,
// and (e.g.) in SQL Server. However, using int-coordinates, the spike makes the polygon invalid. Therefore it is now (since August 2013) checked and removed.
#ifdef BOOST_GEOMETRY_TEST_FAILURES
// TODO: commented working at ii/validity, this changes the area slightly, to be checked
// So using int's, the spike is removed automatically. Therefore there is one polygon less, and less points. Also area differs
test_one<polygon, multi_polygon, multi_polygon>("ticket_8364_step3",
"MULTIPOLYGON(((3232 2532,2136 2790,1032 1764,1032 1458,1032 1212,2136 2328,3232 2220,3232 1056,1031 1056,1031 2856,3232 2856,3232 2532)))",
"MULTIPOLYGON(((1032 2130,2052 2712,1032 1764,1032 2130)),((3234 2580,3234 2532,2558 2690,3234 2580)),((2558 2690,2136 2760,2052 2712,2136 2790,2558 2690)))",
2,
if_typed<ct, int>(19, 22),
if_typed<ct, int>(2775595.5, 2775256.487954), // SQL Server: 2775256.47588724
3,
-1, // don't check point-count
if_typed<ct, int>(7893.0, 7810.487954), // SQL Server: 7810.48711165739
if_typed<ct, int>(1, 5),
-1,
if_typed<ct, int>(2783349.5, 2775256.487954 + 7810.487954),
ignore_validity);
#endif
count_set(2, 3), -1, expectation_limits(2775256, 2775610), // SQL Server: 2775256.47588724
3, -1, expectation_limits(7810, 7893), // SQL Server: 7810.48711165739
count_set(2, 6), ignore_validity);
// TODO: behaviour is not good yet. It is changed at introduction of self-turns.
test_one<polygon, multi_polygon, multi_polygon>("ticket_8364_step4",
"MULTIPOLYGON(((2567 2688,2136 2790,2052 2712,1032 2130,1032 1764,1032 1458,1032 1212,2136 2328,3232 2220,3232 1056,1031 1056,1031 2856,3232 2856,3232 2580,2567 2688)))",
"MULTIPOLYGON(((1032 2556,1778 2556,1032 2130,1032 2556)),((3234 2580,3234 2556,1778 2556,2136 2760,3234 2580)))",
if_typed<ct, int>(1, 2),
if_typed<ct, int>(17, 20),
if_typed<ct, int>(2615783.5, 2616029.559567), // SQL Server: 2616029.55616044
1,
if_typed<ct, int>(9, 11),
if_typed<ct, int>(161133.5, 161054.559567), // SQL Server: 161054.560110092
if_typed<ct, int>(1, 3),
if_typed<ct, int>(25, 31),
if_typed<ct, int>(2776875.5, 2616029.559567 + 161054.559567));
count_set(1, 2), -1, expectation_limits(2615783, 2616030), // SQL Server: 2616029.55616044
1, -1, expectation_limits(161054, 161134), // SQL Server: 161054.560110092
count_set(1, 3));
}
template <typename P, bool ClockWise, bool Closed>
@ -76,7 +60,6 @@ void test_spikes_in_ticket_8365()
// See: https://svn.boost.org/trac/boost/ticket/8365
// NOTE: polygons below are closed and clockwise
typedef typename bg::coordinate_type<P>::type ct;
typedef bg::model::polygon<P, ClockWise, Closed> polygon;
typedef bg::model::multi_polygon<polygon> multi_polygon;
@ -85,13 +68,11 @@ void test_spikes_in_ticket_8365()
"MULTIPOLYGON(((5388 1560,4650 1722,3912 1884,4650 1398)),((2442 3186,1704 3348,966 2700,1704 3024)))",
2,
18,
if_typed<ct, int>(7975092.5, 7975207.6047877), // SQL Server:
expectation_limits(7975092.5, 7975207.6047877),
2,
-1,
if_typed<ct, int>(196.5, 197.1047877), // SQL Server:
if_typed<ct, int>(3, 4),
-1,
if_typed<ct, int>(7975092.5 + 196.5, 7975207.6047877 + 197.1047877));
expectation_limits(196.5, 198.5),
count_set(2, 4));
}
@ -109,6 +90,7 @@ int test_main(int, char* [])
test_spikes_in_ticket_8364<bg::model::d2::point_xy<int>, false, false>();
test_spikes_in_ticket_8365<bg::model::d2::point_xy<int>, true, true >();
test_spikes_in_ticket_8365<bg::model::d2::point_xy<int>, false, false >();
return 0;
}

View File

@ -59,20 +59,45 @@
# include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
#endif
enum difference_type
{
difference_a, difference_b, difference_sym
};
struct ut_settings : ut_base_settings
{
double percentage;
bool sym_difference;
bool sym_difference_validity = true;
bool validity_of_sym = true;
bool remove_spikes = false;
// The validity check gives sometimes false negatives.
// boost::geometry::is_valid can return FALSE while it is valid.
// (especially at touch in combination with a u/u turn)
// For now, the cases where this is the case are skipped for validity check.
bool validity_false_negative_a = false;
bool validity_false_negative_b = false;
bool validity_false_negative_sym = false;
explicit ut_settings(double p = 0.0001, bool validity = true, bool sd = true)
: ut_base_settings(validity)
, percentage(p)
, sym_difference(sd)
{}
bool test_validity_of_diff(difference_type dtype) const
{
bool const sym = dtype == difference_sym;
bool const a = dtype == difference_a;
bool const b = dtype == difference_b;
return sym && validity_false_negative_sym ? false
: a && validity_false_negative_a ? false
: b && validity_false_negative_b ? false
: sym ? (validity_of_sym || BG_IF_TEST_FAILURES)
: test_validity();
}
};
inline ut_settings tolerance(double percentage)
@ -137,7 +162,7 @@ std::string test_difference(std::string const& caseid, G1 const& g1, G2 const& g
const count_set& expected_count,
int expected_rings_count, int expected_point_count,
expectation_limits const& expected_area,
bool sym,
difference_type dtype,
ut_settings const& settings)
{
typedef typename bg::coordinate_type<G1>::type coordinate_type;
@ -145,8 +170,7 @@ std::string test_difference(std::string const& caseid, G1 const& g1, G2 const& g
bg::model::multi_polygon<OutputType> result;
if (sym)
if (dtype == difference_sym)
{
bg::sym_difference(g1, g2, result);
}
@ -167,7 +191,7 @@ std::string test_difference(std::string const& caseid, G1 const& g1, G2 const& g
<
G1, G2
>::type strategy_type;
if (sym)
if (dtype == difference_sym)
{
bg::sym_difference(g1, g2, result_s, strategy_type());
}
@ -191,12 +215,7 @@ std::string test_difference(std::string const& caseid, G1 const& g1, G2 const& g
typename bg::default_area_result<G1>::type const area = bg::area(result);
#if ! defined(BOOST_GEOMETRY_NO_BOOST_TEST)
bool const test_validity
= sym
? (settings.sym_difference_validity || BG_IF_TEST_FAILURES)
: settings.test_validity();
if (test_validity)
if (settings.test_validity_of_diff(dtype))
{
// std::cout << bg::dsv(result) << std::endl;
typedef bg::model::multi_polygon<OutputType> result_type;
@ -218,7 +237,7 @@ std::string test_difference(std::string const& caseid, G1 const& g1, G2 const& g
typename setop_output_type<OutputType>::type
inserted, array_with_one_empty_geometry;
array_with_one_empty_geometry.push_back(OutputType());
if (sym)
if (dtype == difference_sym)
{
boost::copy(array_with_one_empty_geometry,
bg::detail::sym_difference::sym_difference_insert<OutputType>
@ -287,12 +306,12 @@ template <typename OutputType, typename G1, typename G2>
std::string test_difference(std::string const& caseid, G1 const& g1, G2 const& g2,
const count_set& expected_count, int expected_point_count,
expectation_limits const& expected_area,
bool sym,
difference_type dtype,
ut_settings const& settings)
{
return test_difference<OutputType>(caseid, g1, g2,
expected_count, -1, expected_point_count, expected_area,
sym, settings);
dtype, settings);
}
#ifdef BOOST_GEOMETRY_CHECK_WITH_POSTGIS
@ -331,7 +350,7 @@ std::string test_one(std::string const& caseid,
#if ! defined(BOOST_GEOMETRY_TEST_DIFFERENCE_ONLY_B)
result = test_difference<OutputType>(caseid + "_a", g1, g2,
expected_count1, expected_rings_count1, expected_point_count1,
expected_area1, false, settings);
expected_area1, difference_a, settings);
#endif
#if defined(BOOST_GEOMETRY_TEST_DIFFERENCE_ONLY_A)
return result;
@ -339,7 +358,7 @@ std::string test_one(std::string const& caseid,
test_difference<OutputType>(caseid + "_b", g2, g1,
expected_count2, expected_rings_count2, expected_point_count2,
expected_area2, false, settings);
expected_area2, difference_b, settings);
#if defined(BOOST_GEOMETRY_TEST_DIFFERENCE_ONLY_B)
return result;
@ -354,7 +373,7 @@ std::string test_one(std::string const& caseid,
expected_rings_count_s,
expected_point_count_s,
expected_area_s,
true, settings);
difference_sym, settings);
}
return result;
}
@ -383,6 +402,7 @@ std::string test_one(std::string const& caseid,
settings);
}
// Version with expectations of symmetric: all specified
template <typename OutputType, typename G1, typename G2>
std::string test_one(std::string const& caseid,
std::string const& wkt1, std::string const& wkt2,
@ -404,6 +424,30 @@ std::string test_one(std::string const& caseid,
settings);
}
// Version with expectations of symmetric: specify only count
template <typename OutputType, typename G1, typename G2>
std::string test_one(std::string const& caseid,
std::string const& wkt1, std::string const& wkt2,
const count_set& expected_count1,
int expected_point_count1,
expectation_limits const& expected_area1,
const count_set& expected_count2,
int expected_point_count2,
expectation_limits const& expected_area2,
const count_set& expected_count_s,
ut_settings const& settings = ut_settings())
{
return test_one<OutputType, G1, G2>(caseid, wkt1, wkt2,
expected_count1, -1, expected_point_count1, expected_area1,
expected_count2, -1, expected_point_count2, expected_area2,
expected_count_s, -1,
expected_point_count1 >= 0 && expected_point_count2 >= 0
? (expected_point_count1 + expected_point_count2) : -1,
expected_area1 + expected_area2,
settings);
}
// Version with expectations of symmetric: all automatically
template <typename OutputType, typename G1, typename G2>
std::string test_one(std::string const& caseid,
std::string const& wkt1, std::string const& wkt2,

View File

@ -75,7 +75,7 @@ struct test_sym_difference_of_areal_geometries
PolygonOut
>(case_id, areal1, areal2,
expected_polygon_count, expected_point_count, expected_area,
true, settings);
difference_sym, settings);
}
};

View File

@ -348,7 +348,7 @@ inline void test_aa()
"MULTIPOLYGON(((0 0, 0 5, 5 5, 5 0, 0 0),(0 0, 4 1, 4 4, 1 4, 0 0)),"
"((2 6, 2 8, 8 8, 8 5, 7 5, 7 6, 2 6)))",
"MULTIPOLYGON(((0 0, 1 4, 5 4, 5 1, 4 1, 0 0),(0 0, 2 1, 2 2, 1 2, 0 0)),"
"((5 0, 5 1, 6 1, 6 4, 5 4, 3 6, 2 5, 2 7, 7 7, 7 0 5 0)))",
"((5 0, 5 1, 6 1, 6 4, 5 4, 3 6, 2 5, 2 7, 7 7, 7 0, 5 0)))",
"MULTIPOINT()",
"MULTILINESTRING()",
"MULTIPOLYGON(((0 0,0 5,4 5,3 6,7 6,7 7,2 7,2 8,8 8,8 5,7 5,7 0,0 0),"

View File

@ -1,7 +1,7 @@
// Boost.Geometry
// Robustness Test
// Copyright (c) 2019 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2019-2021 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2021.
// Modifications copyright (c) 2021, Oracle and/or its affiliates.
@ -11,6 +11,8 @@
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#define BOOST_GEOMETRY_NO_ROBUSTNESS
#include <iostream>
#include <iomanip>
#include <fstream>
@ -42,11 +44,22 @@ static std::string case_c[2] =
"MULTIPOLYGON(((1 1,0 1,0 3,1 3,1 1)))"
};
struct test_settings
{
bool verbose{false};
bool do_output{false};
// Settings currently not modifiable, and still giving quite some errors
double start_bound{1.0e-2};
double step_factor{50.0}; // on each side -> 100 steps per factor
int max_factor{10000};
};
template <bg::overlay_type OverlayType, typename Geometry>
bool test_overlay(std::string const& caseid,
Geometry const& g1, Geometry const& g2,
double expected_area,
bool do_output)
test_settings const& settings)
{
typedef typename boost::range_value<Geometry>::type geometry_out;
@ -62,9 +75,9 @@ bool test_overlay(std::string const& caseid,
OverlayType
> overlay;
typedef typename bg::strategy::intersection::services::default_strategy
typedef typename bg::strategies::relate::services::default_strategy
<
typename bg::cs_tag<Geometry>::type
Geometry, Geometry
>::type strategy_type;
strategy_type strategy;
@ -86,7 +99,7 @@ bool test_overlay(std::string const& caseid,
const double detected_area = bg::area(result);
if (std::fabs(detected_area - expected_area) > 0.01)
{
if (do_output)
if (settings.do_output)
{
std::cout << "ERROR: " << caseid << std::setprecision(18)
<< " detected=" << detected_area
@ -118,9 +131,9 @@ template <bg::overlay_type OverlayType, typename MultiPolygon>
std::size_t test_case(std::size_t& error_count,
std::size_t case_index, std::size_t i, std::size_t j,
std::size_t min_vertex_index, std::size_t max_vertex_index,
double x, double y, double expectation,
double offset_x, double offset_y, double expectation,
MultiPolygon const& poly1, MultiPolygon const& poly2,
bool do_output)
test_settings const settings)
{
std::size_t n = 0;
for (std::size_t k = min_vertex_index; k <= max_vertex_index; k++, ++n)
@ -130,21 +143,23 @@ std::size_t test_case(std::size_t& error_count,
switch (case_index)
{
case 2 :
update(bg::interior_rings(poly2_adapted.front()).front(), x, y, k);
update(bg::interior_rings(poly2_adapted.front()).front(), offset_x, offset_y, k);
break;
default :
update(bg::exterior_ring(poly2_adapted.front()), x, y, k);
update(bg::exterior_ring(poly2_adapted.front()), offset_x, offset_y, k);
break;
}
std::ostringstream out;
out << "case_" << i << "_" << j << "_" << k;
if (! test_overlay<OverlayType>(out.str(), poly1, poly2_adapted, expectation, do_output))
if (! test_overlay<OverlayType>(out.str(), poly1, poly2_adapted, expectation, settings))
{
if (error_count == 0)
if (error_count == 0 && ! settings.do_output)
{
// First failure is always reported
test_overlay<OverlayType>(out.str(), poly1, poly2_adapted, expectation, true);
test_settings adapted = settings;
adapted.do_output = true;
test_overlay<OverlayType>(out.str(), poly1, poly2_adapted, expectation, adapted);
}
error_count++;
}
@ -155,7 +170,7 @@ std::size_t test_case(std::size_t& error_count,
template <typename T, bool Clockwise, bg::overlay_type OverlayType>
std::size_t test_all(std::size_t case_index, std::size_t min_vertex_index,
std::size_t max_vertex_index,
double expectation, bool do_output)
double expectation, test_settings const& settings)
{
typedef bg::model::point<T, 2, bg::cs::cartesian> point_type;
typedef bg::model::polygon<point_type, Clockwise> polygon;
@ -177,21 +192,25 @@ std::size_t test_all(std::size_t case_index, std::size_t min_vertex_index,
std::size_t error_count = 0;
std::size_t n = 0;
for (double factor = 1.0; factor > 1.0e-10; factor /= 10.0)
for (int factor = 1; factor < settings.max_factor; factor *= 2)
{
std::size_t i = 0;
double const bound = 1.0e-5 * factor;
double const step = 1.0e-6 * factor;
for (double x = -bound; x <= bound; x += step, ++i)
double const bound = settings.start_bound / factor;
double const step = bound / settings.step_factor;
if (settings.verbose)
{
std::cout << "--> use " << bound << " " << step << std::endl;
}
for (double offset_x = -bound; offset_x <= bound; offset_x += step, ++i)
{
std::size_t j = 0;
for (double y = -bound; y <= bound; y += step, ++j, ++n)
for (double offset_y = -bound; offset_y <= bound; offset_y += step, ++j, ++n)
{
n += test_case<OverlayType>(error_count,
case_index, i, j,
min_vertex_index, max_vertex_index,
x, y, expectation,
poly1, poly2, do_output);
min_vertex_index, max_vertex_index,
offset_x, offset_y, expectation,
poly1, poly2, settings);
}
}
}
@ -205,22 +224,17 @@ std::size_t test_all(std::size_t case_index, std::size_t min_vertex_index,
int test_main(int argc, char** argv)
{
typedef double coordinate_type;
BoostGeometryWriteTestConfiguration();
using coor_t = default_test_type;
const double factor = argc > 1 ? atof(argv[1]) : 2.0;
const bool do_output = argc > 2 && atol(argv[2]) == 1;
test_settings settings;
settings.do_output = argc > 2 && atol(argv[2]) == 1;
std::cout << std::endl << " -> TESTING "
<< string_from_type<coordinate_type>::name()
<< " " << factor
<< std::endl;
test_all<coordinate_type, true, bg::overlay_union>(1, 0, 3, 22.0, do_output);
test_all<coordinate_type, true, bg::overlay_union>(2, 0, 3, 73.0, do_output);
test_all<coordinate_type, true, bg::overlay_intersection>(3, 1, 2, 2.0, do_output);
test_all<coordinate_type, true, bg::overlay_union>(3, 1, 2, 14.0, do_output);
// Test three polygons, for the last test two types of intersections
test_all<coor_t, true, bg::overlay_union>(1, 0, 3, 22.0, settings);
test_all<coor_t, true, bg::overlay_union>(2, 0, 3, 73.0, settings);
test_all<coor_t, true, bg::overlay_intersection>(3, 1, 2, 2.0, settings);
test_all<coor_t, true, bg::overlay_union>(3, 1, 2, 14.0, settings);
return 0;
}
}

View File

@ -1,13 +1,17 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Robustness Test
// Copyright (c) 2009-2020 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2009-2021 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_NO_BOOST_TEST
#define BOOST_GEOMETRY_NO_ROBUSTNESS
#define BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE
// NOTE: there is no randomness here. Count is to measure performance
#include <test_overlay_p_q.hpp>
@ -113,8 +117,10 @@ int main(int argc, char** argv)
("count_y", po::value<int>(&count_y)->default_value(10), "Triangle count in y-direction")
("offset", po::value<int>(&offset)->default_value(0), "Offset of second triangle in x-direction")
("diff", po::value<bool>(&settings.also_difference)->default_value(false), "Include testing on difference")
#if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE)
("ccw", po::value<bool>(&ccw)->default_value(false), "Counter clockwise polygons")
("open", po::value<bool>(&open)->default_value(false), "Open polygons")
#endif
("wkt", po::value<bool>(&settings.wkt)->default_value(false), "Create a WKT of the inputs, for all tests")
("svg", po::value<bool>(&settings.svg)->default_value(false), "Create a SVG for all tests")
;
@ -129,6 +135,7 @@ int main(int argc, char** argv)
return 1;
}
#if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE)
if (ccw && open)
{
test_all<default_test_type, false, false>(count, count_x, count_y, offset, settings);
@ -142,6 +149,7 @@ int main(int argc, char** argv)
test_all<default_test_type, true, false>(count, count_x, count_y, offset, settings);
}
else
#endif
{
test_all<default_test_type, true, true>(count, count_x, count_y, offset, settings);
}

View File

@ -1,13 +1,15 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Robustness Test
// Copyright (c) 2009-2020 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2009-2021 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_NO_BOOST_TEST
#define BOOST_GEOMETRY_NO_ROBUSTNESS
#define BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE
#include <test_overlay_p_q.hpp>
@ -256,8 +258,10 @@ int main(int argc, char** argv)
("help", "Help message")
("multi", po::value<bool>(&multi)->default_value(false), "Multiple tangencies at one point")
("diff", po::value<bool>(&settings.also_difference)->default_value(false), "Include testing on difference")
#if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE)
("ccw", po::value<bool>(&ccw)->default_value(false), "Counter clockwise polygons")
("open", po::value<bool>(&open)->default_value(false), "Open polygons")
#endif
("wkt", po::value<bool>(&settings.wkt)->default_value(false), "Create a WKT of the inputs, for all tests")
("svg", po::value<bool>(&settings.svg)->default_value(false), "Create a SVG for all tests")
;
@ -273,6 +277,7 @@ int main(int argc, char** argv)
}
// template par's are: CoordinateType, Clockwise, Closed
#if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE)
if (ccw && open)
{
test_all<default_test_type, false, false>(multi, single_selftangent, settings);
@ -286,6 +291,7 @@ int main(int argc, char** argv)
test_all<default_test_type, true, false>(multi, single_selftangent, settings);
}
else
#endif
{
test_all<default_test_type, true, true>(multi, single_selftangent, settings);
}

View File

@ -1,13 +1,17 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Robustness Test
// Copyright (c) 2009-2020 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2009-2021 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_NO_BOOST_TEST
#define BOOST_GEOMETRY_NO_ROBUSTNESS
#define BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE
// NOTE: there is no randomness here. Count is to measure performance
#include <test_overlay_p_q.hpp>
@ -109,12 +113,14 @@ void test_type(int count, int min_points, int max_points, T rotation, p_q_settin
template <typename T>
void test_all(std::string const& type, int count, int min_points, int max_points, T rotation, p_q_settings settings)
{
#if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE)
if (type == "float")
{
settings.tolerance = 1.0e-3;
test_type<float, float>(count, min_points, max_points, rotation, settings);
}
else if (type == "double")
#endif
{
test_type<double, double>(count, min_points, max_points, rotation, settings);
}
@ -130,7 +136,7 @@ int main(int argc, char** argv)
int count = 1;
//int seed = static_cast<unsigned int>(std::time(0));
std::string type = "float";
std::string type = "double";
int min_points = 9;
int max_points = 9;
bool ccw = false;
@ -140,15 +146,17 @@ int main(int argc, char** argv)
description.add_options()
("help", "Help message")
//("seed", po::value<int>(&seed), "Initialization seed for random generator")
// ("seed", po::value<int>(&seed), "Initialization seed for random generator")
("count", po::value<int>(&count)->default_value(1), "Number of tests")
("diff", po::value<bool>(&settings.also_difference)->default_value(false), "Include testing on difference")
("min_points", po::value<int>(&min_points)->default_value(9), "Minimum number of points")
("max_points", po::value<int>(&max_points)->default_value(9), "Maximum number of points")
("rotation", po::value<double>(&rotation)->default_value(1.0e-13), "Rotation angle")
#if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE)
("ccw", po::value<bool>(&ccw)->default_value(false), "Counter clockwise polygons")
("open", po::value<bool>(&open)->default_value(false), "Open polygons")
("type", po::value<std::string>(&type)->default_value("float"), "Type (float,double)")
("type", po::value<std::string>(&type)->default_value("double"), "Type (float,double)")
#endif
("wkt", po::value<bool>(&settings.wkt)->default_value(false), "Create a WKT of the inputs, for all tests")
("svg", po::value<bool>(&settings.svg)->default_value(false), "Create a SVG for all tests")
;

View File

@ -1,13 +1,17 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Robustness Test
// Copyright (c) 2011-2020 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2011-2021 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_NO_BOOST_TEST
#define BOOST_GEOMETRY_NO_ROBUSTNESS
#define BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE
// NOTE: there is no randomness here. Count is to measure performance
#include <test_overlay_p_q.hpp>
@ -43,9 +47,8 @@ inline void make_polygon(MultiPolygon& mp, int count_x, int count_y, int index,
}
template <typename MultiPolygon>
void test_intersects(int count_x, int count_y, int width_x, p_q_settings const& settings)
void test_intersects(int index, int count_x, int count_y, int width_x, p_q_settings const& settings)
{
MultiPolygon mp;
@ -64,6 +67,10 @@ void test_intersects(int count_x, int count_y, int width_x, p_q_settings const&
std::ostringstream filename;
filename << "intersects_"
<< string_from_type<coordinate_type>::name()
<< "_" << index
<< "_" << count_x
<< "_" << count_y
<< "_" << width_x
<< ".svg";
std::ofstream svg(filename.str().c_str());
@ -92,7 +99,7 @@ void test_all(int count, int count_x, int count_y, int width_x, p_q_settings con
for(int i = 0; i < count; i++)
{
test_intersects<multi_polygon>(count_x, count_y, width_x, settings);
test_intersects<multi_polygon>(i, count_x, count_y, width_x, settings);
}
auto const t = std::chrono::high_resolution_clock::now();
auto const elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(t - t0).count();
@ -123,8 +130,10 @@ int main(int argc, char** argv)
("count_x", po::value<int>(&count_x)->default_value(10), "Triangle count in x-direction")
("count_y", po::value<int>(&count_y)->default_value(10), "Triangle count in y-direction")
("width_x", po::value<int>(&width_x)->default_value(7), "Width of triangle in x-direction")
#if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE)
("ccw", po::value<bool>(&ccw)->default_value(false), "Counter clockwise polygons")
("open", po::value<bool>(&open)->default_value(false), "Open polygons")
#endif
("wkt", po::value<bool>(&settings.wkt)->default_value(false), "Create a WKT of the inputs, for all tests")
("svg", po::value<bool>(&settings.svg)->default_value(false), "Create a SVG for all tests")
;
@ -139,6 +148,7 @@ int main(int argc, char** argv)
return 1;
}
#if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE)
if (ccw && open)
{
test_all<default_test_type, false, false>(count, count_x, count_y, width_x, settings);
@ -152,6 +162,7 @@ int main(int argc, char** argv)
test_all<default_test_type, true, false>(count, count_x, count_y, width_x, settings);
}
else
#endif
{
test_all<default_test_type, true, true>(count, count_x, count_y, width_x, settings);
}

View File

@ -1,13 +1,15 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Robustness Test
// Copyright (c) 2009-2020 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2009-2021 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_NO_BOOST_TEST
#define BOOST_GEOMETRY_NO_ROBUSTNESS
#define BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE
#include <test_overlay_p_q.hpp>
@ -166,11 +168,13 @@ void test_type(int seed, int count, p_q_settings const& settings)
template <bool Clockwise, bool Closed>
void test_all(std::string const& type, int seed, int count, p_q_settings settings)
{
#if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE)
if (type == "float")
{
test_type<float, Clockwise, Closed>(seed, count, settings);
}
else if (type == "double")
#endif
{
test_type<double, Clockwise, Closed>(seed, count, settings);
}
@ -187,7 +191,7 @@ int main(int argc, char** argv)
int count = 1;
int seed = static_cast<unsigned int>(std::time(0));
std::string type = "float";
std::string type = "double";
bool ccw = false;
bool open = false;
p_q_settings settings;
@ -197,9 +201,11 @@ int main(int argc, char** argv)
("seed", po::value<int>(&seed), "Initialization seed for random generator")
("count", po::value<int>(&count)->default_value(1), "Number of tests")
("diff", po::value<bool>(&settings.also_difference)->default_value(false), "Include testing on difference")
#if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE)
("ccw", po::value<bool>(&ccw)->default_value(false), "Counter clockwise polygons")
("open", po::value<bool>(&open)->default_value(false), "Open polygons")
("type", po::value<std::string>(&type)->default_value("float"), "Type (float,double)")
("type", po::value<std::string>(&type)->default_value("double"), "Type (float,double)")
#endif
("wkt", po::value<bool>(&settings.wkt)->default_value(false), "Create a WKT of the inputs, for all tests")
("svg", po::value<bool>(&settings.svg)->default_value(false), "Create a SVG for all tests")
;
@ -214,6 +220,7 @@ int main(int argc, char** argv)
return 1;
}
#if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE)
if (ccw && open)
{
test_all<false, false>(type, seed, count, settings);
@ -227,6 +234,7 @@ int main(int argc, char** argv)
test_all<true, false>(type, seed, count, settings);
}
else
#endif
{
test_all<true, true>(type, seed, count, settings);
}

View File

@ -1,13 +1,15 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Robustness Test
// Copyright (c) 2009-2020 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2009-2021 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_NO_BOOST_TEST
#define BOOST_GEOMETRY_NO_ROBUSTNESS
#define BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE
#include <test_overlay_p_q.hpp>
@ -174,8 +176,10 @@ int main(int argc, char** argv)
("level", po::value<int>(&level)->default_value(3), "Level to reach (higher->slower)")
("size", po::value<int>(&field_size)->default_value(10), "Size of the field")
("form", po::value<std::string>(&form)->default_value("box"), "Form of the polygons (box, triangle)")
#if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE)
("ccw", po::value<bool>(&ccw)->default_value(false), "Counter clockwise polygons")
("open", po::value<bool>(&open)->default_value(false), "Open polygons")
#endif
("wkt", po::value<bool>(&settings.wkt)->default_value(false), "Create a WKT of the inputs, for all tests")
("svg", po::value<bool>(&settings.svg)->default_value(false), "Create a SVG for all tests")
;
@ -193,7 +197,7 @@ int main(int argc, char** argv)
bool triangular = form != "box";
#if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE)
if (ccw && open)
{
test_all<default_test_type, false, false>(seed, count, field_size, level, triangular, settings);
@ -207,6 +211,7 @@ int main(int argc, char** argv)
test_all<default_test_type, true, false>(seed, count, field_size, level, triangular, settings);
}
else
#endif
{
test_all<default_test_type, true, true>(seed, count, field_size, level, triangular, settings);
}

View File

@ -1,13 +1,15 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Robustness Test
// Copyright (c) 2009-2020 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2009-2021 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_NO_BOOST_TEST
#define BOOST_GEOMETRY_NO_ROBUSTNESS
#define BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE
#include <test_overlay_p_q.hpp>
@ -98,8 +100,10 @@ int main(int argc, char** argv)
("count", po::value<int>(&count)->default_value(1), "Number of tests")
("point_count", po::value<int>(&point_count)->default_value(1), "Number of points in the star")
("diff", po::value<bool>(&settings.also_difference)->default_value(false), "Include testing on difference")
#if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE)
("ccw", po::value<bool>(&ccw)->default_value(false), "Counter clockwise polygons")
("open", po::value<bool>(&open)->default_value(false), "Open polygons")
#endif
("wkt", po::value<bool>(&settings.wkt)->default_value(false), "Create a WKT of the inputs, for all tests")
("svg", po::value<bool>(&settings.svg)->default_value(false), "Create a SVG for all tests")
;
@ -117,7 +121,7 @@ int main(int argc, char** argv)
int star_point_count = point_count * 2 + 1;
int comb_comb_count = point_count;
#if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE)
if (ccw && open)
{
test_all<default_test_type, false, false>(count, star_point_count, comb_comb_count, factor1, factor2, do_union, settings);
@ -131,6 +135,7 @@ int main(int argc, char** argv)
test_all<default_test_type, true, false>(count, star_point_count, comb_comb_count, factor1, factor2, do_union, settings);
}
else
#endif
{
test_all<default_test_type, true, true>(count, star_point_count, comb_comb_count, factor1, factor2, do_union, settings);
}

View File

@ -1,7 +1,7 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Robustness Test
// Copyright (c) 2009-2020 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2009-2021 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2021.
// Modifications copyright (c) 2021, Oracle and/or its affiliates.
@ -40,21 +40,16 @@
struct p_q_settings
{
bool svg;
bool also_difference;
bool validity;
bool wkt;
bool verify_area;
double tolerance;
bool svg{false};
bool also_difference{false};
bool validity{false};
bool wkt{false};
bool verify_area{false};
double tolerance{1.0e-3};
bool verbose{false};
p_q_settings()
: svg(false)
, also_difference(false)
, validity(false)
, wkt(false)
, verify_area(false)
, tolerance(1.0e-3) // since rescaling to integer the tolerance should be less. Was originally 1.0e-6
{}
// NOTE: since rescaling to integer the tolerance is less.
// Was originally 1.0e-6 TODO: restore
};
template <typename Geometry>
@ -209,6 +204,7 @@ static bool test_overlay_p_q(std::string const& caseid,
}
bool svg = settings.svg;
bool wkt = settings.wkt;
if (wrong || settings.wkt)
{
@ -216,53 +212,66 @@ static bool test_overlay_p_q(std::string const& caseid,
{
result = false;
svg = true;
wkt = true;
}
bg::unique(out_i);
bg::unique(out_u);
std::cout
<< "type: " << string_from_type<CalculationType>::name()
<< " id: " << caseid
<< " area i: " << area_i
<< " area u: " << area_u
<< " area p: " << area_p
<< " area q: " << area_q
<< " sum: " << sum;
if (settings.also_difference)
if (settings.verbose)
{
std::cout
<< " area d1: " << area_d1
<< " area d2: " << area_d2;
}
std::cout
<< std::endl
<< std::setprecision(9)
<< " p: " << bg::wkt(p) << std::endl
<< " q: " << bg::wkt(q) << std::endl
<< " i: " << bg::wkt(out_i) << std::endl
<< " u: " << bg::wkt(out_u) << std::endl
;
<< "type: " << string_from_type<CalculationType>::name()
<< " id: " << caseid
<< " area i: " << area_i
<< " area u: " << area_u
<< " area p: " << area_p
<< " area q: " << area_q
<< " sum: " << sum;
if (settings.also_difference)
{
std::cout
<< " area d1: " << area_d1
<< " area d2: " << area_d2;
}
std::cout
<< std::endl
<< std::setprecision(9)
<< " p: " << bg::wkt(p) << std::endl
<< " q: " << bg::wkt(q) << std::endl
<< " i: " << bg::wkt(out_i) << std::endl
<< " u: " << bg::wkt(out_u) << std::endl;
}
}
if(svg)
std::string filename;
{
std::ostringstream filename;
filename << "overlay_" << caseid << "_"
std::ostringstream out;
out << "overlay_" << caseid << "_"
<< string_from_type<coordinate_type>::name();
if (!std::is_same<coordinate_type, CalculationType>::value)
{
filename << string_from_type<CalculationType>::name();
out << string_from_type<CalculationType>::name();
}
filename
out
#if defined(BOOST_GEOMETRY_USE_RESCALING)
<< "_rescaled"
<< "_rescaled"
#endif
<< ".svg";
<< ".";
filename = out.str();
}
std::ofstream svg(filename.str().c_str());
if (wkt)
{
std::ofstream stream(filename + "wkt");
// Stream input WKT's
stream << bg::wkt(p) << std::endl;
stream << bg::wkt(q) << std::endl;
// If you need the output WKT, then stream out_i and out_u
}
if (svg)
{
std::ofstream svg(filename + "svg");
bg::svg_mapper<point_type> mapper(svg, 500, 500);

View File

@ -1,7 +1,7 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Robustness Test
// Copyright (c) 2012-2020 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2012-2021 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2015-2021.
// Modifications copyright (c) 2015-2021 Oracle and/or its affiliates.
@ -13,6 +13,8 @@
// http://www.boost.org/LICENSE_1_0.txt)
#define BOOST_GEOMETRY_NO_BOOST_TEST
#define BOOST_GEOMETRY_NO_ROBUSTNESS
#define BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE
#if defined(_MSC_VER)
# pragma warning( disable : 4244 )

View File

@ -27,7 +27,7 @@
#include <boost/geometry/strategies/spherical/side_by_cross_track.hpp>
//#include <boost/geometry/strategies/spherical/side_via_plane.hpp>
#include <boost/geometry/strategies/spherical/ssf.hpp>
#include <boost/geometry/strategies/cartesian/side_by_triangle.hpp>
#include <boost/geometry/strategy/cartesian/side_robust.hpp>
#include <boost/geometry/strategies/geographic/mapping_ssf.hpp>
#include <boost/geometry/strategies/geographic/side_andoyer.hpp>

View File

@ -21,6 +21,8 @@
#include <boost/geometry/algorithms/covered_by.hpp>
#include <boost/geometry/algorithms/within.hpp>
#include <boost/geometry/strategy/cartesian/side_robust.hpp>
#include <boost/geometry/strategies/cartesian/point_in_poly_franklin.hpp>
#include <boost/geometry/strategies/cartesian/point_in_poly_crossings_multiply.hpp>
#include <boost/geometry/strategies/agnostic/point_in_poly_winding.hpp>
@ -28,7 +30,6 @@
#include <boost/geometry/strategies/cartesian/box_in_box.hpp>
#include <boost/geometry/strategies/agnostic/point_in_box_by_side.hpp>
#include <boost/geometry/strategies/cartesian/side_by_triangle.hpp>
#include <boost/geometry/strategies/spherical/ssf.hpp>
// TEMP