[simplify] Correctly propagate strategies to area() and perimeter().

Also made the algorithm more robust by checking the iterator before
using it.
This commit is contained in:
Adam Wulkiewicz
2021-03-03 01:15:12 +01:00
parent 3620e0aada
commit cb03829dc1
4 changed files with 93 additions and 13 deletions

View File

@@ -120,8 +120,8 @@ class douglas_peucker
PSDistanceStrategy const& ps_distance_strategy)
{
typedef typename std::iterator_traits<Iterator>::value_type::point_type point_type;
using distance_type = decltype(ps_distance_strategy.apply(
std::declval<point_type>(), std::declval<point_type>(), std::declval<point_type>()));
typedef decltype(ps_distance_strategy.apply(std::declval<point_type>(),
std::declval<point_type>(), std::declval<point_type>())) distance_type;
std::size_t size = end - begin;
@@ -153,7 +153,7 @@ class douglas_peucker
// Find most far point, compare to the current segment
//geometry::segment<Point const> s(begin->p, last->p);
distance_type md(-1.0); // any value < 0
Iterator candidate;
Iterator candidate = end;
for (Iterator it = begin + 1; it != last; ++it)
{
distance_type dist = ps_distance_strategy.apply(*(it->p), *(begin->p), *(last->p));
@@ -174,7 +174,7 @@ class douglas_peucker
// If a point is found, set the include flag
// and handle segments in between recursively
if (max_dist < md)
if (max_dist < md && candidate != end)
{
#ifdef BOOST_GEOMETRY_DEBUG_DOUGLAS_PEUCKER
std::cout << "use " << dsv(candidate->p) << std::endl;
@@ -411,10 +411,9 @@ public :
return;
}
// TODO: use calculate_point_order
// TODO: pass strategies
// TODO: instead of area() use calculate_point_order() ?
int const input_sign = area_sign(geometry::area(ring));
int const input_sign = area_sign(geometry::area(ring, strategies));
std::set<std::size_t> visited_indexes;
@@ -464,12 +463,11 @@ public :
simplify_range<0>::apply(rotated, out, max_distance, impl, strategies);
// TODO: use calculate_point_order
// TODO: pass strategies
// TODO: instead of area() use calculate_point_order() ?
// Verify that what was positive, stays positive (or goes to 0)
// and what was negative stays negative (or goes to 0)
int const output_sign = area_sign(geometry::area(out));
int const output_sign = area_sign(geometry::area(out, strategies));
if (output_sign == input_sign)
{
// Result is considered as satisfactory (usually this is the
@@ -482,10 +480,8 @@ public :
// when another starting point is used
geometry::clear(out);
// TODO: pass strategies
if (iteration == 0
&& geometry::perimeter(ring) < 3 * max_distance)
&& geometry::perimeter(ring, strategies) < 3 * max_distance)
{
// Check if it is useful to iterate. A minimal triangle has a
// perimeter of a bit more than 3 times the simplify distance

View File

@@ -19,6 +19,8 @@
#include <boost/geometry/strategies/detail.hpp>
#include <boost/geometry/strategies/simplify/services.hpp>
#include <boost/geometry/strategy/cartesian/area.hpp>
#include <boost/geometry/util/type_traits.hpp>
@@ -32,6 +34,26 @@ template <typename CalculationType = void>
struct cartesian
: public strategies::detail::cartesian_base
{
// TODO: Replace this if calculate_point_order() is used in simplify
template <typename Geometry>
static auto area(Geometry const&)
{
return strategy::area::cartesian<CalculationType>();
}
// For perimeter()
template <typename Geometry1, typename Geometry2>
static auto distance(Geometry1 const&, Geometry2 const&,
std::enable_if_t
<
util::is_pointlike<Geometry1>::value
&& util::is_pointlike<Geometry2>::value
> * = nullptr)
{
return strategy::distance::pythagoras<CalculationType>();
}
// For douglas_peucker
template <typename Geometry1, typename Geometry2>
static auto distance(Geometry1 const&, Geometry2 const&,
std::enable_if_t
@@ -51,6 +73,7 @@ struct cartesian
>();
}
// For equals()
template <typename Geometry1, typename Geometry2>
static auto relate(Geometry1 const&, Geometry2 const&,
std::enable_if_t

View File

@@ -18,6 +18,8 @@
#include <boost/geometry/strategies/geographic/distance_cross_track.hpp>
#include <boost/geometry/strategies/spherical/point_in_point.hpp>
#include <boost/geometry/strategy/geographic/area.hpp>
namespace boost { namespace geometry
{
@@ -43,6 +45,35 @@ public:
: base_t(spheroid)
{}
// TODO: Replace this if calculate_point_order() is used in simplify
template <typename Geometry>
auto area(Geometry const&) const
{
return strategy::area::geographic
<
FormulaPolicy,
strategy::default_order<FormulaPolicy>::value,
Spheroid,
CalculationType
>(base_t::m_spheroid);
}
// For perimeter()
template <typename Geometry1, typename Geometry2>
auto distance(Geometry1 const&, Geometry2 const&,
std::enable_if_t
<
util::is_pointlike<Geometry1>::value
&& util::is_pointlike<Geometry2>::value
> * = nullptr) const
{
return strategy::distance::geographic
<
FormulaPolicy, Spheroid, CalculationType
>(base_t::m_spheroid);
}
// For douglas_peucker
template <typename Geometry1, typename Geometry2>
auto distance(Geometry1 const&, Geometry2 const&,
std::enable_if_t
@@ -61,6 +92,7 @@ public:
>(base_t::m_spheroid);
}
// For equals()
template <typename Geometry1, typename Geometry2>
static auto relate(Geometry1 const&, Geometry2 const&,
std::enable_if_t

View File

@@ -19,6 +19,8 @@
#include <boost/geometry/strategies/spherical/distance_cross_track.hpp>
#include <boost/geometry/strategies/spherical/point_in_point.hpp>
#include <boost/geometry/strategy/spherical/area.hpp>
namespace boost { namespace geometry
{
@@ -44,6 +46,32 @@ public:
: base_t(radius_or_sphere)
{}
// TODO: Replace this if calculate_point_order() is used in simplify
template <typename Geometry>
auto area(Geometry const&) const
{
return strategy::area::spherical
<
typename base_t::radius_type, CalculationType
>(base_t::radius());
}
// For perimeter()
template <typename Geometry1, typename Geometry2>
auto distance(Geometry1 const&, Geometry2 const&,
std::enable_if_t
<
util::is_pointlike<Geometry1>::value
&& util::is_pointlike<Geometry2>::value
> * = nullptr) const
{
return strategy::distance::haversine
<
typename base_t::radius_type, CalculationType
>(base_t::radius());
}
// For douglas_peucker
template <typename Geometry1, typename Geometry2>
auto distance(Geometry1 const&, Geometry2 const&,
std::enable_if_t
@@ -63,6 +91,7 @@ public:
>(base_t::radius());
}
// For equals()
template <typename Geometry1, typename Geometry2>
static auto relate(Geometry1 const&, Geometry2 const&,
std::enable_if_t