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

This commit is contained in:
Vissarion Fisikopoulos 2021-11-05 09:24:07 +02:00
commit ea0df6db82
62 changed files with 1554 additions and 974 deletions

View File

@ -0,0 +1,34 @@
# Boost.Geometry
# Example CMakeLists.txt building the Boost.Geometry with wxWidget example
#
# Copyright (c) 2021-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)
cmake_minimum_required(VERSION 3.10)
project(with_external_libs)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED True)
# Set BOOST_ROOT in your environment (this is cmake default)
find_package(Boost)
# Set WX_ROOT, similarly, also in your environment
set(WX_ROOT $ENV{WX_ROOT})
message(STATUS "Using wxWidgets from this folder: " $ENV{WX_ROOT})
# WX Widgets
link_directories(${WX_ROOT}/lib)
add_executable(wx x04_wxwidgets_world_mapper.cpp)
target_include_directories(wx PRIVATE ${Boost_INCLUDE_DIRS})
target_include_directories(wx PRIVATE ${WX_ROOT}/include)
target_include_directories(wx PRIVATE ${WX_ROOT}/include/wx-3.1)
# WX configuration (get the values using wx-config --cxxflags and wx-config --libs)
target_compile_definitions(wx PRIVATE WXUSINGDLL __WXGTK2__ __WXGTK__)
target_link_libraries(wx PRIVATE wx_gtk2u_html-3.1 wx_gtk2u_core-3.1 wx_baseu_net-3.1 wx_baseu-3.1)

View File

@ -1,115 +1,62 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Boost.Geometry
//
// Copyright (c) 2010-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2010-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)
//
// wxWidgets World Mapper example
//
// It will show a basic wxWidgets window, displaying world countries,
// highlighting the country under the mouse, and indicating position
// of the mouse in latitude/longitude and in pixels.
// To compile this program:
// Install wxWidgets (if not done before)
// export BOOST_ROOT=.....
// export WX_ROOT=.... (for example /home/myname/mylib/wxWidgets/Linux/x86_64)
// mkdir build
// cd build
// cmake .. -G Ninja
// ninja
// If necessary, CMakeLists.txt should be adapted, the options for wx
// are provided by "wx-config --cxxflags" and "... --libs"
// and might need a change in CMakeLists.txt
// #define EXAMPLE_WX_USE_GRAPHICS_CONTEXT 1
//#define EXAMPLE_WX_USE_GRAPHICS_CONTEXT 1
#include <fstream>
#include <sstream>
#include <boost/foreach.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/scoped_array.hpp>
#include <boost/geometry/geometry.hpp>
#include <boost/geometry/geometries/geometries.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/multi_geometries.hpp>
#include <boost/geometry/geometries/multi_polygon.hpp>
#include <boost/geometry/geometries/register/point.hpp>
#include <boost/geometry/geometries/register/ring.hpp>
#include <boost/geometry/extensions/algorithms/selected.hpp>
// wxWidgets, if these headers are NOT found, adapt include path (and lib path)
#include "wx/wx.h"
#include "wx/math.h"
#include "wx/stockitem.h"
#ifdef EXAMPLE_WX_USE_GRAPHICS_CONTEXT
#include "wx/graphics.h"
#include "wx/dcgraph.h"
#endif
typedef boost::geometry::model::d2::point_xy<double> point_2d;
typedef boost::geometry::model::multi_polygon
using point_2d = boost::geometry::model::d2::point_xy<double>;
using country_type = boost::geometry::model::multi_polygon
<
boost::geometry::model::polygon<point_2d>
> country_type;
>;
// Adapt wxWidgets points to Boost.Geometry points such that they can be used
// in e.g. transformations (see below)
BOOST_GEOMETRY_REGISTER_POINT_2D(wxPoint, int, cs::cartesian, x, y)
BOOST_GEOMETRY_REGISTER_POINT_2D(wxRealPoint, double, cs::cartesian, x, y)
// wxWidgets draws using wxPoint*, so we HAVE to use that.
// Therefore have to make a wxPoint* array
// 1) compatible with Boost.Geometry
// 2) compatible with Boost.Range (required by Boost.Geometry)
// 3) compatible with std::back_inserter (required by Boost.Geometry)
// For compatible 2):
typedef std::pair<wxPoint*,wxPoint*> wxPointPointerPair;
// For compatible 1):
BOOST_GEOMETRY_REGISTER_RING(wxPointPointerPair);
// For compatible 3):
// Specialize back_insert_iterator for the wxPointPointerPair
// (has to be done within "namespace std")
namespace std
{
template <>
class back_insert_iterator<wxPointPointerPair>
{
public:
typedef std::output_iterator_tag iterator_category;
typedef void value_type;
typedef void difference_type;
typedef void pointer;
typedef void reference;
typedef wxPointPointerPair container_type;
explicit back_insert_iterator(wxPointPointerPair& x)
: current(boost::begin(x))
, end(boost::end(x))
{}
inline back_insert_iterator<wxPointPointerPair>&
operator=(wxPoint const& value)
{
// Check if not passed beyond
if (current != end)
{
*current++ = value;
}
return *this;
}
// Boiler-plate
inline back_insert_iterator<wxPointPointerPair>& operator*() { return *this; }
inline back_insert_iterator<wxPointPointerPair>& operator++() { return *this; }
inline back_insert_iterator<wxPointPointerPair>& operator++(int) { return *this; }
private:
boost::range_iterator<wxPointPointerPair>::type current, end;
};
} // namespace std
// ----------------------------------------------------------------------------
// Read an ASCII file containing WKT's
// ----------------------------------------------------------------------------
@ -161,26 +108,29 @@ private:
void OnPaint(wxPaintEvent& );
void OnMouseMove(wxMouseEvent&);
typedef boost::geometry::strategy::transform::map_transformer
using map_transformer_type = boost::geometry::strategy::transform::map_transformer
<
double, 2, 2,
true, true
> map_transformer_type;
>;
typedef boost::geometry::strategy::transform::inverse_transformer
using inverse_transformer_type = boost::geometry::strategy::transform::inverse_transformer
<
double, 2, 2
> inverse_transformer_type;
>;
boost::shared_ptr<map_transformer_type> m_map_transformer;
boost::shared_ptr<inverse_transformer_type> m_inverse_transformer;
std::shared_ptr<map_transformer_type> m_map_transformer;
std::shared_ptr<inverse_transformer_type> m_inverse_transformer;
boost::geometry::model::box<point_2d> m_box;
std::vector<country_type> m_countries;
int m_focus;
int m_focus = -1;
wxBrush m_orange;
wxFrame* m_owner;
wxBrush m_orange = wxBrush(wxColour(255, 128, 0), wxBRUSHSTYLE_SOLID);
wxBrush m_blue = wxBrush(wxColour(0, 128, 255), wxBRUSHSTYLE_SOLID);
wxBrush m_green = wxBrush(wxColour(0, 255, 0), wxBRUSHSTYLE_SOLID);
wxFrame* m_owner = nullptr;
DECLARE_EVENT_TABLE()
};
@ -244,19 +194,14 @@ void HelloWorldFrame::OnCloseWindow(wxCloseEvent& )
HelloWorldCanvas::HelloWorldCanvas(wxFrame *frame)
: wxWindow(frame, wxID_ANY)
, m_owner(frame)
, m_focus(-1)
{
boost::geometry::assign_inverse(m_box);
read_wkt("../data/world.wkt", m_countries, m_box);
m_orange = wxBrush(wxColour(255, 128, 0), wxSOLID);
}
void HelloWorldCanvas::OnMouseMove(wxMouseEvent &event)
{
namespace bg = boost::geometry;
if (m_inverse_transformer)
{
// Boiler-plate wxWidgets code
@ -264,19 +209,21 @@ void HelloWorldCanvas::OnMouseMove(wxMouseEvent &event)
PrepareDC(dc);
m_owner->PrepareDC(dc);
// Transform the point to Lon/Lat
// Transform the point opn the screen back to Lon/Lat
point_2d point;
bg::transform(event.GetPosition(), point, *m_inverse_transformer);
boost::geometry::transform(event.GetPosition(), point,
*m_inverse_transformer);
// Determine selected object
int i = 0;
int previous_focus = m_focus;
m_focus = -1;
BOOST_FOREACH(country_type const& country, m_countries)
for (country_type const& country : m_countries)
{
if (bg::selected(country, point, 0))
if (boost::geometry::within(point, country))
{
m_focus = i;
break;
}
i++;
}
@ -287,7 +234,7 @@ void HelloWorldCanvas::OnMouseMove(wxMouseEvent &event)
// Undraw old focus
if (previous_focus >= 0)
{
dc.SetBrush(*wxWHITE_BRUSH);
dc.SetBrush(m_green);
DrawCountry(dc, m_countries[previous_focus]);
}
// Draw new focus
@ -309,6 +256,11 @@ void HelloWorldCanvas::OnMouseMove(wxMouseEvent &event)
void HelloWorldCanvas::OnPaint(wxPaintEvent& )
{
if (m_countries.empty())
{
return;
}
#if defined(EXAMPLE_WX_USE_GRAPHICS_CONTEXT)
wxPaintDC pdc(this);
wxGCDC gdc(pdc);
@ -340,11 +292,12 @@ void HelloWorldCanvas::DrawCountries(wxDC& dc)
{
namespace bg = boost::geometry;
dc.SetBackground(*wxLIGHT_GREY_BRUSH);
dc.SetBackground(m_blue);
dc.Clear();
BOOST_FOREACH(country_type const& country, m_countries)
for (country_type const& country : m_countries)
{
dc.SetBrush(m_green);
DrawCountry(dc, country);
}
if (m_focus != -1)
@ -357,27 +310,23 @@ void HelloWorldCanvas::DrawCountries(wxDC& dc)
void HelloWorldCanvas::DrawCountry(wxDC& dc, country_type const& country)
{
namespace bg = boost::geometry;
BOOST_FOREACH(bg::model::polygon<point_2d> const& poly, country)
for (auto const& poly : country)
{
// Use only exterior ring, holes are (for the moment) ignored. This would need
// a holey-polygon compatible wx object
// Use only exterior ring, holes are (for the moment) ignored.
// This would need a holey-polygon compatible wx object
std::size_t n = boost::size(bg::exterior_ring(poly));
boost::scoped_array<wxPoint> points(new wxPoint[n]);
wxPointPointerPair pair = std::make_pair(points.get(), points.get() + n);
bg::transform(bg::exterior_ring(poly), pair, *m_map_transformer);
dc.DrawPolygon(n, points.get());
// Define a Boost.Geometry ring of wxPoints
// Behind the scenes that is a vector, and a vector has .data(),
// can be used for the *wxPoint pointer needed for wxWidget DrawPolygon
boost::geometry::model::ring<wxPoint> ring;
boost::geometry::transform(boost::geometry::exterior_ring(poly), ring,
*m_map_transformer);
dc.DrawPolygon(ring.size(), ring.data());
}
}
// ----------------------------------------------------------------------------
BEGIN_EVENT_TABLE(HelloWorldFrame, wxFrame)
EVT_CLOSE(HelloWorldFrame::OnCloseWindow)
EVT_MENU(wxID_EXIT, HelloWorldFrame::OnExit)

View File

@ -1,23 +0,0 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
//
// Copyright Barend Gehrels 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)
wxWidgets World Mapper example
It will show a basic wxWidgets window, displaying world countries, highlighting the country under
the mouse, and indicating position of the mouse in latitude/longitude and in pixels.
To compile this program:
Install wxWidgets (if not done before)
Using Linux/gcc
- check if installation is OK, http://wiki.wxwidgets.org/Installing_and_configuring_under_Ubuntu
- compile using e.g. gcc -o x04_wxwidgets -I../../../.. x04_wxwidgets_world_mapper.cpp `wx-config --cxxflags` `wx-config --libs`

View File

@ -28,9 +28,6 @@
#include <boost/range/end.hpp>
#include <boost/range/size.hpp>
#include <boost/throw_exception.hpp>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/cs.hpp>
@ -41,15 +38,18 @@
#include <boost/geometry/core/tag_cast.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/visit.hpp>
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/algorithms/detail/centroid/translating_transformer.hpp>
#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
#include <boost/geometry/algorithms/detail/point_on_border.hpp>
#include <boost/geometry/algorithms/detail/visit.hpp>
#include <boost/geometry/algorithms/is_empty.hpp>
#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/geometries/adapted/boost_variant.hpp> // For backward compatibility
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/strategies/centroid/cartesian.hpp>
@ -61,6 +61,7 @@
#include <boost/geometry/util/algorithm.hpp>
#include <boost/geometry/util/select_coordinate_type.hpp>
#include <boost/geometry/util/type_traits_std.hpp>
#include <boost/geometry/views/closeable_view.hpp>
@ -540,9 +541,9 @@ struct centroid<default_strategy, false>
} // namespace resolve_strategy
namespace resolve_variant {
namespace resolve_dynamic {
template <typename Geometry>
template <typename Geometry, typename Tag = typename tag<Geometry>::type>
struct centroid
{
template <typename Point, typename Strategy>
@ -553,37 +554,22 @@ struct centroid
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct centroid<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
template <typename Geometry>
struct centroid<Geometry, dynamic_geometry_tag>
{
template <typename Point, typename Strategy>
struct visitor: boost::static_visitor<void>
static inline void apply(Geometry const& geometry,
Point& out,
Strategy const& strategy)
{
Point& m_out;
Strategy const& m_strategy;
visitor(Point& out, Strategy const& strategy)
: m_out(out), m_strategy(strategy)
{}
template <typename Geometry>
void operator()(Geometry const& geometry) const
traits::visit<Geometry>::apply([&](auto const& g)
{
centroid<Geometry>::apply(geometry, m_out, m_strategy);
}
};
template <typename Point, typename Strategy>
static inline void
apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
Point& out,
Strategy const& strategy)
{
boost::apply_visitor(visitor<Point, Strategy>(out, strategy), geometry);
centroid<util::remove_cref_t<decltype(g)>>::apply(g, out, strategy);
}, geometry);
}
};
} // namespace resolve_variant
} // namespace resolve_dynamic
/*!
@ -604,10 +590,9 @@ struct centroid<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
*/
template<typename Geometry, typename Point, typename Strategy>
inline void centroid(Geometry const& geometry, Point& c,
Strategy const& strategy)
inline void centroid(Geometry const& geometry, Point& c, Strategy const& strategy)
{
resolve_variant::centroid<Geometry>::apply(geometry, c, strategy);
resolve_dynamic::centroid<Geometry>::apply(geometry, c, strategy);
}

View File

@ -11,8 +11,14 @@
#define BOOST_GEOMETRY_ALGORITHMS_DENSIFY_HPP
#include <boost/range/size.hpp>
#include <boost/range/value_type.hpp>
#include <boost/throw_exception.hpp>
#include <boost/geometry/algorithms/clear.hpp>
#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
#include <boost/geometry/algorithms/detail/visit.hpp>
#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/cs.hpp>
@ -20,6 +26,8 @@
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/visit.hpp>
#include <boost/geometry/geometries/adapted/boost_variant.hpp> // For backward compatibility
#include <boost/geometry/strategies/default_strategy.hpp>
#include <boost/geometry/strategies/densify/cartesian.hpp>
#include <boost/geometry/strategies/densify/geographic.hpp>
@ -28,11 +36,6 @@
#include <boost/geometry/util/condition.hpp>
#include <boost/geometry/util/range.hpp>
#include <boost/range/size.hpp>
#include <boost/range/value_type.hpp>
#include <boost/throw_exception.hpp>
namespace boost { namespace geometry
{
@ -146,6 +149,15 @@ struct densify_ring<true, false>
: densify_range<false>
{};
struct densify_convert
{
template <typename GeometryIn, typename GeometryOut, typename T, typename Strategy>
static void apply(GeometryIn const& in, GeometryOut &out,
T const& , Strategy const& )
{
geometry::convert(in, out);
}
};
}} // namespace detail::densify
#endif // DOXYGEN_NO_DETAIL
@ -167,6 +179,26 @@ struct densify
: not_implemented<Tag1, Tag2>
{};
template <typename Geometry, typename GeometryOut>
struct densify<Geometry, GeometryOut, point_tag, point_tag>
: geometry::detail::densify::densify_convert
{};
template <typename Geometry, typename GeometryOut>
struct densify<Geometry, GeometryOut, segment_tag, segment_tag>
: geometry::detail::densify::densify_convert
{};
template <typename Geometry, typename GeometryOut>
struct densify<Geometry, GeometryOut, box_tag, box_tag>
: geometry::detail::densify::densify_convert
{};
template <typename Geometry, typename GeometryOut>
struct densify<Geometry, GeometryOut, multi_point_tag, multi_point_tag>
: geometry::detail::densify::densify_convert
{};
template <typename Geometry, typename GeometryOut>
struct densify<Geometry, GeometryOut, linestring_tag, linestring_tag>
: geometry::detail::densify::densify_range<>
@ -328,9 +360,9 @@ struct densify<default_strategy, false>
} // namespace resolve_strategy
namespace resolve_variant {
namespace resolve_dynamic {
template <typename Geometry>
template <typename Geometry, typename Tag = typename tag<Geometry>::type>
struct densify
{
template <typename Distance, typename Strategy>
@ -346,43 +378,48 @@ struct densify
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct densify<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
template <typename Geometry>
struct densify<Geometry, dynamic_geometry_tag>
{
template <typename Distance, typename Strategy>
struct visitor: boost::static_visitor<void>
{
Distance const& m_max_distance;
Strategy const& m_strategy;
visitor(Distance const& max_distance, Strategy const& strategy)
: m_max_distance(max_distance)
, m_strategy(strategy)
{}
template <typename Geometry>
void operator()(Geometry const& geometry, Geometry& out) const
{
densify<Geometry>::apply(geometry, out, m_max_distance, m_strategy);
}
};
template <typename Distance, typename Strategy>
static inline void
apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& out,
apply(Geometry const& geometry,
Geometry& out,
Distance const& max_distance,
Strategy const& strategy)
{
boost::apply_visitor(
visitor<Distance, Strategy>(max_distance, strategy),
geometry,
out
);
traits::visit<Geometry>::apply([&](auto const& g)
{
using geom_t = util::remove_cref_t<decltype(g)>;
geom_t o;
densify<geom_t>::apply(g, o, max_distance, strategy);
out = std::move(o);
}, geometry);
}
};
} // namespace resolve_variant
template <typename Geometry>
struct densify<Geometry, geometry_collection_tag>
{
template <typename Distance, typename Strategy>
static inline void
apply(Geometry const& geometry,
Geometry& out,
Distance const& max_distance,
Strategy const& strategy)
{
detail::visit_breadth_first([&](auto const& g)
{
using geom_t = util::remove_cref_t<decltype(g)>;
geom_t o;
densify<geom_t>::apply(g, o, max_distance, strategy);
traits::emplace_back<Geometry>::apply(out, std::move(o));
return true;
}, geometry);
}
};
} // namespace resolve_dynamic
/*!
@ -428,7 +465,7 @@ inline void densify(Geometry const& geometry,
geometry::clear(out);
resolve_variant::densify
resolve_dynamic::densify
<
Geometry
>::apply(geometry, out, max_distance, strategy);

View File

@ -120,14 +120,14 @@ public:
decltype(strategies.distance(point, range))
>::apply(strategies.distance(point, range));
auto it_pair = point_to_point_range::apply(point,
boost::begin(range),
boost::end(range),
comparable_distance,
cd_min);
auto closest_segment = point_to_point_range::apply(point,
boost::begin(range),
boost::end(range),
comparable_distance,
cd_min);
auto closest_point = strategies.closest_points(point, range)
.apply(point, it_pair->first, it_pair->second);
.apply(point, *closest_segment.first, *closest_segment.second);
set_segment_from_points::apply(point, closest_point, shortest_seg);
}

View File

@ -98,7 +98,7 @@ struct input_geometry_collection_proxy
{
detail::visit_breadth_first([&](auto const& g)
{
call_for_non_boxes(g, fun);
input_geometry_collection_proxy::call_for_non_boxes(g, fun);
return true;
}, m_geometry);
@ -262,7 +262,7 @@ struct convex_hull<GeometryCollection, geometry_collection_tag>
std::vector<ring_type> box_rings;
detail::visit_breadth_first([&](auto const& g)
{
add_ring_for_box(box_rings, g, strategy);
convex_hull::add_ring_for_box(box_rings, g, strategy);
return true;
}, geometry);

View File

@ -0,0 +1,237 @@
// 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_ALGORITHMS_DETAIL_DISTANCE_GEOMETRY_COLLECTION_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_GEOMETRY_COLLECTION_HPP
#include <vector>
#include <boost/geometry/algorithms/dispatch/distance.hpp>
#include <boost/geometry/algorithms/detail/visit.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/index/rtree.hpp>
#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/strategies/distance_result.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace distance
{
template <typename Geometry, typename GeometryCollection, typename Strategies>
inline auto geometry_to_collection(Geometry const& geometry,
GeometryCollection const& collection,
Strategies const& strategies)
{
using result_t = typename geometry::distance_result<Geometry, GeometryCollection, Strategies>::type;
result_t result = 0;
bool is_first = true;
detail::visit_breadth_first([&](auto const& g)
{
result_t r = dispatch::distance
<
Geometry, util::remove_cref_t<decltype(g)>, Strategies
>::apply(geometry, g, strategies);
if (is_first)
{
result = r;
is_first = false;
}
else if (r < result)
{
result = r;
}
return result > result_t(0);
}, collection);
return result;
}
template <typename GeometryCollection1, typename GeometryCollection2, typename Strategies>
inline auto collection_to_collection(GeometryCollection1 const& collection1,
GeometryCollection2 const& collection2,
Strategies const& strategies)
{
using result_t = typename geometry::distance_result<GeometryCollection1, GeometryCollection2, Strategies>::type;
using point1_t = typename geometry::point_type<GeometryCollection1>::type;
using box1_t = model::box<point1_t>;
using point2_t = typename geometry::point_type<GeometryCollection2>::type;
using box2_t = model::box<point2_t>;
using rtree_value_t = std::pair<box1_t, typename boost::range_iterator<GeometryCollection1 const>::type>;
using rtree_params_t = index::parameters<index::rstar<4>, Strategies>;
using rtree_t = index::rtree<rtree_value_t, rtree_params_t>;
rtree_params_t rtree_params(index::rstar<4>(), strategies);
rtree_t rtree(rtree_params);
// Build rtree of boxes and iterators of elements of GC1
// TODO: replace this with visit_breadth_first_iterator to avoid creating an unnecessary container?
{
std::vector<rtree_value_t> values;
visit_breadth_first_impl<true>::apply([&](auto & g1, auto it)
{
box1_t b1 = geometry::return_envelope<box1_t>(g1, strategies);
geometry::detail::expand_by_epsilon(b1);
values.emplace_back(b1, it);
return true;
}, collection1);
rtree_t rt(values.begin(), values.end(), rtree_params);
rtree = std::move(rt);
}
result_t const zero = 0;
auto const rtree_qend = rtree.qend();
result_t result = 0;
bool is_first = true;
visit_breadth_first([&](auto const& g2)
{
box2_t b2 = geometry::return_envelope<box2_t>(g2, strategies);
geometry::detail::expand_by_epsilon(b2);
for (auto it = rtree.qbegin(index::nearest(b2, rtree.size())) ; it != rtree_qend ; ++it)
{
// If the distance between boxes is greater than or equal to previously found
// distance between geometries then stop processing the current b2 because no
// closer b1 will be found
if (! is_first)
{
result_t const bd = dispatch::distance
<
box1_t, box2_t, Strategies
>::apply(it->first, b2, strategies);
if (bd >= result)
{
break;
}
}
// Boxes are closer than the previously found distance (or it's the first time),
// calculate the new distance between geometries and check if it's closer (or assign it).
traits::iter_visit<GeometryCollection1>::apply([&](auto const& g1)
{
result_t const d = dispatch::distance
<
util::remove_cref_t<decltype(g1)>, util::remove_cref_t<decltype(g2)>,
Strategies
>::apply(g1, g2, strategies);
if (is_first)
{
result = d;
is_first = false;
}
else if (d < result)
{
result = d;
}
}, it->second);
// The smallest possible distance found, end searching.
if (! is_first && result <= zero)
{
return false;
}
}
// Just in case
return is_first || result > zero;
}, collection2);
return result;
}
}} // namespace detail::distance
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template
<
typename Geometry, typename GeometryCollection, typename Strategies, typename Tag1
>
struct distance
<
Geometry, GeometryCollection, Strategies,
Tag1, geometry_collection_tag, void, false
>
{
static inline auto apply(Geometry const& geometry,
GeometryCollection const& collection,
Strategies const& strategies)
{
assert_dimension_equal<Geometry, GeometryCollection>();
return detail::distance::geometry_to_collection(geometry, collection, strategies);
}
};
template
<
typename GeometryCollection, typename Geometry, typename Strategies, typename Tag2
>
struct distance
<
GeometryCollection, Geometry, Strategies,
geometry_collection_tag, Tag2, void, false
>
{
static inline auto apply(GeometryCollection const& collection,
Geometry const& geometry,
Strategies const& strategies)
{
assert_dimension_equal<Geometry, GeometryCollection>();
return detail::distance::geometry_to_collection(geometry, collection, strategies);
}
};
template
<
typename GeometryCollection1, typename GeometryCollection2, typename Strategies
>
struct distance
<
GeometryCollection1, GeometryCollection2, Strategies,
geometry_collection_tag, geometry_collection_tag, void, false
>
{
static inline auto apply(GeometryCollection1 const& collection1,
GeometryCollection2 const& collection2,
Strategies const& strategies)
{
assert_dimension_equal<GeometryCollection1, GeometryCollection2>();
// Build the rtree for the smaller GC (ignoring recursive GCs)
return boost::size(collection1) <= boost::size(collection2)
? detail::distance::collection_to_collection(collection1, collection2, strategies)
: detail::distance::collection_to_collection(collection2, collection1, strategies);
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_BOX_HPP

View File

@ -7,9 +7,9 @@
// 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 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.
@ -27,6 +27,7 @@
#include <boost/geometry/algorithms/detail/distance/linear_to_linear.hpp>
#include <boost/geometry/algorithms/detail/distance/linear_or_areal_to_areal.hpp>
#include <boost/geometry/algorithms/detail/distance/linear_to_box.hpp>
#include <boost/geometry/algorithms/detail/distance/geometry_collection.hpp>
#include <boost/geometry/algorithms/detail/distance/geometry_to_segment_or_box.hpp>
#include <boost/geometry/algorithms/detail/distance/segment_to_segment.hpp>
#include <boost/geometry/algorithms/detail/distance/segment_to_box.hpp>

View File

@ -8,7 +8,6 @@
// This file was modified by Oracle on 2014-2021.
// Modifications copyright (c) 2014-2021, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@ -28,6 +27,7 @@
#include <boost/geometry/algorithms/dispatch/distance.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/visit.hpp>
#include <boost/geometry/geometries/adapted/boost_variant.hpp> // For backward compatibility
#include <boost/geometry/geometries/concepts/check.hpp>
@ -92,10 +92,9 @@ template
struct distance
{
template <typename Geometry1, typename Geometry2>
static inline typename distance_result<Geometry1, Geometry2, Strategy>::type
apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
static inline auto apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
return dispatch::distance
<
@ -123,11 +122,9 @@ struct distance<Strategy, false>
typename Geometry1, typename Geometry2, typename S,
std::enable_if_t<is_strategy_converter_specialized<S>::value, int> = 0
>
static inline
typename distance_result<Geometry1, Geometry2, S>::type
apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
S const& strategy)
static inline auto apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
S const& strategy)
{
typedef strategies::distance::services::strategy_converter<Strategy> converter;
typedef decltype(converter::get(strategy)) strategy_type;
@ -143,11 +140,9 @@ struct distance<Strategy, false>
typename Geometry1, typename Geometry2, typename S,
std::enable_if_t<! is_strategy_converter_specialized<S>::value, int> = 0
>
static inline
typename distance_result<Geometry1, Geometry2, S>::type
apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
S const& strategy)
static inline auto apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
S const& strategy)
{
typedef strategies::distance::services::custom_strategy_converter
<
@ -166,11 +161,9 @@ template <>
struct distance<default_strategy, false>
{
template <typename Geometry1, typename Geometry2>
static inline
typename distance_result<Geometry1, Geometry2, default_strategy>::type
apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
default_strategy)
static inline auto apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
default_strategy)
{
typedef typename strategies::distance::services::default_strategy
<
@ -187,18 +180,22 @@ struct distance<default_strategy, false>
} // namespace resolve_strategy
namespace resolve_variant
namespace resolve_dynamic
{
template <typename Geometry1, typename Geometry2>
template
<
typename Geometry1, typename Geometry2,
typename Tag1 = typename geometry::tag<Geometry1>::type,
typename Tag2 = typename geometry::tag<Geometry2>::type
>
struct distance
{
template <typename Strategy>
static inline typename distance_result<Geometry1, Geometry2, Strategy>::type
apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
static inline auto apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
return resolve_strategy::distance
<
@ -208,174 +205,72 @@ struct distance
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
struct distance<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
template <typename DynamicGeometry1, typename Geometry2, typename Tag2>
struct distance<DynamicGeometry1, Geometry2, dynamic_geometry_tag, Tag2>
{
template <typename Strategy>
struct visitor: static_visitor
<
typename distance_result
<
variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
Geometry2,
Strategy
>::type
>
static inline auto apply(DynamicGeometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
Geometry2 const& m_geometry2;
Strategy const& m_strategy;
visitor(Geometry2 const& geometry2,
Strategy const& strategy)
: m_geometry2(geometry2),
m_strategy(strategy)
{}
template <typename Geometry1>
typename distance_result<Geometry1, Geometry2, Strategy>::type
operator()(Geometry1 const& geometry1) const
using result_t = typename geometry::distance_result<DynamicGeometry1, Geometry2, Strategy>::type;
result_t result = 0;
traits::visit<DynamicGeometry1>::apply([&](auto const& g1)
{
return distance
<
Geometry1,
Geometry2
>::template apply
<
Strategy
>(geometry1, m_geometry2, m_strategy);
}
};
template <typename Strategy>
static inline typename distance_result
<
variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
Geometry2,
Strategy
>::type
apply(variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
return boost::apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1);
result = resolve_strategy::distance
<
Strategy
>::apply(g1, geometry2, strategy);
}, geometry1);
return result;
}
};
template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct distance<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
template <typename Geometry1, typename DynamicGeometry2, typename Tag1>
struct distance<Geometry1, DynamicGeometry2, Tag1, dynamic_geometry_tag>
{
template <typename Strategy>
struct visitor: static_visitor
<
typename distance_result
<
Geometry1,
variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
Strategy
>::type
>
static inline auto apply(Geometry1 const& geometry1,
DynamicGeometry2 const& geometry2,
Strategy const& strategy)
{
Geometry1 const& m_geometry1;
Strategy const& m_strategy;
visitor(Geometry1 const& geometry1,
Strategy const& strategy)
: m_geometry1(geometry1),
m_strategy(strategy)
{}
template <typename Geometry2>
typename distance_result<Geometry1, Geometry2, Strategy>::type
operator()(Geometry2 const& geometry2) const
using result_t = typename geometry::distance_result<Geometry1, DynamicGeometry2, Strategy>::type;
result_t result = 0;
traits::visit<DynamicGeometry2>::apply([&](auto const& g2)
{
return distance
<
Geometry1,
Geometry2
>::template apply
<
Strategy
>(m_geometry1, geometry2, m_strategy);
}
};
template <typename Strategy>
static inline typename distance_result
<
Geometry1,
variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
Strategy
>::type
apply(
Geometry1 const& geometry1,
const variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry2,
Strategy const& strategy)
{
return boost::apply_visitor(visitor<Strategy>(geometry1, strategy), geometry2);
result = resolve_strategy::distance
<
Strategy
>::apply(geometry1, g2, strategy);
}, geometry2);
return result;
}
};
template
<
BOOST_VARIANT_ENUM_PARAMS(typename T1),
BOOST_VARIANT_ENUM_PARAMS(typename T2)
>
struct distance
<
boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>,
boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>
>
template <typename DynamicGeometry1, typename DynamicGeometry2>
struct distance<DynamicGeometry1, DynamicGeometry2, dynamic_geometry_tag, dynamic_geometry_tag>
{
template <typename Strategy>
struct visitor: static_visitor
<
typename distance_result
<
boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>,
boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>,
Strategy
>::type
>
static inline auto apply(DynamicGeometry1 const& geometry1,
DynamicGeometry2 const& geometry2,
Strategy const& strategy)
{
Strategy const& m_strategy;
visitor(Strategy const& strategy)
: m_strategy(strategy)
{}
template <typename Geometry1, typename Geometry2>
typename distance_result<Geometry1, Geometry2, Strategy>::type
operator()(Geometry1 const& geometry1, Geometry2 const& geometry2) const
using result_t = typename geometry::distance_result<DynamicGeometry1, DynamicGeometry2, Strategy>::type;
result_t result = 0;
traits::visit<DynamicGeometry1, DynamicGeometry2>::apply([&](auto const& g1, auto const& g2)
{
return distance
<
Geometry1,
Geometry2
>::template apply
<
Strategy
>(geometry1, geometry2, m_strategy);
}
};
template <typename Strategy>
static inline typename distance_result
<
boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>,
boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>,
Strategy
>::type
apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1,
boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2,
Strategy const& strategy)
{
return boost::apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2);
result = resolve_strategy::distance
<
Strategy
>::apply(g1, g2, strategy);
}, geometry1, geometry2);
return result;
}
};
} // namespace resolve_variant
} // namespace resolve_dynamic
/*!
@ -415,10 +310,9 @@ for distance, it is probably so that there is no specialization
for return_type<...> for your strategy.
*/
template <typename Geometry1, typename Geometry2, typename Strategy>
inline typename distance_result<Geometry1, Geometry2, Strategy>::type
distance(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
inline auto distance(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
concepts::check<Geometry1 const>();
concepts::check<Geometry2 const>();
@ -426,7 +320,7 @@ distance(Geometry1 const& geometry1,
detail::throw_on_empty_input(geometry1);
detail::throw_on_empty_input(geometry2);
return resolve_variant::distance
return resolve_dynamic::distance
<
Geometry1,
Geometry2
@ -448,13 +342,9 @@ distance(Geometry1 const& geometry1,
\qbk{[include reference/algorithms/distance.qbk]}
*/
template <typename Geometry1, typename Geometry2>
inline typename default_distance_result<Geometry1, Geometry2>::type
distance(Geometry1 const& geometry1,
Geometry2 const& geometry2)
inline auto distance(Geometry1 const& geometry1,
Geometry2 const& geometry2)
{
concepts::check<Geometry1 const>();
concepts::check<Geometry2 const>();
return geometry::distance(geometry1, geometry2, default_strategy());
}

View File

@ -0,0 +1,63 @@
// Boost.Geometry
// Copyright (c) 2021, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_GEOMETRY_COLLECTION_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_GEOMETRY_COLLECTION_HPP
#include <boost/geometry/algorithms/detail/visit.hpp>
#include <boost/geometry/algorithms/dispatch/envelope.hpp>
#include <boost/geometry/algorithms/is_empty.hpp>
#include <boost/geometry/core/tags.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Collection>
struct envelope<Collection, geometry_collection_tag>
{
template <typename Geometry, typename Box, typename Strategy>
static inline void apply(Geometry const& geometry,
Box& mbr,
Strategy const& strategy)
{
using strategy_t = decltype(strategy.envelope(geometry, mbr));
using state_t = typename strategy_t::template multi_state<Box>;
state_t state;
detail::visit_breadth_first([&](auto const& g)
{
if (! geometry::is_empty(g))
{
Box b;
envelope<util::remove_cref_t<decltype(g)>>::apply(g, b, strategy);
state.apply(b);
}
return true;
}, geometry);
state.result(mbr);
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_GEOMETRY_COLLECTION_HPP

View File

@ -6,9 +6,9 @@
// 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.
@ -28,6 +28,7 @@
#include <boost/geometry/algorithms/detail/envelope/areal.hpp>
#include <boost/geometry/algorithms/detail/envelope/box.hpp>
#include <boost/geometry/algorithms/detail/envelope/geometry_collection.hpp>
#include <boost/geometry/algorithms/detail/envelope/linear.hpp>
#include <boost/geometry/algorithms/detail/envelope/multipoint.hpp>
#include <boost/geometry/algorithms/detail/envelope/point.hpp>

View File

@ -22,16 +22,14 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_INTERFACE_HPP
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/algorithms/dispatch/envelope.hpp>
#include <boost/geometry/core/coordinate_system.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/visit.hpp>
#include <boost/geometry/geometries/adapted/boost_variant.hpp> // For backward compatibility
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/strategies/default_strategy.hpp>
@ -39,6 +37,7 @@
#include <boost/geometry/strategies/envelope/services.hpp>
#include <boost/geometry/util/select_most_precise.hpp>
#include <boost/geometry/util/type_traits_std.hpp>
namespace boost { namespace geometry
@ -98,10 +97,10 @@ struct envelope<default_strategy, false>
} // namespace resolve_strategy
namespace resolve_variant
namespace resolve_dynamic
{
template <typename Geometry>
template <typename Geometry, typename Tag = typename tag<Geometry>::type>
struct envelope
{
template <typename Box, typename Strategy>
@ -117,38 +116,22 @@ struct envelope
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct envelope<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
template <typename Geometry>
struct envelope<Geometry, dynamic_geometry_tag>
{
template <typename Box, typename Strategy>
struct visitor: boost::static_visitor<void>
static inline void apply(Geometry const& geometry,
Box& box,
Strategy const& strategy)
{
Box& m_box;
Strategy const& m_strategy;
visitor(Box& box, Strategy const& strategy)
: m_box(box)
, m_strategy(strategy)
{}
template <typename Geometry>
void operator()(Geometry const& geometry) const
traits::visit<Geometry>::apply([&](auto const& g)
{
envelope<Geometry>::apply(geometry, m_box, m_strategy);
}
};
template <typename Box, typename Strategy>
static inline void
apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
Box& box,
Strategy const& strategy)
{
boost::apply_visitor(visitor<Box, Strategy>(box, strategy), geometry);
envelope<util::remove_cref_t<decltype(g)>>::apply(g, box, strategy);
}, geometry);
}
};
} // namespace resolve_variant
} // namespace resolve_dynamic
/*!
@ -172,7 +155,7 @@ struct envelope<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
template<typename Geometry, typename Box, typename Strategy>
inline void envelope(Geometry const& geometry, Box& mbr, Strategy const& strategy)
{
resolve_variant::envelope<Geometry>::apply(geometry, mbr, strategy);
resolve_dynamic::envelope<Geometry>::apply(geometry, mbr, strategy);
}
/*!
@ -193,7 +176,7 @@ inline void envelope(Geometry const& geometry, Box& mbr, Strategy const& strateg
template<typename Geometry, typename Box>
inline void envelope(Geometry const& geometry, Box& mbr)
{
resolve_variant::envelope<Geometry>::apply(geometry, mbr, default_strategy());
resolve_dynamic::envelope<Geometry>::apply(geometry, mbr, default_strategy());
}
@ -219,7 +202,7 @@ template<typename Box, typename Geometry, typename Strategy>
inline Box return_envelope(Geometry const& geometry, Strategy const& strategy)
{
Box mbr;
resolve_variant::envelope<Geometry>::apply(geometry, mbr, strategy);
resolve_dynamic::envelope<Geometry>::apply(geometry, mbr, strategy);
return mbr;
}
@ -242,7 +225,7 @@ template<typename Box, typename Geometry>
inline Box return_envelope(Geometry const& geometry)
{
Box mbr;
resolve_variant::envelope<Geometry>::apply(geometry, mbr, default_strategy());
resolve_dynamic::envelope<Geometry>::apply(geometry, mbr, default_strategy());
return mbr;
}

View File

@ -39,8 +39,6 @@
#include <boost/geometry/views/detail/closed_clockwise_view.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>
@ -48,34 +46,17 @@
namespace boost { namespace geometry
{
// Since these vectors (though ray would be a better name) are used in the
// implementation of equals() for Areal geometries the internal representation
// should be consistent with the side strategy.
template
<
typename T,
typename Geometry,
typename SideStrategy,
typename CSTag = typename cs_tag<Geometry>::type
>
struct collected_vector
: nyi::not_implemented_tag
{};
// compatible with side_robust cartesian strategy
template <typename T, typename Geometry, typename CT, typename CSTag>
struct collected_vector
<
T, Geometry, strategy::side::side_robust<CT>, CSTag
>
template <typename T>
struct collected_vector_cartesian
{
typedef T type;
inline collected_vector()
inline collected_vector_cartesian()
{}
inline collected_vector(T const& px, T const& py,
T const& pdx, T const& pdy)
inline collected_vector_cartesian(T const& px, T const& py,
T const& pdx, T const& pdy)
: x(px)
, y(py)
, dx(pdx)
@ -85,7 +66,7 @@ struct collected_vector
{}
template <typename Point>
inline collected_vector(Point const& p1, Point const& p2)
inline collected_vector_cartesian(Point const& p1, Point const& p2)
: x(get<0>(p1))
, y(get<1>(p1))
, dx(get<0>(p2) - x)
@ -96,8 +77,7 @@ struct collected_vector
bool normalize()
{
T magnitude = math::sqrt(
boost::numeric_cast<T>(dx * dx + dy * dy));
T magnitude = math::sqrt(boost::numeric_cast<T>(dx * dx + dy * dy));
// NOTE: shouldn't here math::equals() be called?
if (magnitude > 0)
@ -111,7 +91,7 @@ struct collected_vector
}
// For sorting
inline bool operator<(collected_vector const& other) const
inline bool operator<(collected_vector_cartesian const& other) const
{
if (math::equals(x, other.x))
{
@ -128,13 +108,13 @@ struct collected_vector
return x < other.x;
}
inline bool next_is_collinear(collected_vector const& other) const
inline bool next_is_collinear(collected_vector_cartesian const& other) const
{
return same_direction(other);
}
// For std::equals
inline bool operator==(collected_vector const& other) const
inline bool operator==(collected_vector_cartesian const& other) const
{
return math::equals(x, other.x)
&& math::equals(y, other.y)
@ -142,7 +122,7 @@ struct collected_vector
}
private:
inline bool same_direction(collected_vector const& other) const
inline bool same_direction(collected_vector_cartesian const& other) const
{
// For high precision arithmetic, we have to be
// more relaxed then using ==
@ -157,49 +137,35 @@ 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
template <typename T, typename Geometry, typename CT, typename CSTag>
struct collected_vector
<
T, Geometry, strategy::side::spherical_side_formula<CT>, CSTag
>
template <typename T, typename Point>
struct collected_vector_spherical
{
typedef T type;
typedef typename geometry::detail::cs_angular_units<Geometry>::type units_type;
typedef model::point<T, 2, cs::spherical_equatorial<units_type> > point_type;
typedef model::point<T, 3, cs::cartesian> vector_type;
collected_vector()
collected_vector_spherical()
{}
template <typename Point>
collected_vector(Point const& p1, Point const& p2)
collected_vector_spherical(Point const& p1, Point const& p2)
: origin(get<0>(p1), get<1>(p1))
{
origin = detail::return_normalized<point_type>(
origin = detail::return_normalized<Point>(
origin,
strategy::normalize::spherical_point());
using namespace geometry::formula;
prev = sph_to_cart3d<vector_type>(p1);
next = sph_to_cart3d<vector_type>(p2);
direction = cross_product(prev, next);
cross = direction = cross_product(prev, next);
}
bool normalize()
{
T magnitude_sqr = dot_product(direction, direction);
T const magnitude_sqr = dot_product(direction, direction);
// NOTE: shouldn't here math::equals() be called?
if (magnitude_sqr > 0)
@ -211,7 +177,7 @@ struct collected_vector
return false;
}
bool operator<(collected_vector const& other) const
bool operator<(collected_vector_spherical const& other) const
{
if (math::equals(get<0>(origin), get<0>(other.origin)))
{
@ -235,13 +201,13 @@ struct collected_vector
// For consistency with side and intersection strategies used by relops
// IMPORTANT: this method should be called for previous vector
// and next vector should be passed as parameter
bool next_is_collinear(collected_vector const& other) const
bool next_is_collinear(collected_vector_spherical const& other) const
{
return formula::sph_side_value(direction, other.next) == 0;
return formula::sph_side_value(cross, other.next) == 0;
}
// For std::equals
bool operator==(collected_vector const& other) const
bool operator==(collected_vector_spherical const& other) const
{
return math::equals(get<0>(origin), get<0>(other.origin))
&& math::equals(get<1>(origin), get<1>(other.origin))
@ -250,76 +216,57 @@ struct collected_vector
private:
// For consistency with side and intersection strategies used by relops
bool is_collinear(collected_vector const& other) const
// NOTE: alternative would be to equal-compare direction's coordinates
// or to check if dot product of directions is equal to 1.
bool is_collinear(collected_vector_spherical const& other) const
{
return formula::sph_side_value(direction, other.prev) == 0
&& formula::sph_side_value(direction, other.next) == 0;
return formula::sph_side_value(cross, other.prev) == 0
&& formula::sph_side_value(cross, other.next) == 0;
}
/*bool same_direction(collected_vector const& other) const
{
return math::equals_with_epsilon(get<0>(direction), get<0>(other.direction))
&& math::equals_with_epsilon(get<1>(direction), get<1>(other.direction))
&& math::equals_with_epsilon(get<2>(direction), get<2>(other.direction));
}*/
point_type origin; // used for sorting and equality check
Point origin; // used for sorting and equality check
vector_type direction; // used for sorting, only in operator<
vector_type cross; // used for sorting, used for collinearity check
vector_type prev; // used for collinearity check, only in operator==
vector_type next; // used for collinearity check
};
// Specialization for spherical polar
template <typename T, typename Geometry, typename CT>
struct collected_vector
<
T, Geometry,
strategy::side::spherical_side_formula<CT>,
spherical_polar_tag
>
: public collected_vector
<
T, Geometry,
strategy::side::spherical_side_formula<CT>,
spherical_equatorial_tag
>
// Version for spherical polar
template <typename T, typename Point>
struct collected_vector_polar
: public collected_vector_spherical<T, Point>
{
typedef collected_vector
<
T, Geometry,
strategy::side::spherical_side_formula<CT>,
spherical_equatorial_tag
> base_type;
using type = T;
using base_point_type
= model::point<T, 2, cs::spherical_equatorial<geometry::degree>>;
using base_type = collected_vector_spherical<T, base_point_type>;
collected_vector() {}
collected_vector_polar() {}
template <typename Point>
collected_vector(Point const& p1, Point const& p2)
collected_vector_polar(Point const& p1, Point const& p2)
: base_type(to_equatorial(p1), to_equatorial(p2))
{}
private:
template <typename Point>
Point to_equatorial(Point const& p)
static base_point_type to_equatorial(Point const& p)
{
typedef typename coordinate_type<Point>::type coord_type;
typedef math::detail::constants_on_spheroid
using coord_type = typename coordinate_type<Point>::type;
using constants = math::detail::constants_on_spheroid
<
coord_type,
typename coordinate_system<Point>::type::units
> constants;
> ;
coord_type const pi_2 = constants::half_period() / 2;
constexpr coord_type pi_2 = constants::half_period() / 2;
Point res = p;
base_point_type res;
set<0>(res, get<0>(p));
set<1>(res, pi_2 - get<1>(p));
return res;
}
};
// TODO: specialize collected_vector for geographic_tag
// TODO: implement collected_vector type for geographic
#ifndef DOXYGEN_NO_DETAIL
@ -348,15 +295,11 @@ private:
return;
}
typedef typename boost::range_size<Collection>::type collection_size_t;
collection_size_t c_old_size = boost::size(collection);
typedef typename boost::range_iterator<ClosedClockwiseRange const>::type iterator;
auto c_old_size = boost::size(collection);
bool is_first = true;
iterator it = boost::begin(range);
auto it = boost::begin(range);
for (iterator prev = it++; it != boost::end(range); prev = it++)
for (auto prev = it++; it != boost::end(range); prev = it++)
{
typename boost::range_value<Collection>::type v(*prev, *it);
@ -375,13 +318,10 @@ private:
}
// If first one has same direction as last one, remove first one
collection_size_t collected_count = boost::size(collection) - c_old_size;
if ( collected_count > 1 )
if (boost::size(collection) > c_old_size + 1)
{
typedef typename boost::range_iterator<Collection>::type c_iterator;
c_iterator first = range::pos(collection, c_old_size);
if (collection.back().next_is_collinear(*first) )
auto first = range::pos(collection, c_old_size);
if (collection.back().next_is_collinear(*first))
{
//collection.erase(first);
// O(1) instead of O(N)

View File

@ -160,26 +160,32 @@ struct length_check
*/
template <typename Geometry1, typename Geometry2, typename Strategy>
struct collected_vector
// Small helper structure do decide to use collect_vectors, or not
template <typename Strategy, typename CsTag>
struct use_collect_vectors
{
typedef typename geometry::select_most_precise
<
typename select_coordinate_type
<
Geometry1, Geometry2
>::type,
double
>::type calculation_type;
typedef geometry::collected_vector
<
calculation_type,
Geometry1,
decltype(std::declval<Strategy>().side())
> type;
static constexpr bool value = false;
};
template <typename Strategy>
struct use_collect_vectors<Strategy, cartesian_tag>
{
static constexpr bool value = true;
template <typename T, typename Point>
using type = collected_vector_cartesian<T>;
};
template <typename CV>
struct use_collect_vectors<strategy::side::spherical_side_formula<CV>, spherical_tag>
{
static constexpr bool value = true;
template <typename T, typename Point>
using type = collected_vector_spherical<T, Point>;
};
template <typename TrivialCheck>
struct equals_by_collection
{
@ -193,10 +199,24 @@ struct equals_by_collection
return false;
}
typedef typename collected_vector
using calculation_type = typename geometry::select_most_precise
<
Geometry1, Geometry2, Strategy
>::type collected_vector_type;
typename select_coordinate_type
<
Geometry1, Geometry2
>::type,
double
>::type;
using collected_vector_type = typename use_collect_vectors
<
decltype(std::declval<Strategy>().side()),
typename Strategy::cs_tag
>::template type
<
calculation_type,
typename geometry::point_type<Geometry1>::type
>;
std::vector<collected_vector_type> c1, c2;
@ -211,7 +231,7 @@ struct equals_by_collection
std::sort(c1.begin(), c1.end());
std::sort(c2.begin(), c2.end());
// Just check if these vectors are equal.
// Check if these vectors are equal.
return std::equal(c1.begin(), c1.end(), c2.begin());
}
};
@ -226,47 +246,40 @@ struct equals_by_relate
>
{};
// If collect_vectors which is a SideStrategy-dispatched optimization
// is implemented in a way consistent with the Intersection/Side Strategy
// then collect_vectors is used, otherwise relate is used.
// Use either collect_vectors or relate
// NOTE: the result could be conceptually different for invalid
// geometries in different coordinate systems because collect_vectors
// and relate treat invalid geometries differently.
template<typename TrivialCheck>
struct equals_by_collection_or_relate
{
template <typename Geometry1, typename Geometry2, typename Strategy>
template <typename Strategy>
using use_vectors = use_collect_vectors
<
decltype(std::declval<Strategy>().side()),
typename Strategy::cs_tag
>;
template
<
typename Geometry1, typename Geometry2, typename Strategy,
std::enable_if_t<use_vectors<Strategy>::value, int> = 0
>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
typedef std::is_base_of
<
nyi::not_implemented_tag,
typename collected_vector
<
Geometry1, Geometry2, Strategy
>::type
> enable_relate_type;
return apply(geometry1, geometry2, strategy, enable_relate_type());
}
private:
template <typename Geometry1, typename Geometry2, typename Strategy>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy,
std::false_type /*enable_relate*/)
{
return equals_by_collection<TrivialCheck>::apply(geometry1, geometry2, strategy);
}
template <typename Geometry1, typename Geometry2, typename Strategy>
template
<
typename Geometry1, typename Geometry2, typename Strategy,
std::enable_if_t<! use_vectors<Strategy>::value, int> = 0
>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy,
std::true_type /*enable_relate*/)
Strategy const& strategy)
{
return equals_by_relate<Geometry1, Geometry2>::apply(geometry1, geometry2, strategy);
}

View File

@ -22,22 +22,23 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_INTERFACE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_INTERFACE_HPP
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/algorithms/dispatch/expand.hpp>
#include <boost/geometry/core/coordinate_system.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/visit.hpp>
#include <boost/geometry/geometries/adapted/boost_variant.hpp> // For backward compatibility
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/strategies/default_strategy.hpp>
#include <boost/geometry/strategies/detail.hpp>
#include <boost/geometry/strategies/expand/services.hpp>
#include <boost/geometry/util/type_traits_std.hpp>
namespace boost { namespace geometry
{
@ -97,10 +98,10 @@ struct expand<default_strategy, false>
} //namespace resolve_strategy
namespace resolve_variant
namespace resolve_dynamic
{
template <typename Geometry>
template <typename Geometry, typename Tag = typename tag<Geometry>::type>
struct expand
{
template <typename Box, typename Strategy>
@ -116,68 +117,24 @@ struct expand
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct expand<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
template <typename Geometry>
struct expand<Geometry, dynamic_geometry_tag>
{
template <typename Box, typename Strategy>
struct visitor: boost::static_visitor<void>
{
Box& m_box;
Strategy const& m_strategy;
visitor(Box& box, Strategy const& strategy)
: m_box(box)
, m_strategy(strategy)
{}
template <typename Geometry>
void operator()(Geometry const& geometry) const
{
return expand<Geometry>::apply(m_box, geometry, m_strategy);
}
};
template <class Box, typename Strategy>
static inline void
apply(Box& box,
boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
Strategy const& strategy)
static inline void apply(Box& box,
Geometry const& geometry,
Strategy const& strategy)
{
return boost::apply_visitor(visitor<Box, Strategy>(box, strategy),
geometry);
traits::visit<Geometry>::apply([&](auto const& g)
{
expand<util::remove_cref_t<decltype(g)>>::apply(box, g, strategy);
}, geometry);
}
};
} // namespace resolve_variant
} // namespace resolve_dynamic
/***
*!
\brief Expands a box using the extend (envelope) of another geometry (box, point)
\ingroup expand
\tparam Box type of the box
\tparam Geometry of second geometry, to be expanded with the box
\param box box to expand another geometry with, might be changed
\param geometry other geometry
\param strategy_less
\param strategy_greater
\note Strategy is currently ignored
*
template
<
typename Box, typename Geometry,
typename StrategyLess, typename StrategyGreater
>
inline void expand(Box& box, Geometry const& geometry,
StrategyLess const& strategy_less,
StrategyGreater const& strategy_greater)
{
concepts::check_concepts_and_equal_dimensions<Box, Geometry const>();
dispatch::expand<Box, Geometry>::apply(box, geometry);
}
***/
/*!
\brief Expands (with strategy)
\ingroup expand
@ -195,7 +152,7 @@ will be added to the box
template <typename Box, typename Geometry, typename Strategy>
inline void expand(Box& box, Geometry const& geometry, Strategy const& strategy)
{
resolve_variant::expand<Geometry>::apply(box, geometry, strategy);
resolve_dynamic::expand<Geometry>::apply(box, geometry, strategy);
}
/*!
@ -213,7 +170,7 @@ added to the box
template <typename Box, typename Geometry>
inline void expand(Box& box, Geometry const& geometry)
{
resolve_variant::expand<Geometry>::apply(box, geometry, default_strategy());
resolve_dynamic::expand<Geometry>::apply(box, geometry, default_strategy());
}
}} // namespace boost::geometry

View File

@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014-2020, Oracle and/or its affiliates.
// Copyright (c) 2014-2021, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@ -54,11 +54,6 @@ private:
CSTag
>::type rescale_policy_type;
typedef detail::overlay::get_turn_info
<
detail::overlay::assign_null_policy
> turn_policy;
public:
typedef detail::overlay::turn_info
<
@ -88,12 +83,11 @@ public:
> interrupt_policy;
// Calculate self-turns, skipping adjacent segments
detail::self_get_turn_points::self_turns<false, turn_policy>(geometry,
strategy,
robust_policy,
turns,
interrupt_policy,
0, true);
detail::self_get_turn_points::self_turns
<
false, detail::overlay::assign_null_policy
>(geometry, strategy, robust_policy, turns, interrupt_policy,
0, true);
if (interrupt_policy.has_intersections)
{

View File

@ -1,6 +1,6 @@
// Boost.Geometry
// Copyright (c) 2014-2020, Oracle and/or its affiliates.
// Copyright (c) 2014-2021, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@ -14,12 +14,11 @@
#include <sstream>
#include <string>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/algorithms/detail/visit.hpp>
#include <boost/geometry/algorithms/dispatch/is_valid.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/visit.hpp>
#include <boost/geometry/geometries/adapted/boost_variant.hpp> // For backward compatibility
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/policies/is_valid/default_policy.hpp>
#include <boost/geometry/policies/is_valid/failing_reason_policy.hpp>
@ -90,10 +89,10 @@ struct is_valid<default_strategy, false>
} // namespace resolve_strategy
namespace resolve_variant
namespace resolve_dynamic
{
template <typename Geometry>
template <typename Geometry, typename Tag = typename tag<Geometry>::type>
struct is_valid
{
template <typename VisitPolicy, typename Strategy>
@ -110,39 +109,42 @@ struct is_valid
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct is_valid<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
template <typename Geometry>
struct is_valid<Geometry, dynamic_geometry_tag>
{
template <typename VisitPolicy, typename Strategy>
struct visitor : boost::static_visitor<bool>
static inline bool apply(Geometry const& geometry,
VisitPolicy& policy_visitor,
Strategy const& strategy)
{
visitor(VisitPolicy& policy, Strategy const& strategy)
: m_policy(policy)
, m_strategy(strategy)
{}
template <typename Geometry>
bool operator()(Geometry const& geometry) const
bool result = true;
traits::visit<Geometry>::apply([&](auto const& g)
{
return is_valid<Geometry>::apply(geometry, m_policy, m_strategy);
}
VisitPolicy& m_policy;
Strategy const& m_strategy;
};
template <typename VisitPolicy, typename Strategy>
static inline bool
apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
VisitPolicy& policy_visitor,
Strategy const& strategy)
{
return boost::apply_visitor(visitor<VisitPolicy, Strategy>(policy_visitor, strategy),
geometry);
result = is_valid<util::remove_cref_t<decltype(g)>>::apply(g, policy_visitor, strategy);
}, geometry);
return result;
}
};
} // namespace resolve_variant
template <typename Geometry>
struct is_valid<Geometry, geometry_collection_tag>
{
template <typename VisitPolicy, typename Strategy>
static inline bool apply(Geometry const& geometry,
VisitPolicy& policy_visitor,
Strategy const& strategy)
{
bool result = true;
detail::visit_breadth_first([&](auto const& g)
{
result = is_valid<util::remove_cref_t<decltype(g)>>::apply(g, policy_visitor, strategy);
return result;
}, geometry);
return result;
}
};
} // namespace resolve_dynamic
// Undocumented for now
@ -151,7 +153,7 @@ inline bool is_valid(Geometry const& geometry,
VisitPolicy& visitor,
Strategy const& strategy)
{
return resolve_variant::is_valid<Geometry>::apply(geometry, visitor, strategy);
return resolve_dynamic::is_valid<Geometry>::apply(geometry, visitor, strategy);
}
@ -175,7 +177,7 @@ template <typename Geometry, typename Strategy>
inline bool is_valid(Geometry const& geometry, Strategy const& strategy)
{
is_valid_default_policy<> visitor;
return resolve_variant::is_valid<Geometry>::apply(geometry, visitor, strategy);
return resolve_dynamic::is_valid<Geometry>::apply(geometry, visitor, strategy);
}
/*!
@ -220,7 +222,7 @@ template <typename Geometry, typename Strategy>
inline bool is_valid(Geometry const& geometry, validity_failure_type& failure, Strategy const& strategy)
{
failure_type_policy<> visitor;
bool result = resolve_variant::is_valid<Geometry>::apply(geometry, visitor, strategy);
bool result = resolve_dynamic::is_valid<Geometry>::apply(geometry, visitor, strategy);
failure = visitor.failure();
return result;
}
@ -271,7 +273,7 @@ inline bool is_valid(Geometry const& geometry, std::string& message, Strategy co
{
std::ostringstream stream;
failing_reason_policy<> visitor(stream);
bool result = resolve_variant::is_valid<Geometry>::apply(geometry, visitor, strategy);
bool result = resolve_dynamic::is_valid<Geometry>::apply(geometry, visitor, strategy);
message = stream.str();
return result;
}

View File

@ -3,9 +3,8 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2017-2020.
// This file was modified by Oracle on 2017-2021.
// Modifications copyright (c) 2017-2020 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,
@ -353,21 +352,20 @@ inline typename geometry::coordinate_type<Point1>::type
template <typename Turns>
inline void calculate_remaining_distance(Turns& turns)
{
typedef typename boost::range_value<Turns>::type turn_type;
typedef typename turn_type::turn_operation_type op_type;
using turn_type = typename boost::range_value<Turns>::type;
using op_type = typename turn_type::turn_operation_type;
for (typename boost::range_iterator<Turns>::type
it = boost::begin(turns);
it != boost::end(turns);
++it)
typename op_type::comparable_distance_type const zero_distance = 0;
for (auto it = boost::begin(turns); it != boost::end(turns); ++it)
{
turn_type& turn = *it;
op_type& op0 = turn.operations[0];
op_type& op1 = turn.operations[1];
if (op0.remaining_distance != 0
|| op1.remaining_distance != 0)
if (op0.remaining_distance != zero_distance
|| op1.remaining_distance != zero_distance)
{
continue;
}

View File

@ -242,33 +242,45 @@ struct base_turn_handler
BOOST_GEOMETRY_ASSERT(index_q > 0 && index_q <= 2);
#if ! defined(BOOST_GEOMETRY_USE_RESCALING)
ti.operations[IndexP].remaining_distance = distance_measure(ti.point, range_p.at(index_p));
ti.operations[IndexQ].remaining_distance = distance_measure(ti.point, range_q.at(index_q));
bool const p_in_range = index_p < range_p.size();
bool const q_in_range = index_q < range_q.size();
ti.operations[IndexP].remaining_distance
= p_in_range
? distance_measure(ti.point, range_p.at(index_p))
: 0;
ti.operations[IndexQ].remaining_distance
= q_in_range
? distance_measure(ti.point, range_q.at(index_q))
: 0;
// pk/q2 is considered as collinear, but there might be
// a tiny measurable difference. If so, use that.
// Calculate pk // qj-qk
bool const p_closer =
ti.operations[IndexP].remaining_distance
< ti.operations[IndexQ].remaining_distance;
auto const dm
if (p_in_range && q_in_range)
{
// pk/q2 is considered as collinear, but there might be
// a tiny measurable difference. If so, use that.
// Calculate pk // qj-qk
bool const p_closer
= ti.operations[IndexP].remaining_distance
< ti.operations[IndexQ].remaining_distance;
auto const dm
= p_closer
? get_distance_measure(range_q.at(index_q - 1),
range_q.at(index_q), range_p.at(index_p))
: get_distance_measure(range_p.at(index_p - 1),
range_p.at(index_p), range_q.at(index_q));
if (! dm.is_zero())
{
// Not truely collinear, distinguish for union/intersection
// If p goes left (positive), take that for a union
bool const p_left = p_closer ? dm.is_positive() : dm.is_negative();
if (! dm.is_zero())
{
// Not truely collinear, distinguish for union/intersection
// If p goes left (positive), take that for a union
bool const p_left
= p_closer ? dm.is_positive() : dm.is_negative();
ti.operations[IndexP].operation = p_left
? operation_union : operation_intersection;
ti.operations[IndexQ].operation = p_left
? operation_intersection : operation_union;
return;
ti.operations[IndexP].operation = p_left
? operation_union : operation_intersection;
ti.operations[IndexQ].operation = p_left
? operation_intersection : operation_union;
return;
}
}
#endif

View File

@ -3,9 +3,8 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2017-2020.
// Modifications copyright (c) 2017-2020 Oracle and/or its affiliates.
// This file was modified by Oracle on 2017-2021.
// Modifications copyright (c) 2017-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,
@ -33,6 +32,9 @@
#include <boost/geometry/geometries/box.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/strategies/detail.hpp>
#include <boost/geometry/strategies/relate/services.hpp>
#include <boost/geometry/util/condition.hpp>
@ -271,6 +273,85 @@ struct self_get_turn_points
#endif // DOXYGEN_NO_DISPATCH
namespace resolve_strategy
{
template
<
bool Reverse,
typename AssignPolicy,
typename Strategies,
bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategies>::value
>
struct self_get_turn_points
{
template
<
typename Geometry,
typename RobustPolicy,
typename Turns,
typename InterruptPolicy
>
static inline void apply(Geometry const& geometry,
Strategies const& strategies,
RobustPolicy const& robust_policy,
Turns& turns,
InterruptPolicy& interrupt_policy,
int source_index,
bool skip_adjacent)
{
using turn_policy = detail::overlay::get_turn_info<AssignPolicy>;
dispatch::self_get_turn_points
<
Reverse,
typename tag<Geometry>::type,
Geometry,
turn_policy
>::apply(geometry, strategies, robust_policy, turns, interrupt_policy,
source_index, skip_adjacent);
}
};
template <bool Reverse, typename AssignPolicy, typename Strategy>
struct self_get_turn_points<Reverse, AssignPolicy, Strategy, false>
{
template
<
typename Geometry,
typename RobustPolicy,
typename Turns,
typename InterruptPolicy
>
static inline void apply(Geometry const& geometry,
Strategy const& strategy,
RobustPolicy const& robust_policy,
Turns& turns,
InterruptPolicy& interrupt_policy,
int source_index,
bool skip_adjacent)
{
using strategies::relate::services::strategy_converter;
self_get_turn_points
<
Reverse,
AssignPolicy,
decltype(strategy_converter<Strategy>::get(strategy))
>::apply(geometry,
strategy_converter<Strategy>::get(strategy),
robust_policy,
turns,
interrupt_policy,
source_index,
skip_adjacent);
}
};
} // namespace resolve_strategy
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace self_get_turn_points
{
@ -282,13 +363,13 @@ template
bool Reverse,
typename AssignPolicy,
typename Geometry,
typename IntersectionStrategy,
typename Strategy,
typename RobustPolicy,
typename Turns,
typename InterruptPolicy
>
inline void self_turns(Geometry const& geometry,
IntersectionStrategy const& strategy,
Strategy const& strategy,
RobustPolicy const& robust_policy,
Turns& turns,
InterruptPolicy& interrupt_policy,
@ -297,14 +378,9 @@ inline void self_turns(Geometry const& geometry,
{
concepts::check<Geometry const>();
typedef detail::overlay::get_turn_info<detail::overlay::assign_null_policy> turn_policy;
dispatch::self_get_turn_points
resolve_strategy::self_get_turn_points
<
Reverse,
typename tag<Geometry>::type,
Geometry,
turn_policy
Reverse, AssignPolicy, Strategy
>::apply(geometry, strategy, robust_policy, turns, interrupt_policy,
source_index, skip_adjacent);
}
@ -351,12 +427,11 @@ inline void self_turns(Geometry const& geometry,
geometry::point_order<Geometry>::value
>::value;
detail::self_get_turn_points::self_turns
resolve_strategy::self_get_turn_points
<
reverse,
AssignPolicy
>(geometry, strategy, robust_policy, turns, interrupt_policy,
source_index, skip_adjacent);
reverse, AssignPolicy, Strategy
>::apply(geometry, strategy, robust_policy, turns, interrupt_policy,
source_index, skip_adjacent);
}

View File

@ -181,20 +181,16 @@ struct visit_breadth_first<Geometry, dynamic_geometry_tag>
}
};
// NOTE: This specialization works partially like std::visit and partially like
// std::ranges::for_each. If the argument is rvalue reference then the elements
// are passed into the function as rvalue references as well. This is consistent
// with std::visit but different than std::ranges::for_each. It's done this way
// because visit_breadth_first is also specialized for static and dynamic geometries
// which and references for them has to be propagated like that. If this is not
// desireable then the support for other kinds of geometries should be dropped and
// this algorithm should work only for geometry collection.
// This is not a problem right now because only non-rvalue references are passed
// but in the future there might be some issues. Consider e.g. passing a temporary
// mutable proxy range as geometry collection. In such case the elements would be
// passed as rvalue references which would be incorrect.
template <typename Geometry>
struct visit_breadth_first<Geometry, geometry_collection_tag>
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
template <bool PassIterator = false>
struct visit_breadth_first_impl
{
template <typename F, typename Geom>
static bool apply(F function, Geom && geom)
@ -217,7 +213,7 @@ struct visit_breadth_first<Geometry, geometry_collection_tag>
bool result = true;
traits::iter_visit<util::remove_cref_t<Geom>>::apply([&](auto && g)
{
result = visit_breadth_first::visit_or_enqueue(
result = visit_breadth_first_impl::visit_or_enqueue<PassIterator>(
function, std::forward<decltype(g)>(g), queue, it);
}, it);
@ -236,7 +232,7 @@ struct visit_breadth_first<Geometry, geometry_collection_tag>
// so this call can be avoided.
traits::iter_visit<util::remove_cref_t<Geom>>::apply([&](auto && g)
{
visit_breadth_first::set_iterators(std::forward<decltype(g)>(g), it, end);
visit_breadth_first_impl::set_iterators(std::forward<decltype(g)>(g), it, end);
}, queue.front());
queue.pop_front();
}
@ -247,7 +243,7 @@ struct visit_breadth_first<Geometry, geometry_collection_tag>
private:
template
<
typename F, typename Geom, typename Iterator,
bool PassIter, typename F, typename Geom, typename Iterator,
std::enable_if_t<util::is_geometry_collection<Geom>::value, int> = 0
>
static bool visit_or_enqueue(F &, Geom &&, std::deque<Iterator> & queue, Iterator iter)
@ -257,13 +253,22 @@ private:
}
template
<
typename F, typename Geom, typename Iterator,
std::enable_if_t<! util::is_geometry_collection<Geom>::value, int> = 0
bool PassIter, typename F, typename Geom, typename Iterator,
std::enable_if_t<! util::is_geometry_collection<Geom>::value && ! PassIter, int> = 0
>
static bool visit_or_enqueue(F & f, Geom && g, std::deque<Iterator> & , Iterator)
{
return f(std::forward<Geom>(g));
}
template
<
bool PassIter, typename F, typename Geom, typename Iterator,
std::enable_if_t<! util::is_geometry_collection<Geom>::value && PassIter, int> = 0
>
static bool visit_or_enqueue(F & f, Geom && g, std::deque<Iterator> & , Iterator iter)
{
return f(std::forward<Geom>(g), iter);
}
template
<
@ -284,6 +289,32 @@ private:
{}
};
} // namespace detail
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
// NOTE: This specialization works partially like std::visit and partially like
// std::ranges::for_each. If the argument is rvalue reference then the elements
// are passed into the function as rvalue references as well. This is consistent
// with std::visit but different than std::ranges::for_each. It's done this way
// because visit_breadth_first is also specialized for static and dynamic geometries
// and references for them has to be propagated like that. If this is not
// desireable then the support for other kinds of geometries should be dropped and
// this algorithm should work only for geometry collection. Or forwarding of rvalue
// references should simply be dropped entirely.
// This is not a problem right now because only non-rvalue references are passed
// but in the future there might be some issues. Consider e.g. passing a temporary
// mutable proxy range as geometry collection. In such case the elements would be
// passed as rvalue references which would be incorrect.
template <typename Geometry>
struct visit_breadth_first<Geometry, geometry_collection_tag>
: detail::visit_breadth_first_impl<>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH

View File

@ -68,6 +68,29 @@ struct distance_strategy_type<Geometry1, Geometry2, Strategies, true, true>
{};
template
<
typename Geometry1, typename Geometry2, typename Strategies,
bool IsDynamicOrGC = util::is_dynamic_geometry<Geometry1>::value
|| util::is_dynamic_geometry<Geometry2>::value
|| util::is_geometry_collection<Geometry1>::value
|| util::is_geometry_collection<Geometry2>::value
>
struct distance_strategy_tag
{
using type = void;
};
template <typename Geometry1, typename Geometry2, typename Strategies>
struct distance_strategy_tag<Geometry1, Geometry2, Strategies, false>
{
using type = typename strategy::distance::services::tag
<
typename distance_strategy_type<Geometry1, Geometry2, Strategies>::type
>::type;
};
template
<
typename Geometry1, typename Geometry2,
@ -91,11 +114,11 @@ template
linear_tag,
areal_tag
>::type,
typename StrategyTag = typename strategy::distance::services::tag
typename StrategyTag = typename distance_strategy_tag
<
typename distance_strategy_type<Geometry1, Geometry2, Strategy>::type
Geometry1, Geometry2, Strategy
>::type,
bool Reverse = reverse_dispatch<Geometry1, Geometry2>::type::value
bool Reverse = reverse_dispatch<Geometry1, Geometry2>::value
>
struct distance : not_implemented<Tag1, Tag2>
{};

View File

@ -5,8 +5,8 @@
// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2014-2020.
// Modifications copyright (c) 2014-2020, Oracle and/or its affiliates.
// This file was modified by Oracle on 2014-2021.
// Modifications copyright (c) 2014-2021, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@ -26,21 +26,20 @@
#include <boost/range/size.hpp>
#include <boost/range/value_type.hpp>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/algorithms/detail/counting.hpp>
#include <boost/geometry/algorithms/detail/visit.hpp>
#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/core/tag_cast.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/visit.hpp>
#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/algorithms/detail/counting.hpp>
#include <boost/geometry/geometries/adapted/boost_variant.hpp> // For backward compatibility
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/util/type_traits_std.hpp>
namespace boost { namespace geometry
{
@ -140,48 +139,54 @@ struct num_points<Geometry, AddForOpen, multi_tag>
#endif
namespace resolve_variant
namespace resolve_dynamic
{
template <typename Geometry>
template <typename Geometry, typename Tag = typename tag<Geometry>::type>
struct num_points
{
static inline std::size_t apply(Geometry const& geometry,
bool add_for_open)
static inline std::size_t apply(Geometry const& geometry, bool add_for_open)
{
concepts::check<Geometry const>();
return add_for_open
? dispatch::num_points<Geometry, true>::apply(geometry)
: dispatch::num_points<Geometry, false>::apply(geometry);
? dispatch::num_points<Geometry, true>::apply(geometry)
: dispatch::num_points<Geometry, false>::apply(geometry);
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct num_points<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
template <typename Geometry>
struct num_points<Geometry, dynamic_geometry_tag>
{
struct visitor: boost::static_visitor<std::size_t>
static inline std::size_t apply(Geometry const& geometry, bool add_for_open)
{
bool m_add_for_open;
visitor(bool add_for_open): m_add_for_open(add_for_open) {}
template <typename Geometry>
inline std::size_t operator()(Geometry const& geometry) const
std::size_t result = 0;
traits::visit<Geometry>::apply([&](auto const& g)
{
return num_points<Geometry>::apply(geometry, m_add_for_open);
}
};
static inline std::size_t
apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
bool add_for_open)
{
return boost::apply_visitor(visitor(add_for_open), geometry);
result = num_points<util::remove_cref_t<decltype(g)>>::apply(g, add_for_open);
}, geometry);
return result;
}
};
} // namespace resolve_variant
template <typename Geometry>
struct num_points<Geometry, geometry_collection_tag>
{
static inline std::size_t apply(Geometry const& geometry, bool add_for_open)
{
std::size_t result = 0;
detail::visit_breadth_first([&](auto const& g)
{
result += num_points<util::remove_cref_t<decltype(g)>>::apply(g, add_for_open);
return true;
}, geometry);
return result;
}
};
} // namespace resolve_dynamic
/*!
@ -198,7 +203,7 @@ struct num_points<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
template <typename Geometry>
inline std::size_t num_points(Geometry const& geometry, bool add_for_open = false)
{
return resolve_variant::num_points<Geometry>::apply(geometry, add_for_open);
return resolve_dynamic::num_points<Geometry>::apply(geometry, add_for_open);
}
#if defined(_MSC_VER)

View File

@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014-2020, Oracle and/or its affiliates.
// Copyright (c) 2014-2021, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@ -16,22 +16,19 @@
#include <boost/range/size.hpp>
#include <boost/range/value_type.hpp>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/algorithms/detail/counting.hpp>
#include <boost/geometry/algorithms/detail/visit.hpp>
#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/visit.hpp>
#include <boost/geometry/util/range.hpp>
#include <boost/geometry/geometries/adapted/boost_variant.hpp> // For backward compatibility
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/algorithms/detail/counting.hpp>
#include <boost/geometry/util/range.hpp>
namespace boost { namespace geometry
{
@ -140,11 +137,11 @@ struct num_segments<Geometry, multi_polygon_tag>
namespace resolve_variant
namespace resolve_dynamic
{
template <typename Geometry>
template <typename Geometry, typename Tag = typename tag<Geometry>::type>
struct num_segments
{
static inline std::size_t apply(Geometry const& geometry)
@ -156,27 +153,38 @@ struct num_segments
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct num_segments<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
template <typename Geometry>
struct num_segments<Geometry, dynamic_geometry_tag>
{
struct visitor: boost::static_visitor<std::size_t>
static inline std::size_t apply(Geometry const& geometry)
{
template <typename Geometry>
inline std::size_t operator()(Geometry const& geometry) const
std::size_t result = 0;
traits::visit<Geometry>::apply([&](auto const& g)
{
return num_segments<Geometry>::apply(geometry);
}
};
static inline std::size_t
apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry)
{
return boost::apply_visitor(visitor(), geometry);
result = num_segments<util::remove_cref_t<decltype(g)>>::apply(g);
}, geometry);
return result;
}
};
} // namespace resolve_variant
template <typename Geometry>
struct num_segments<Geometry, geometry_collection_tag>
{
static inline std::size_t apply(Geometry const& geometry)
{
std::size_t result = 0;
detail::visit_breadth_first([&](auto const& g)
{
result += num_segments<util::remove_cref_t<decltype(g)>>::apply(g);
return true;
}, geometry);
return result;
}
};
} // namespace resolve_dynamic
@ -193,7 +201,7 @@ struct num_segments<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
template <typename Geometry>
inline std::size_t num_segments(Geometry const& geometry)
{
return resolve_variant::num_segments<Geometry>::apply(geometry);
return resolve_dynamic::num_segments<Geometry>::apply(geometry);
}

View File

@ -21,20 +21,19 @@
#include <boost/range/value_type.hpp>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/algorithms/length.hpp>
#include <boost/geometry/algorithms/detail/calculate_null.hpp>
#include <boost/geometry/algorithms/detail/calculate_sum.hpp>
#include <boost/geometry/algorithms/detail/multi_sum.hpp>
// #include <boost/geometry/algorithms/detail/throw_on_empty_input.hpp>
#include <boost/geometry/algorithms/detail/visit.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/visit.hpp>
#include <boost/geometry/geometries/adapted/boost_variant.hpp> // For backward compatibility
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/strategies/default_length_result.hpp>
@ -162,9 +161,9 @@ struct perimeter<default_strategy, false>
} // namespace resolve_strategy
namespace resolve_variant {
namespace resolve_dynamic {
template <typename Geometry>
template <typename Geometry, typename Tag = typename geometry::tag<Geometry>::type>
struct perimeter
{
template <typename Strategy>
@ -176,39 +175,40 @@ struct perimeter
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct perimeter<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
template <typename Geometry>
struct perimeter<Geometry, dynamic_geometry_tag>
{
typedef typename default_length_result
<
boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>
>::type result_type;
template <typename Strategy>
struct visitor: boost::static_visitor<result_type>
static inline typename default_length_result<Geometry>::type
apply(Geometry const& geometry, Strategy const& strategy)
{
Strategy const& m_strategy;
visitor(Strategy const& strategy): m_strategy(strategy) {}
template <typename Geometry>
typename default_length_result<Geometry>::type
operator()(Geometry const& geometry) const
typename default_length_result<Geometry>::type result = 0;
traits::visit<Geometry>::apply([&](auto const& g)
{
return perimeter<Geometry>::apply(geometry, m_strategy);
}
};
template <typename Strategy>
static inline result_type
apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
Strategy const& strategy)
{
return boost::apply_visitor(visitor<Strategy>(strategy), geometry);
result = perimeter<util::remove_cref_t<decltype(g)>>::apply(g, strategy);
}, geometry);
return result;
}
};
} // namespace resolve_variant
template <typename Geometry>
struct perimeter<Geometry, geometry_collection_tag>
{
template <typename Strategy>
static inline typename default_length_result<Geometry>::type
apply(Geometry const& geometry, Strategy const& strategy)
{
typename default_length_result<Geometry>::type result = 0;
detail::visit_breadth_first([&](auto const& g)
{
result += perimeter<util::remove_cref_t<decltype(g)>>::apply(g, strategy);
return true;
}, geometry);
return result;
}
};
} // namespace resolve_dynamic
/*!
@ -232,7 +232,7 @@ inline typename default_length_result<Geometry>::type perimeter(
Geometry const& geometry)
{
// detail::throw_on_empty_input(geometry);
return resolve_variant::perimeter<Geometry>::apply(geometry, default_strategy());
return resolve_dynamic::perimeter<Geometry>::apply(geometry, default_strategy());
}
/*!
@ -254,7 +254,7 @@ inline typename default_length_result<Geometry>::type perimeter(
Geometry const& geometry, Strategy const& strategy)
{
// detail::throw_on_empty_input(geometry);
return resolve_variant::perimeter<Geometry>::apply(geometry, strategy);
return resolve_dynamic::perimeter<Geometry>::apply(geometry, strategy);
}
}} // namespace boost::geometry

View File

@ -31,15 +31,13 @@
#include <boost/range/end.hpp>
#include <boost/range/size.hpp>
#include <boost/range/value_type.hpp>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/algorithms/area.hpp>
#include <boost/geometry/algorithms/clear.hpp>
#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/algorithms/detail/dummy_geometries.hpp>
#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
#include <boost/geometry/algorithms/detail/visit.hpp>
#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/algorithms/is_empty.hpp>
#include <boost/geometry/algorithms/perimeter.hpp>
@ -50,7 +48,9 @@
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/mutable_range.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/visit.hpp>
#include <boost/geometry/geometries/adapted/boost_variant.hpp> // For backward compatibility
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/strategies/concepts/simplify_concept.hpp>
@ -60,6 +60,8 @@
#include <boost/geometry/strategies/simplify/geographic.hpp>
#include <boost/geometry/strategies/simplify/spherical.hpp>
#include <boost/geometry/util/type_traits_std.hpp>
#ifdef BOOST_GEOMETRY_DEBUG_DOUGLAS_PEUCKER
#include <boost/geometry/io/dsv/write.hpp>
#endif
@ -301,6 +303,23 @@ struct simplify_range_insert
};
struct simplify_copy_assign
{
template
<
typename In, typename Out, typename Distance,
typename Impl, typename Strategies
>
static inline void apply(In const& in, Out& out,
Distance const& ,
Impl const& ,
Strategies const& )
{
out = in;
}
};
struct simplify_copy
{
template
@ -615,6 +634,17 @@ struct simplify<Point, point_tag>
}
};
template <typename Segment>
struct simplify<Segment, segment_tag>
: detail::simplify::simplify_copy_assign
{};
template <typename Box>
struct simplify<Box, box_tag>
: detail::simplify::simplify_copy_assign
{};
// Linestring, keep 2 points (unless those points are the same)
template <typename Linestring>
struct simplify<Linestring, linestring_tag>
@ -803,9 +833,9 @@ struct simplify_insert<default_strategy, false>
} // namespace resolve_strategy
namespace resolve_variant {
namespace resolve_dynamic {
template <typename Geometry>
template <typename Geometry, typename Tag = typename tag<Geometry>::type>
struct simplify
{
template <typename Distance, typename Strategy>
@ -818,43 +848,46 @@ struct simplify
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct simplify<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
template <typename Geometry>
struct simplify<Geometry, dynamic_geometry_tag>
{
template <typename Distance, typename Strategy>
struct visitor: boost::static_visitor<void>
static inline void apply(Geometry const& geometry,
Geometry& out,
Distance const& max_distance,
Strategy const& strategy)
{
Distance const& m_max_distance;
Strategy const& m_strategy;
visitor(Distance const& max_distance, Strategy const& strategy)
: m_max_distance(max_distance)
, m_strategy(strategy)
{}
template <typename Geometry>
void operator()(Geometry const& geometry, Geometry& out) const
traits::visit<Geometry>::apply([&](auto const& g)
{
simplify<Geometry>::apply(geometry, out, m_max_distance, m_strategy);
}
};
template <typename Distance, typename Strategy>
static inline void
apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& out,
Distance const& max_distance,
Strategy const& strategy)
{
boost::apply_visitor(
visitor<Distance, Strategy>(max_distance, strategy),
geometry,
out
);
using geom_t = util::remove_cref_t<decltype(g)>;
geom_t o;
simplify<geom_t>::apply(g, o, max_distance, strategy);
out = std::move(o);
}, geometry);
}
};
} // namespace resolve_variant
template <typename Geometry>
struct simplify<Geometry, geometry_collection_tag>
{
template <typename Distance, typename Strategy>
static inline void apply(Geometry const& geometry,
Geometry& out,
Distance const& max_distance,
Strategy const& strategy)
{
detail::visit_breadth_first([&](auto const& g)
{
using geom_t = util::remove_cref_t<decltype(g)>;
geom_t o;
simplify<geom_t>::apply(g, o, max_distance, strategy);
traits::emplace_back<Geometry>::apply(out, std::move(o));
return true;
}, geometry);
}
};
} // namespace resolve_dynamic
/*!
@ -882,7 +915,7 @@ inline void simplify(Geometry const& geometry, Geometry& out,
geometry::clear(out);
resolve_variant::simplify<Geometry>::apply(geometry, out, max_distance, strategy);
resolve_dynamic::simplify<Geometry>::apply(geometry, out, max_distance, strategy);
}

View File

@ -45,39 +45,43 @@ struct geometry_id
template <>
struct geometry_id<point_tag> : std::integral_constant<int, 1> {};
struct geometry_id<point_tag> : std::integral_constant<int, 1> {};
template <>
struct geometry_id<linestring_tag> : std::integral_constant<int, 2> {};
struct geometry_id<linestring_tag> : std::integral_constant<int, 2> {};
template <>
struct geometry_id<polygon_tag> : std::integral_constant<int, 3> {};
struct geometry_id<polygon_tag> : std::integral_constant<int, 3> {};
template <>
struct geometry_id<multi_point_tag> : std::integral_constant<int, 4> {};
struct geometry_id<multi_point_tag> : std::integral_constant<int, 4> {};
template <>
struct geometry_id<multi_linestring_tag> : std::integral_constant<int, 5> {};
struct geometry_id<multi_linestring_tag> : std::integral_constant<int, 5> {};
template <>
struct geometry_id<multi_polygon_tag> : std::integral_constant<int, 6> {};
struct geometry_id<multi_polygon_tag> : std::integral_constant<int, 6> {};
template <>
struct geometry_id<segment_tag> : std::integral_constant<int, 92> {};
struct geometry_id<geometry_collection_tag> : std::integral_constant<int, 7> {};
template <>
struct geometry_id<ring_tag> : std::integral_constant<int, 93> {};
struct geometry_id<segment_tag> : std::integral_constant<int, 92> {};
template <>
struct geometry_id<box_tag> : std::integral_constant<int, 94> {};
struct geometry_id<ring_tag> : std::integral_constant<int, 93> {};
template <>
struct geometry_id<box_tag> : std::integral_constant<int, 94> {};
} // namespace core_dispatch

View File

@ -4,8 +4,8 @@
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// 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
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
@ -21,10 +21,12 @@
#include <boost/range/value_type.hpp>
#include <boost/geometry/core/geometry_types.hpp>
#include <boost/geometry/core/ring_type.hpp>
#include <boost/geometry/core/static_assert.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/util/sequence.hpp>
#include <boost/geometry/util/type_traits_std.hpp>
@ -137,6 +139,36 @@ struct point_type<multi_polygon_tag, MultiPolygon>
};
template <typename DynamicGeometry>
struct point_type<dynamic_geometry_tag, DynamicGeometry>
{
using geometry_t = typename util::sequence_front
<
typename traits::geometry_types<DynamicGeometry>::type
>::type;
using type = typename point_type
<
typename tag<geometry_t>::type,
typename util::remove_cptrref<geometry_t>::type
>::type;
};
template <typename GeometryCollection>
struct point_type<geometry_collection_tag, GeometryCollection>
{
using geometry_t = typename util::sequence_front
<
typename traits::geometry_types<GeometryCollection>::type
>::type;
using type = typename point_type
<
typename tag<geometry_t>::type,
typename util::remove_cptrref<geometry_t>::type
>::type;
};
} // namespace core_dispatch
#endif // DOXYGEN_NO_DISPATCH

View File

@ -2,8 +2,8 @@
// Copyright (c) 2013 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2016-2020.
// Modifications copyright (c) 2016-2020 Oracle and/or its affiliates.
// This file was modified by Oracle on 2016-2021.
// Modifications copyright (c) 2016-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,
@ -53,8 +53,8 @@ struct less<Type, false>
template <typename Ratio>
static inline bool apply(Ratio const& lhs, Ratio const& rhs)
{
BOOST_GEOMETRY_ASSERT(lhs.denominator() != 0);
BOOST_GEOMETRY_ASSERT(rhs.denominator() != 0);
BOOST_GEOMETRY_ASSERT(lhs.denominator() != Type(0));
BOOST_GEOMETRY_ASSERT(rhs.denominator() != Type(0));
Type const a = lhs.numerator() / lhs.denominator();
Type const b = rhs.numerator() / rhs.denominator();
return ! geometry::math::equals(a, b)
@ -86,8 +86,8 @@ struct equal<Type, false>
template <typename Ratio>
static inline bool apply(Ratio const& lhs, Ratio const& rhs)
{
BOOST_GEOMETRY_ASSERT(lhs.denominator() != 0);
BOOST_GEOMETRY_ASSERT(rhs.denominator() != 0);
BOOST_GEOMETRY_ASSERT(lhs.denominator() != Type(0));
BOOST_GEOMETRY_ASSERT(rhs.denominator() != Type(0));
Type const a = lhs.numerator() / lhs.denominator();
Type const b = rhs.numerator() / rhs.denominator();
return geometry::math::equals(a, b);
@ -144,7 +144,8 @@ class segment_ratio
// Type-alias for the type itself
using thistype = segment_ratio<Type>;
public :
public:
using int_type = Type;
inline segment_ratio()
: m_numerator(0)
@ -231,7 +232,7 @@ public :
);
}
inline bool is_zero() const { return math::equals(m_numerator, 0); }
inline bool is_zero() const { return math::equals(m_numerator, Type(0)); }
inline bool is_one() const { return math::equals(m_numerator, m_denominator); }
inline bool on_segment() const
{

View File

@ -26,7 +26,7 @@
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/strategy/cartesian/side_robust.hpp>
#include <boost/geometry/strategies/side.hpp>
#include <boost/geometry/strategies/covered_by.hpp>
#include <boost/geometry/strategies/within.hpp>
@ -118,11 +118,14 @@ struct cartesian_point_box_by_side
template <typename Point, typename Box>
static inline bool apply(Point const& point, Box const& box)
{
using side_strategy_type
= typename strategy::side::services::default_strategy
<cartesian_tag, CalculationType>::type;
return within::detail::point_in_box_by_side
<
within::detail::decide_within
>(point, box,
strategy::side::side_robust<CalculationType>());
>(point, box, side_strategy_type());
}
};
@ -189,11 +192,13 @@ struct cartesian_point_box_by_side
template <typename Point, typename Box>
static bool apply(Point const& point, Box const& box)
{
using side_strategy_type
= typename strategy::side::services::default_strategy
<cartesian_tag, CalculationType>::type;
return within::detail::point_in_box_by_side
<
within::detail::decide_covered_by
>(point, box,
strategy::side::side_robust<CalculationType>());
>(point, box, side_strategy_type());
}
};

View File

@ -86,8 +86,11 @@ struct strategy_converter<strategy::area::geographic<FP, SO, S, CT> >
: strategies::area::geographic<FP, S, CT>(spheroid)
{}
using strategies::area::geographic<FP, S, CT>::area;
template <typename Geometry>
auto area(Geometry const&) const
auto area(Geometry const&,
std::enable_if_t<! util::is_box<Geometry>::value> * = nullptr) const
{
return strategy::area::geographic<FP, SO, S, CT>(this->m_spheroid);
}

View File

@ -38,7 +38,6 @@
#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>
@ -174,7 +173,7 @@ struct cartesian_segments
// Up to now, division was postponed. Here we divide using numerator/
// denominator. In case of integer this results in an integer
// division.
BOOST_GEOMETRY_ASSERT(ratio.denominator() != 0);
BOOST_GEOMETRY_ASSERT(ratio.denominator() != typename SegmentRatio::int_type(0));
typedef typename promote_integral<CoordinateType>::type calc_type;
@ -439,7 +438,9 @@ struct cartesian_segments
return Policy::disjoint();
}
typedef side::side_robust<CalculationType> side_strategy_type;
using side_strategy_type
= typename side::services::default_strategy
<cartesian_tag, CalculationType>::type;
side_info sides;
sides.set<0>(side_strategy_type::apply(q1, q2, p1),
side_strategy_type::apply(q1, q2, p2));

View File

@ -24,7 +24,7 @@
#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/side.hpp>
#include <boost/geometry/strategies/cartesian/point_in_box.hpp>
#include <boost/geometry/strategies/cartesian/disjoint_box_box.hpp>
@ -116,7 +116,9 @@ public:
else // count == 2 || count == -2
{
// 1 left, -1 right
typedef side::side_robust<CalculationType> side_strategy_type;
using side_strategy_type
= typename side::services::default_strategy
<cartesian_tag, CalculationType>::type;
side = side_strategy_type::apply(s1, s2, point);
}

View File

@ -11,11 +11,11 @@
#ifndef BOOST_GEOMETRY_STRATEGIES_CONVEX_HULL_CARTESIAN_HPP
#define BOOST_GEOMETRY_STRATEGIES_CONVEX_HULL_CARTESIAN_HPP
#include <boost/geometry/strategies/side.hpp>
#include <boost/geometry/strategies/cartesian/point_in_point.hpp>
#include <boost/geometry/strategies/convex_hull/services.hpp>
#include <boost/geometry/strategies/detail.hpp>
#include <boost/geometry/strategy/cartesian/side_robust.hpp>
#include <boost/geometry/util/type_traits.hpp>
@ -42,7 +42,10 @@ public:
static auto side()
{
return strategy::side::side_robust<CalculationType>();
using side_strategy_type
= typename strategy::side::services::default_strategy
<cartesian_tag, CalculationType>::type;
return side_strategy_type();
}
};

View File

@ -68,6 +68,13 @@ struct cartesian
{
return strategy::envelope::cartesian<CalculationType>();
}
template <typename Geometry, typename Box>
static auto envelope(Geometry const&, Box const&,
typename util::enable_if_geometry_collection_t<Geometry> * = nullptr)
{
return strategy::envelope::cartesian<CalculationType>();
}
};

View File

@ -86,6 +86,16 @@ public:
FormulaPolicy, Spheroid, CalculationType
>(base_t::m_spheroid);
}
template <typename Geometry, typename Box>
auto envelope(Geometry const&, Box const&,
typename util::enable_if_geometry_collection_t<Geometry> * = nullptr) const
{
return strategy::envelope::geographic
<
FormulaPolicy, Spheroid, CalculationType
>(base_t::m_spheroid);
}
};

View File

@ -79,6 +79,13 @@ struct spherical
{
return strategy::envelope::spherical<CalculationType>();
}
template <typename Geometry, typename Box>
static auto envelope(Geometry const&, Box const&,
typename util::enable_if_geometry_collection_t<Geometry> * = nullptr)
{
return strategy::envelope::spherical<CalculationType>();
}
};

View File

@ -19,8 +19,6 @@
#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>

View File

@ -15,6 +15,7 @@
#include <boost/geometry/strategies/detail.hpp>
#include <boost/geometry/strategies/is_convex/services.hpp>
#include <boost/geometry/strategy/cartesian/side_by_triangle.hpp>
#include <boost/geometry/strategy/cartesian/side_robust.hpp>
namespace boost { namespace geometry

View File

@ -158,7 +158,10 @@ public:
static auto side()
{
return strategy::side::side_robust<CalculationType>();
using side_strategy_type
= typename strategy::side::services::default_strategy
<cartesian_tag, CalculationType>::type;
return side_strategy_type();
}
// within

View File

@ -24,17 +24,15 @@
#include <type_traits>
#include <boost/geometry/core/config.hpp>
#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>
@ -254,6 +252,23 @@ private:
}
};
#if ! defined(BOOST_GEOMETRY_USE_RESCALING)
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template <typename CalculationType>
struct default_strategy<cartesian_tag, CalculationType>
{
typedef side_by_triangle<CalculationType> type;
};
}
#endif
#endif
}} // namespace strategy::side
}} // namespace boost::geometry

View File

@ -18,6 +18,7 @@
#ifndef BOOST_GEOMETRY_STRATEGY_CARTESIAN_SIDE_ROBUST_HPP
#define BOOST_GEOMETRY_STRATEGY_CARTESIAN_SIDE_ROBUST_HPP
#include <boost/geometry/core/config.hpp>
#include <boost/geometry/strategy/cartesian/side_non_robust.hpp>
#include <boost/geometry/strategies/side.hpp>
@ -177,6 +178,7 @@ public:
};
#ifdef BOOST_GEOMETRY_USE_RESCALING
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
@ -190,6 +192,7 @@ struct default_strategy<cartesian_tag, CalculationType>
}
#endif
#endif
}} // namespace strategy::side

View File

@ -26,7 +26,16 @@ test-suite boost-geometry-algorithms-buffer
[ run buffer_multi_linestring.cpp : : : <define>BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE : algorithms_buffer_multi_linestring ]
[ run buffer_multi_polygon.cpp : : : <define>BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE : algorithms_buffer_multi_polygon ]
[ run buffer_linestring_aimes.cpp : : : <define>BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE : algorithms_buffer_linestring_aimes ]
# Uncomment next line if you want to test this manually; requires access to data/ folder
# TODO
# [ run buffer_linestring.cpp : : : <define>BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE <define>BOOST_GEOMETRY_NO_ROBUSTNESS : algorithms_buffer_linestring_norescale ]
# [ run buffer_multi_linestring.cpp : : : <define>BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE <define>BOOST_GEOMETRY_NO_ROBUSTNESS : algorithms_buffer_multi_linestring_norescale ]
[ run buffer_ring.cpp : : : <define>BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE <define>BOOST_GEOMETRY_NO_ROBUSTNESS : algorithms_buffer_ring_norescale ]
[ run buffer_polygon.cpp : : : <define>BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE <define>BOOST_GEOMETRY_NO_ROBUSTNESS : algorithms_buffer_polygon_norescale ]
[ run buffer_multi_point.cpp : : : <define>BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE <define>BOOST_GEOMETRY_NO_ROBUSTNESS : algorithms_buffer_multi_point_norescale ]
[ run buffer_multi_polygon.cpp : : : <define>BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE <define>BOOST_GEOMETRY_NO_ROBUSTNESS : algorithms_buffer_multi_polygon_norescale ]
[ run buffer_linestring_aimes.cpp : : : <define>BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE <define>BOOST_GEOMETRY_NO_ROBUSTNESS : algorithms_buffer_linestring_aimes_norescale ]
# Uncomment next lines if you want to test this manually; requires access to data/ folder
# [ run buffer_countries.cpp : : : <define>BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE : algorithms_buffer_countries ]
# [ run buffer_countries.cpp : : : <define>BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE <define>BOOST_GEOMETRY_NO_ROBUSTNESS : algorithms_buffer_countries_norescale ]
;

View File

@ -1,7 +1,7 @@
// Boost.Geometry
// Unit Test
// Copyright (c) 2017-2018, Oracle and/or its affiliates.
// Copyright (c) 2017-2021, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@ -9,6 +9,8 @@
// http://www.boost.org/users/license.html
#include <boost/variant/variant.hpp>
#include <geometry_test_common.hpp>
#include <boost/geometry/geometries/geometries.hpp>
@ -159,6 +161,17 @@ inline void test_geometry(std::string const& wkt, Check const& check)
bg::densify(g, o, max_distance);
check_result(g, o, max_distance, def_s, check);
using variant_t = boost::variant<G, typename bg::point_type<G>::type>;
variant_t v = g, vo;
bg::densify(v, vo, max_distance);
check(v, vo, def_s);
bg::model::geometry_collection<variant_t> gc{v}, gco;
bg::densify(gc, gco, max_distance);
check(gc, gco, def_s);
}
{

View File

@ -491,6 +491,24 @@ void test_variant()
//BOOST_CHECK_CLOSE(bg::distance(point, v2, s), bg::distance(point, point, s), 0.0001);
}
template <typename T>
void test_geometry_collection()
{
using point_type = bg::model::point<T, 2, bg::cs::cartesian>;
using segment_type = bg::model::segment<point_type>;
using box_type = bg::model::box<point_type>;
using variant_type = boost::variant<point_type, segment_type, box_type>;
using gc_type = bg::model::geometry_collection<variant_type>;
point_type p1 {1, 3}, p2 {2, 3};
segment_type s1 {{2, 2}, {4, 4}}, s2 {{3, 2}, {5, 4}};
gc_type gc1 {p1, s1}, gc2 {p2, s2};
BOOST_CHECK_CLOSE(bg::distance(p1, gc2), bg::distance(p1, p2), 0.0001);
BOOST_CHECK_CLOSE(bg::distance(gc1, s2), bg::distance(s1, s2), 0.0001);
BOOST_CHECK_CLOSE(bg::distance(gc1, gc2), bg::distance(s1, s2), 0.0001);
}
int test_main(int, char* [])
{
#ifdef TEST_ARRAY
@ -525,5 +543,7 @@ int test_main(int, char* [])
test_variant<double>();
test_variant<int>();
test_geometry_collection<double>();
return 0;
}

View File

@ -21,6 +21,7 @@
#include <boost/geometry/algorithms/envelope.hpp>
#include <boost/geometry/geometries/box.hpp>
#include <boost/geometry/geometries/geometry_collection.hpp>
#include <boost/geometry/strategies/strategies.hpp>
#include <boost/geometry/io/wkt/read.hpp>
@ -97,6 +98,10 @@ void test_envelope(std::string const& wkt,
check_result<box_type, bg::dimension<Geometry>::type::value>
::apply(b, x1, y1, z1, x2, y2, z2);
bg::model::geometry_collection<boost::variant<Geometry>> gc{v};
bg::envelope(gc, b);
check_result<box_type, bg::dimension<Geometry>::type::value>
::apply(b, x1, y1, z1, x2, y2, z2);
}

View File

@ -19,4 +19,5 @@ test-suite boost-geometry-algorithms-equals
[ run equals.cpp : : : : algorithms_equals ]
[ run equals_multi.cpp : : : : algorithms_equals_multi ]
[ run equals_on_spheroid.cpp : : : : algorithms_equals_on_spheroid ]
[ run equals_sph.cpp : : : : algorithms_equals_sph ]
;

View File

@ -233,3 +233,32 @@ BOOST_AUTO_TEST_CASE( equals_segment_segment_geo )
test_segment_segment<bgm::point<double, 2, cs_type> >("geo");
test_segment_segment<bgm::point<long double, 2, cs_type> >("geo");
}
// This version uses collect_vectors (because its side
// strategy is spherical_side_formula) and fails
BOOST_AUTO_TEST_CASE( equals_ring_ring_se)
{
using cs_type = bg::cs::spherical_equatorial<bg::degree> ;
using ring_type = bgm::ring<bgm::point<double, 2, cs_type> >;
test_geometry<ring_type, ring_type>("ring_simplex",
"POLYGON((10 50,10 51,11 50,10 50))",
"POLYGON((10 50,10 51,11 50,10 50))",
true);
}
BOOST_AUTO_TEST_CASE( equals_ring_ring_geo )
{
using cs_type = bg::cs::geographic<bg::degree> ;
using ring_type = bgm::ring<bgm::point<double, 2, cs_type> >;
test_geometry<ring_type, ring_type>("ring_simplex",
"POLYGON((10 50,10 51,11 50,10 50))",
"POLYGON((10 50,10 51,11 50,10 50))",
true);
test_geometry<ring_type, ring_type>("ring_simplex_false",
"POLYGON((10 50,10 51,11 50,10 50))",
"POLYGON((10 50,10 51.01,11 50,10 50))",
false);
}

View File

@ -147,5 +147,13 @@ int test_main( int , char* [] )
{
test_all<bg::model::point<double, 2, bg::cs::spherical_equatorial<bg::degree> > >();
// TODO: the polar version needs several traits more, for example in cs_tag,
// to compile properly.
//test_all<bg::model::point<double, 2, bg::cs::polar<bg::degree> > >();
#if defined(BOOST_GEOMETRY_TEST_FAILURES)
test_all<bg::model::point<double, 2, bg::cs::geographic<bg::degree> > >();
#endif
return 0;
}

View File

@ -26,7 +26,10 @@
#include <boost/variant/variant.hpp>
struct no_strategy {};
struct no_strategy
{
using cs_tag = void;
};
template <typename Geometry1, typename Geometry2, typename Strategy>
bool call_equals(Geometry1 const& geometry1,
@ -60,7 +63,9 @@ void check_geometry(Geometry1 const& geometry1,
<< " equals: " << wkt1
<< " to " << wkt2
<< " -> Expected: " << expected
<< " detected: " << detected);
<< " detected: " << detected
<< " strategy: " << typeid(Strategy).name()
<< " cs: " << typeid(typename Strategy::cs_tag).name());
detected = call_equals(geometry2, geometry1, strategy);
@ -69,7 +74,8 @@ void check_geometry(Geometry1 const& geometry1,
<< " equals: " << wkt2
<< " to " << wkt1
<< " -> Expected: " << expected
<< " detected: " << detected);
<< " strategy: " << typeid(Strategy).name()
<< " cs: " << typeid(typename Strategy::cs_tag).name());
}

View File

@ -1,7 +1,7 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Unit Test
// Copyright (c) 2014-2018, Oracle and/or its affiliates.
// Copyright (c) 2014-2021, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@ -27,6 +27,8 @@
#include <boost/geometry/algorithms/intersection.hpp>
#include <boost/geometry/algorithms/reverse.hpp>
#include <boost/geometry/geometries/geometry_collection.hpp>
BOOST_AUTO_TEST_CASE( test_is_valid_point )
{
#ifdef BOOST_GEOMETRY_TEST_DEBUG
@ -1414,3 +1416,40 @@ BOOST_AUTO_TEST_CASE( test_is_valid_variant )
vg = invalid_polygon;
test::apply("v04", vg, false);
}
BOOST_AUTO_TEST_CASE( test_is_valid_geometry_collection )
{
#ifdef BOOST_GEOMETRY_TEST_DEBUG
std::cout << std::endl << std::endl;
std::cout << "************************************" << std::endl;
std::cout << " is_valid: geometry collection" << std::endl;
std::cout << "************************************" << std::endl;
#endif
using polygon_type = bg::model::polygon<point_type>; // cw, closed
using variant_type = boost::variant
<
linestring_type, multi_linestring_type, polygon_type
>;
using gc_type = bg::model::geometry_collection<variant_type>;
typedef test_valid_variant<gc_type> test;
gc_type gc;
linestring_type valid_linestring =
from_wkt<linestring_type>("LINESTRING(0 0,1 0)");
multi_linestring_type invalid_multi_linestring =
from_wkt<multi_linestring_type>("MULTILINESTRING((0 0,1 0),(0 0))");
polygon_type valid_polygon =
from_wkt<polygon_type>("POLYGON((0 0,1 1,1 0,0 0))");
polygon_type invalid_polygon =
from_wkt<polygon_type>("POLYGON((0 0,2 2,2 0,1 0))");
gc = {valid_linestring, valid_polygon};
test::apply("gc01", gc, true);
gc = {invalid_multi_linestring, valid_polygon};
test::apply("gc02", gc, false);
gc = {valid_linestring, invalid_polygon};
test::apply("gc03", gc, false);
}

View File

@ -6,6 +6,10 @@
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// Copyright (c) 2013-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
// 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)
@ -67,6 +71,12 @@ int test_main(int, char* [])
typedef bg::model::polygon<point, true, false> open_polygon;
typedef bg::model::multi_polygon<open_polygon> open_multi_polygon;
using variant = boost::variant<linestring, polygon>;
using open_variant = boost::variant<linestring, open_polygon>;
using geometry_collection = bg::model::geometry_collection<variant>;
using open_geometry_collection = bg::model::geometry_collection<open_variant>;
test_num_points<point>("POINT(0 0)", 1u);
test_num_points<linestring>("LINESTRING(0 0,1 1)", 2u);
test_num_points<segment>("LINESTRING(0 0,1 1)", 2u);
@ -89,6 +99,12 @@ int test_main(int, char* [])
test_num_points<open_multi_polygon>("MULTIPOLYGON(((0 0,0 10,10 10,10 0)),((0 10,1 10,1 9)))", 7u, 9u);
test_num_points<open_multi_polygon>("MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0)),((0 10,1 10,1 9,0 10)))", 7u, 9u);
test_num_points<variant>("POLYGON((0 0,1 1,0 1,0 0))", 4u);
test_num_points<open_variant>("POLYGON((0 0,1 1,0 1))", 3u, 4u);
test_num_points<geometry_collection>("GEOMETRYCOLLECTION(POLYGON((0 0,1 1,0 1,0 0)),LINESTRING(0 0,1 1))", 6u);
test_num_points<open_geometry_collection>("GEOMETRYCOLLECTION(POLYGON((0 0,1 1,0 1)),LINESTRING(0 0,1 1))", 5u, 6u);
return 0;
}

View File

@ -1,9 +1,10 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Unit Test
// Copyright (c) 2014, Oracle and/or its affiliates.
// Copyright (c) 2014-2021, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
@ -289,3 +290,16 @@ BOOST_AUTO_TEST_CASE( test_variant )
variant_geometry = p_closed;
tester::apply(variant_geometry, 4);
}
BOOST_AUTO_TEST_CASE( test_geometry_collection )
{
using variant = boost::variant<linestring, polygon_cw_closed>;
using geometry_collection = bg::model::geometry_collection<variant>;
using tester = test_num_segments<geometry_collection>;
geometry_collection gc;
bg::read_wkt("GEOMETRYCOLLECTION(LINESTRING(0 0,1 1,2 2),POLYGON((0 0,0 1,1 1,1 0,0 0)))", gc);
tester::apply(gc, 6);
}

View File

@ -16,16 +16,15 @@
test-suite boost-geometry-algorithms-difference
:
[ run difference.cpp : : : <define>BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE
: algorithms_difference ]
[ run difference.cpp : : : <define>BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE : algorithms_difference ]
[ run difference_multi.cpp : : : <define>BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE : algorithms_difference_multi ]
[ run difference.cpp : : : <define>BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE <define>BOOST_GEOMETRY_NO_ROBUSTNESS : algorithms_difference_norescale ]
[ run difference_multi.cpp : : : <define>BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE <define>BOOST_GEOMETRY_NO_ROBUSTNESS : algorithms_difference_multi_norescale ]
[ run difference_multi_spike.cpp : : : <define>BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE : algorithms_difference_multi_spike ]
[ run difference_areal_linear.cpp : : : : algorithms_difference_areal_linear ]
[ run difference_l_a_sph.cpp : : : : algorithms_difference_l_a_sph ]
[ run difference_linear_linear.cpp : : : : algorithms_difference_linear_linear ]
[ run difference_multi.cpp : : : <define>BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE
: algorithms_difference_multi ]
[ run difference_multi_areal_linear.cpp : : : : algorithms_difference_multi_areal_linear ]
[ run difference_multi_spike.cpp : : : <define>BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE
: algorithms_difference_multi_spike ]
[ run difference_pl_a.cpp : : : : algorithms_difference_pl_a ]
[ run difference_pl_l.cpp : : : : algorithms_difference_pl_l ]
[ run difference_pl_pl.cpp : : : : algorithms_difference_pl_pl ]

View File

@ -51,7 +51,7 @@ void test_spikes_in_ticket_8364()
"MULTIPOLYGON(((1032 2556,1778 2556,1032 2130,1032 2556)),((3234 2580,3234 2556,1778 2556,2136 2760,3234 2580)))",
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));
count_set(1, 3), ignore_validity);
}
template <typename P, bool ClockWise, bool Closed>

View File

@ -16,12 +16,12 @@
test-suite boost-geometry-algorithms-intersection
:
[ run intersection.cpp : : : <define>BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE
: algorithms_intersection ]
[ run intersection.cpp : : : <define>BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE : algorithms_intersection ]
[ run intersection_multi.cpp : : : <define>BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE : algorithms_intersection_multi ]
[ run intersection.cpp : : : <define>BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE <define>BOOST_GEOMETRY_NO_ROBUSTNESS : algorithms_intersection_norescale ]
[ run intersection_multi.cpp : : : <define>BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE <define>BOOST_GEOMETRY_NO_ROBUSTNESS : algorithms_intersection_multi_norescale ]
[ run intersection_areal_areal_linear.cpp : : : : algorithms_intersection_areal_areal_linear ]
[ run intersection_linear_linear.cpp : : : : algorithms_intersection_linear_linear ]
[ run intersection_multi.cpp : : : <define>BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE
: algorithms_intersection_multi ]
[ run intersection_pl_a.cpp : : : : algorithms_intersection_pl_a ]
[ run intersection_pl_l.cpp : : : : algorithms_intersection_pl_l ]
[ run intersection_pl_pl.cpp : : : : algorithms_intersection_pl_pl ]

View File

@ -16,14 +16,14 @@
test-suite boost-geometry-algorithms-union
:
[ run union.cpp : : : <define>BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE
: algorithms_union ]
[ run union.cpp : : : <define>BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE : algorithms_union ]
[ run union_multi.cpp : : : <define>BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE : algorithms_union_multi ]
[ run union.cpp : : : <define>BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE <define>BOOST_GEOMETRY_NO_ROBUSTNESS : algorithms_union_norescale ]
[ run union_multi.cpp : : : <define>BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE <define>BOOST_GEOMETRY_NO_ROBUSTNESS : algorithms_union_multi_norescale ]
[ run union_aa_geo.cpp : : : : algorithms_union_aa_geo ]
[ run union_aa_sph.cpp : : : : algorithms_union_aa_sph ]
[ run union_linear_linear.cpp : : : : algorithms_union_linear_linear ]
[ run union_multi.cpp : : : <define>BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE
: algorithms_union_multi ]
[ run union_pl_pl.cpp : : : : algorithms_union_pl_pl ]
[ run union_tupled.cpp : : : : algorithms_union_tupled ]
[ run union_other_types.cpp : : : : algorithms_union_other_types ]
[ run union_other_types.cpp : : : <define>BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE : algorithms_union_other_types ]
;

View File

@ -113,6 +113,7 @@ int test_main(int, char* [])
using bg::model::d2::point_xy;
#if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE)
// Standard floating point types
test_areal<point_xy<float>>({exclude::hard});
test_areal<point_xy<double>>({});
@ -121,23 +122,30 @@ int test_main(int, char* [])
// Standard integer types
test_areal<point_xy<std::int16_t>>({exclude::fp});
test_areal<point_xy<std::int32_t>>({exclude::fp});
#endif
test_areal<point_xy<std::int64_t>>({exclude::fp});
// Boost multi precision (integer)
test_areal<point_xy<bm::int128_t>>({exclude::fp});
#if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE)
test_areal<point_xy<bm::checked_int128_t>>({exclude::fp});
#endif
// Boost multi precision (floating point)
#if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE)
test_areal<point_xy<bm::number<bm::cpp_bin_float<5>>>>();
test_areal<point_xy<bm::number<bm::cpp_bin_float<10>>>>();
test_areal<point_xy<bm::number<bm::cpp_bin_float<50>>>>();
#endif
test_areal<point_xy<bm::number<bm::cpp_bin_float<100>>>>();
test_areal<point_xy<bm::number<bm::cpp_dec_float<50>>>>({});
// Boost multi precision (rational)
test_areal<point_xy<bm::cpp_rational>>({exclude::fp});
#if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE)
test_areal<point_xy<bm::checked_cpp_rational>>({exclude::fp});
#endif
// Boost multi precision float128 wrapper, is currently NOT supported
// and it is limited to certain compilers anyway
@ -146,8 +154,10 @@ int test_main(int, char* [])
// Boost rational (tests compilation)
// (the rectangular case is correct; other input might give wrong results)
// The int16 version throws a <zero denominator> exception
#if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE)
test_areal<point_xy<boost::rational<std::int16_t>>>({exclude::all});
test_areal<point_xy<boost::rational<std::int32_t>>>({exclude::fp});
#endif
test_areal<point_xy<boost::rational<std::int64_t>>>({exclude::fp});
return 0;

View File

@ -5,6 +5,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.
@ -222,6 +226,18 @@ void test_all()
"POINT(0 0)",
"POINT(0 0)", 1.0);
test_geometry<bg::model::segment<P> >(
"SEGMENT(0 0, 1 1)",
"SEGMENT(0 0, 1 1)", 1.0);
test_geometry<bg::model::box<P> >(
"BOX(0 0, 1 1)",
"BOX(0 0, 1 1)", 1.0);
test_geometry<bg::model::multi_point<P> >(
"MULTIPOINT(0 0, 1 1, 2 2)",
"MULTIPOINT(0 0, 1 1, 2 2)", 1.0);
// RING: check compilation and behaviour
test_geometry<bg::model::ring<P> >(

View File

@ -2,6 +2,11 @@
// Unit Test
// Copyright (c) 2007-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)
@ -15,6 +20,7 @@
#include <geometry_test_common.hpp>
#include <boost/geometry/algorithms/perimeter.hpp>
#include <boost/geometry/geometries/geometry_collection.hpp>
#include <boost/geometry/strategies/strategies.hpp>
#include <boost/geometry/io/wkt/read.hpp>
@ -37,6 +43,16 @@ void test_perimeter(Geometry const& geometry, long double expected_perimeter)
#endif
BOOST_CHECK_CLOSE(perimeter, expected_perimeter, 0.0001);
boost::variant<Geometry> v(geometry);
perimeter = bg::perimeter(v);
BOOST_CHECK_CLOSE(perimeter, expected_perimeter, 0.0001);
bg::model::geometry_collection<boost::variant<Geometry>> gc{v};
perimeter = bg::perimeter(gc);
BOOST_CHECK_CLOSE(perimeter, expected_perimeter, 0.0001);
}
@ -58,6 +74,16 @@ void test_perimeter(Geometry const& geometry, long double expected_perimeter, St
#endif
BOOST_CHECK_CLOSE(perimeter, expected_perimeter, 0.0001);
boost::variant<Geometry> v(geometry);
perimeter = bg::perimeter(v, strategy);
BOOST_CHECK_CLOSE(perimeter, expected_perimeter, 0.0001);
bg::model::geometry_collection<boost::variant<Geometry>> gc{v};
perimeter = bg::perimeter(gc, strategy);
BOOST_CHECK_CLOSE(perimeter, expected_perimeter, 0.0001);
}
template <typename Geometry>
@ -65,12 +91,7 @@ void test_geometry(std::string const& wkt, double expected_perimeter)
{
Geometry geometry;
bg::read_wkt(wkt, geometry);
boost::variant<Geometry> v(geometry);
test_perimeter(geometry, expected_perimeter);
#if !defined(BOOST_GEOMETRY_TEST_DEBUG)
test_perimeter(v, expected_perimeter);
#endif
}
template <typename Geometry, typename Strategy>

View File

@ -2,6 +2,11 @@
// Unit Test
// Copyright (c) 2007-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)
@ -18,11 +23,24 @@
#include <boost/geometry/algorithms/equals.hpp>
#include <boost/geometry/algorithms/simplify.hpp>
#include <boost/geometry/algorithms/distance.hpp>
#include <boost/geometry/geometries/geometry_collection.hpp>
#include <boost/geometry/strategies/strategies.hpp>
#include <boost/geometry/io/wkt/wkt.hpp>
#include <boost/variant/variant.hpp>
template <typename Geometry, typename Tag = typename bg::tag<Geometry>::type>
struct boost_variant_type
{
using type = boost::variant<Geometry, typename bg::point_type<Geometry>::type>;
};
template <typename Geometry>
struct boost_variant_type<Geometry, bg::point_tag>
{
using type = boost::variant<Geometry>;
};
template
<
typename GeometryForTag,
@ -158,8 +176,9 @@ void test_geometry(std::string const& wkt,
bg::read_wkt(wkt, geometry);
bg::read_wkt(expected_wkt, expected);
boost::variant<Geometry> v(geometry);
using variant_t = typename boost_variant_type<Geometry>::type;
variant_t v(geometry);
// Define default strategy for testing
typedef bg::strategy::simplify::douglas_peucker
<
@ -167,15 +186,27 @@ void test_geometry(std::string const& wkt,
bg::strategy::distance::projected_point<double>
> dp;
BOOST_CONCEPT_ASSERT((bg::concepts::SimplifyStrategy<dp, point_type>));
check_geometry(geometry, expected, distance);
check_geometry(v, expected, distance);
BOOST_CONCEPT_ASSERT( (bg::concepts::SimplifyStrategy<dp, point_type>) );
check_geometry(geometry, expected, distance, dp());
check_geometry(v, expected, distance, dp());
// For now check GC here because it's not supported by equals()
{
using gc_t = bg::model::geometry_collection<variant_t>;
gc_t gc{v};
gc_t gc_simplified;
bg::simplify(gc, gc_simplified, distance);
bg::detail::visit_breadth_first([&](auto const& g)
{
test_equality<Geometry>::apply(g, expected);
return false;
}, gc_simplified);
}
// Check inserter (if applicable)
test_inserter
<
@ -217,7 +248,7 @@ void test_geometry(std::string const& wkt,
bg::correct_closure(geometry);
bg::correct_closure(expected);
boost::variant<Geometry> v(geometry);
typename boost_variant_type<Geometry>::type v(geometry);
BOOST_CONCEPT_ASSERT( (bg::concepts::SimplifyStrategy<Strategy,
typename bg::point_type<Geometry>::type>) );