[simplify] Allow different input and output geometries

Update comments
This commit is contained in:
Adam Wulkiewicz 2022-06-25 00:37:22 +02:00
parent 6d57aedf7f
commit 6a6dba760a

View File

@ -98,10 +98,8 @@ struct douglas_peucker_point
\brief Implements the simplify algorithm.
\details The douglas_peucker policy simplifies a linestring, ring or
vector of points using the well-known Douglas-Peucker algorithm.
\tparam Point the point type
\tparam PointDistanceStrategy point-segment distance strategy to be used
\note This strategy uses itself a point-segment-distance strategy which
can be specified
\note This strategy uses itself a point-segment potentially comparable
distance strategy
\author Barend and Maarten, 1995/1996
\author Barend, revised for Generic Geometry Library, 2008
*/
@ -417,8 +415,12 @@ private :
}
public :
template <typename Ring, typename Distance, typename Impl, typename Strategies>
static inline void apply(Ring const& ring, Ring& out, Distance const& max_distance,
template
<
typename RingIn, typename RingOut,
typename Distance, typename Impl, typename Strategies
>
static inline void apply(RingIn const& ring, RingOut& out, Distance const& max_distance,
Impl const& impl, Strategies const& strategies)
{
std::size_t const size = boost::size(ring);
@ -427,7 +429,10 @@ public :
return;
}
bool const is_closed = closure<Ring>::value == closed;
bool const is_closed_in = geometry::closure<RingIn>::value == closed;
bool const is_closed_out = geometry::closure<RingOut>::value == closed;
bool const is_clockwise_in = geometry::point_order<RingIn>::value == clockwise;
bool const is_clockwise_out = geometry::point_order<RingOut>::value == clockwise;
// TODO: instead of area() use calculate_point_order() ?
@ -438,7 +443,7 @@ public :
// Rotate it into a copied vector
// (vector, because source type might not support rotation)
// (duplicate end point will be simplified away)
typedef typename geometry::point_type<Ring>::type point_type;
typedef typename geometry::point_type<RingIn>::type point_type;
std::vector<point_type> rotated;
rotated.reserve(size + 1); // 1 because open rings are closed
@ -477,7 +482,7 @@ public :
// Do not duplicate the closing point
auto rot_end = boost::end(ring);
std::size_t rot_index = index;
if (is_closed && size > 1)
if (is_closed_in && size > 1)
{
--rot_end;
if (rot_index == size - 1) { rot_index = 0; }
@ -492,7 +497,7 @@ public :
simplify_range<0>::apply(rotated, out, max_distance, impl, strategies);
// Open output if needed
if (! is_closed && boost::size(out) > 1)
if (! is_closed_out && boost::size(out) > 1)
{
range::pop_back(out);
}
@ -526,6 +531,11 @@ public :
visited_indexes.insert(index);
rotated.clear();
}
if (BOOST_GEOMETRY_CONDITION(is_clockwise_in != is_clockwise_out))
{
std::reverse(boost::begin(out), boost::end(out));
}
}
};
@ -581,8 +591,12 @@ private:
}
public:
template <typename Polygon, typename Distance, typename Impl, typename Strategies>
static inline void apply(Polygon const& poly_in, Polygon& poly_out,
template
<
typename PolygonIn, typename PolygonOut,
typename Distance, typename Impl, typename Strategies
>
static inline void apply(PolygonIn const& poly_in, PolygonOut& poly_out,
Distance const& max_distance,
Impl const& impl, Strategies const& strategies)
{
@ -601,17 +615,20 @@ public:
template<typename Policy>
struct simplify_multi
{
template <typename MultiGeometry, typename Distance, typename Impl, typename Strategies>
static inline void apply(MultiGeometry const& multi, MultiGeometry& out,
template
<
typename MultiGeometryIn, typename MultiGeometryOut,
typename Distance, typename Impl, typename Strategies
>
static inline void apply(MultiGeometryIn const& multi, MultiGeometryOut& out,
Distance const& max_distance,
Impl const& impl, Strategies const& strategies)
{
range::clear(out);
typedef typename boost::range_value<MultiGeometry>::type single_type;
using single_type = typename boost::range_value<MultiGeometryOut>::type;
for (typename boost::range_iterator<MultiGeometry const>::type
it = boost::begin(multi); it != boost::end(multi); ++it)
for (auto it = boost::begin(multi); it != boost::end(multi); ++it)
{
single_type single_out;
Policy::apply(*it, single_out, max_distance, impl, strategies);
@ -624,6 +641,35 @@ struct simplify_multi
};
template <typename Geometry>
struct has_same_tag_as
{
template <typename OtherGeometry>
struct pred
: std::is_same
<
typename geometry::tag<Geometry>::type,
typename geometry::tag<OtherGeometry>::type
>
{};
};
template <typename StaticGeometryIn, typename DynamicGeometryOut>
struct static_geometry_type
{
using type = typename util::sequence_find_if
<
typename traits::geometry_types<DynamicGeometryOut>::type,
detail::simplify::has_same_tag_as<StaticGeometryIn>::pred
>::type;
BOOST_GEOMETRY_STATIC_ASSERT(
(! std::is_void<type>::value),
"Unable to find corresponding geometry in GeometryOut",
StaticGeometryIn, DynamicGeometryOut);
};
}} // namespace detail::simplify
#endif // DOXYGEN_NO_DETAIL
@ -634,50 +680,66 @@ namespace dispatch
template
<
typename Geometry,
typename Tag = typename tag<Geometry>::type
typename GeometryIn,
typename GeometryOut,
typename TagIn = typename tag<GeometryIn>::type,
typename TagOut = typename tag<GeometryOut>::type
>
struct simplify: not_implemented<Tag>
struct simplify: not_implemented<TagIn, TagOut>
{};
template <typename Point>
struct simplify<Point, point_tag>
template <typename PointIn, typename PointOut>
struct simplify<PointIn, PointOut, point_tag, point_tag>
{
template <typename Distance, typename Impl, typename Strategy>
static inline void apply(Point const& point, Point& out, Distance const& ,
static inline void apply(PointIn const& point, PointOut& out, Distance const& ,
Impl const& , Strategy const& )
{
geometry::convert(point, out);
}
};
template <typename Segment>
struct simplify<Segment, segment_tag>
template <typename SegmentIn, typename SegmentOut>
struct simplify<SegmentIn, SegmentOut, segment_tag, segment_tag>
: detail::simplify::simplify_copy_assign
{};
template <typename Box>
struct simplify<Box, box_tag>
template <typename BoxIn, typename BoxOut>
struct simplify<BoxIn, BoxOut, box_tag, 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>
template <typename LinestringIn, typename LinestringOut>
struct simplify<LinestringIn, LinestringOut, linestring_tag, linestring_tag>
: detail::simplify::simplify_range<2>
{};
template <typename Ring>
struct simplify<Ring, ring_tag>
template <typename RingIn, typename RingOut>
struct simplify<RingIn, RingOut, ring_tag, ring_tag>
: detail::simplify::simplify_ring
{};
template <typename Polygon>
struct simplify<Polygon, polygon_tag>
template <typename PolygonIn, typename PolygonOut>
struct simplify<PolygonIn, PolygonOut, polygon_tag, polygon_tag>
: detail::simplify::simplify_polygon
{};
template <typename MultiPointIn, typename MultiPointOut>
struct simplify<MultiPointIn, MultiPointOut, multi_point_tag, multi_point_tag>
: detail::simplify::simplify_copy
{};
template <typename MultiLinestringIn, typename MultiLinestringOut>
struct simplify<MultiLinestringIn, MultiLinestringOut, multi_linestring_tag, multi_linestring_tag>
: detail::simplify::simplify_multi<detail::simplify::simplify_range<2> >
{};
template <typename MultiPolygonIn, typename MultiPolygonOut>
struct simplify<MultiPolygonIn, MultiPolygonOut, multi_polygon_tag, multi_polygon_tag>
: detail::simplify::simplify_multi<detail::simplify::simplify_polygon>
{};
template
<
@ -698,23 +760,6 @@ struct simplify_insert<Ring, ring_tag>
: detail::simplify::simplify_range_insert
{};
template <typename MultiPoint>
struct simplify<MultiPoint, multi_point_tag>
: detail::simplify::simplify_copy
{};
template <typename MultiLinestring>
struct simplify<MultiLinestring, multi_linestring_tag>
: detail::simplify::simplify_multi<detail::simplify::simplify_range<2> >
{};
template <typename MultiPolygon>
struct simplify<MultiPolygon, multi_polygon_tag>
: detail::simplify::simplify_multi<detail::simplify::simplify_polygon>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
@ -730,15 +775,15 @@ template
>
struct simplify
{
template <typename Geometry, typename Distance>
static inline void apply(Geometry const& geometry,
Geometry& out,
template <typename GeometryIn, typename GeometryOut, typename Distance>
static inline void apply(GeometryIn const& geometry,
GeometryOut& out,
Distance const& max_distance,
Strategies const& strategies)
{
dispatch::simplify
<
Geometry
GeometryIn, GeometryOut
>::apply(geometry, out, max_distance,
detail::simplify::douglas_peucker(),
strategies);
@ -748,9 +793,9 @@ struct simplify
template <typename Strategy>
struct simplify<Strategy, false>
{
template <typename Geometry, typename Distance>
static inline void apply(Geometry const& geometry,
Geometry& out,
template <typename GeometryIn, typename GeometryOut, typename Distance>
static inline void apply(GeometryIn const& geometry,
GeometryOut& out,
Distance const& max_distance,
Strategy const& strategy)
{
@ -767,15 +812,23 @@ struct simplify<Strategy, false>
template <>
struct simplify<default_strategy, false>
{
template <typename Geometry, typename Distance>
static inline void apply(Geometry const& geometry,
Geometry& out,
template <typename GeometryIn, typename GeometryOut, typename Distance>
static inline void apply(GeometryIn const& geometry,
GeometryOut& out,
Distance const& max_distance,
default_strategy)
{
// NOTE: Alternatively take two geometry types in default_strategy
using cs_tag1_t = typename geometry::cs_tag<GeometryIn>::type;
using cs_tag2_t = typename geometry::cs_tag<GeometryOut>::type;
BOOST_GEOMETRY_STATIC_ASSERT(
(std::is_same<cs_tag1_t, cs_tag2_t>::value),
"Incompatible coordinate systems",
cs_tag1_t, cs_tag2_t);
typedef typename strategies::simplify::services::default_strategy
<
Geometry
GeometryIn
>::type strategy_type;
simplify
@ -852,12 +905,17 @@ struct simplify_insert<default_strategy, false>
namespace resolve_dynamic {
template <typename Geometry, typename Tag = typename tag<Geometry>::type>
template
<
typename GeometryIn, typename GeometryOut,
typename TagIn = typename tag<GeometryIn>::type,
typename TagOut = typename tag<GeometryOut>::type
>
struct simplify
{
template <typename Distance, typename Strategy>
static inline void apply(Geometry const& geometry,
Geometry& out,
static inline void apply(GeometryIn const& geometry,
GeometryOut& out,
Distance const& max_distance,
Strategy const& strategy)
{
@ -865,40 +923,44 @@ struct simplify
}
};
template <typename Geometry>
struct simplify<Geometry, dynamic_geometry_tag>
template <typename GeometryIn, typename GeometryOut>
struct simplify<GeometryIn, GeometryOut, dynamic_geometry_tag, dynamic_geometry_tag>
{
template <typename Distance, typename Strategy>
static inline void apply(Geometry const& geometry,
Geometry& out,
static inline void apply(GeometryIn const& geometry,
GeometryOut& out,
Distance const& max_distance,
Strategy const& strategy)
{
traits::visit<Geometry>::apply([&](auto const& g)
traits::visit<GeometryIn>::apply([&](auto const& g)
{
using geom_t = util::remove_cref_t<decltype(g)>;
geom_t o;
simplify<geom_t>::apply(g, o, max_distance, strategy);
using detail::simplify::static_geometry_type;
using geom_out_t = typename static_geometry_type<geom_t, GeometryOut>::type;
geom_out_t o;
simplify<geom_t, geom_out_t>::apply(g, o, max_distance, strategy);
out = std::move(o);
}, geometry);
}
};
template <typename Geometry>
struct simplify<Geometry, geometry_collection_tag>
template <typename GeometryIn, typename GeometryOut>
struct simplify<GeometryIn, GeometryOut, geometry_collection_tag, geometry_collection_tag>
{
template <typename Distance, typename Strategy>
static inline void apply(Geometry const& geometry,
Geometry& out,
static inline void apply(GeometryIn const& geometry,
GeometryOut& 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));
using detail::simplify::static_geometry_type;
using geom_out_t = typename static_geometry_type<geom_t, GeometryOut>::type;
geom_out_t o;
simplify<geom_t, geom_out_t>::apply(g, o, max_distance, strategy);
traits::emplace_back<GeometryOut>::apply(out, std::move(o));
return true;
}, geometry);
}
@ -911,6 +973,7 @@ struct simplify<Geometry, geometry_collection_tag>
\brief Simplify a geometry using a specified strategy
\ingroup simplify
\tparam Geometry \tparam_geometry
\tparam GeometryOut The output geometry
\tparam Distance A numerical distance measure
\tparam Strategy A type fulfilling a SimplifyStrategy concept
\param strategy A strategy to calculate simplification
@ -918,21 +981,22 @@ struct simplify<Geometry, geometry_collection_tag>
\param out output geometry, simplified version of the input geometry
\param max_distance distance (in units of input coordinates) of a vertex
to other segments to be removed
\param strategy simplify strategy to be used for simplification, might
include point-distance strategy
\param strategy simplify strategy to be used for simplification
\note The simplification is done with Douglas-Peucker algorithm
\image html svg_simplify_country.png "The image below presents the simplified country"
\qbk{distinguish,with strategy}
*/
template<typename Geometry, typename Distance, typename Strategy>
inline void simplify(Geometry const& geometry, Geometry& out,
template<typename Geometry, typename GeometryOut, typename Distance, typename Strategy>
inline void simplify(Geometry const& geometry, GeometryOut& out,
Distance const& max_distance, Strategy const& strategy)
{
concepts::check<Geometry>();
concepts::check<Geometry const>();
concepts::check<GeometryOut>();
geometry::clear(out);
resolve_dynamic::simplify<Geometry>::apply(geometry, out, max_distance, strategy);
resolve_dynamic::simplify<Geometry, GeometryOut>::apply(geometry, out, max_distance, strategy);
}
@ -942,21 +1006,22 @@ inline void simplify(Geometry const& geometry, Geometry& out,
\brief Simplify a geometry
\ingroup simplify
\tparam Geometry \tparam_geometry
\tparam GeometryOut The output geometry
\tparam Distance \tparam_numeric
\note This version of simplify simplifies a geometry using the default
strategy (Douglas Peucker),
\param geometry input geometry, to be simplified
\param out output geometry, simplified version of the input geometry
\param max_distance distance (in units of input coordinates) of a vertex
to other segments to be removed
\note The simplification is done with Douglas-Peucker algorithm
\qbk{[include reference/algorithms/simplify.qbk]}
*/
template<typename Geometry, typename Distance>
inline void simplify(Geometry const& geometry, Geometry& out,
template<typename Geometry, typename GeometryOut, typename Distance>
inline void simplify(Geometry const& geometry, GeometryOut& out,
Distance const& max_distance)
{
concepts::check<Geometry>();
concepts::check<Geometry const>();
concepts::check<GeometryOut>();
geometry::simplify(geometry, out, max_distance, default_strategy());
}
@ -976,8 +1041,7 @@ namespace detail { namespace simplify
\param out output iterator, outputs all simplified points
\param max_distance distance (in units of input coordinates) of a vertex
to other segments to be removed
\param strategy simplify strategy to be used for simplification,
might include point-distance strategy
\param strategy simplify strategy to be used for simplification
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/simplify.qbk]}