Merge pull request #405 from awulkiew/feature/area_strategy

Add missing propagation of area strategy in buffer, is_valid and overlay.
This commit is contained in:
Adam Wulkiewicz 2017-07-05 13:51:43 +02:00 committed by GitHub
commit a51a331df9
10 changed files with 205 additions and 92 deletions

View File

@ -5,6 +5,10 @@
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2017.
// Modifications copyright (c) 2017 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.
@ -61,7 +65,8 @@ namespace detail { namespace correct
template <typename Geometry>
struct correct_nop
{
static inline void apply(Geometry& )
template <typename Strategy>
static inline void apply(Geometry& , Strategy const& )
{}
};
@ -104,8 +109,8 @@ struct correct_box_loop<Box, DimensionCount, DimensionCount>
template <typename Box>
struct correct_box
{
static inline void apply(Box& box)
template <typename Strategy>
static inline void apply(Box& box, Strategy const& )
{
// Currently only for Cartesian coordinates
// (or spherical without crossing dateline)
@ -119,18 +124,12 @@ struct correct_box
// Close a ring, if not closed
template <typename Ring, typename Predicate>
template <typename Ring, template <typename> class Predicate>
struct correct_ring
{
typedef typename point_type<Ring>::type point_type;
typedef typename coordinate_type<Ring>::type coordinate_type;
typedef typename strategy::area::services::default_strategy
<
typename cs_tag<point_type>::type,
point_type
>::type strategy_type;
typedef detail::area::ring_area
<
order_as_direction<geometry::point_order<Ring>::value>::value,
@ -138,7 +137,8 @@ struct correct_ring
> ring_area_type;
static inline void apply(Ring& r)
template <typename Strategy>
static inline void apply(Ring& r, Strategy const& strategy)
{
// Check close-ness
if (boost::size(r) > 2)
@ -158,10 +158,10 @@ struct correct_ring
}
}
// Check area
Predicate predicate;
typedef typename default_area_result<Ring>::type area_result_type;
area_result_type const zero = area_result_type();
if (predicate(ring_area_type::apply(r, strategy_type()), zero))
typedef typename Strategy::return_type area_result_type;
Predicate<area_result_type> predicate;
area_result_type const zero = 0;
if (predicate(ring_area_type::apply(r, strategy), zero))
{
std::reverse(boost::begin(r), boost::end(r));
}
@ -174,15 +174,15 @@ template <typename Polygon>
struct correct_polygon
{
typedef typename ring_type<Polygon>::type ring_type;
typedef typename default_area_result<Polygon>::type area_result_type;
static inline void apply(Polygon& poly)
template <typename Strategy>
static inline void apply(Polygon& poly, Strategy const& strategy)
{
correct_ring
<
ring_type,
std::less<area_result_type>
>::apply(exterior_ring(poly));
std::less
>::apply(exterior_ring(poly), strategy);
typename interior_return_type<Polygon>::type
rings = interior_rings(poly);
@ -192,8 +192,8 @@ struct correct_polygon
correct_ring
<
ring_type,
std::greater<area_result_type>
>::apply(*it);
std::greater
>::apply(*it, strategy);
}
}
};
@ -237,7 +237,7 @@ struct correct<Ring, ring_tag>
: detail::correct::correct_ring
<
Ring,
std::less<typename default_area_result<Ring>::type>
std::less
>
{};
@ -281,29 +281,36 @@ namespace resolve_variant {
template <typename Geometry>
struct correct
{
static inline void apply(Geometry& geometry)
template <typename Strategy>
static inline void apply(Geometry& geometry, Strategy const& strategy)
{
concepts::check<Geometry const>();
dispatch::correct<Geometry>::apply(geometry);
dispatch::correct<Geometry>::apply(geometry, strategy);
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct correct<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
{
template <typename Strategy>
struct visitor: boost::static_visitor<void>
{
Strategy const& m_strategy;
visitor(Strategy const& strategy): m_strategy(strategy) {}
template <typename Geometry>
void operator()(Geometry& geometry) const
{
correct<Geometry>::apply(geometry);
correct<Geometry>::apply(geometry, m_strategy);
}
};
template <typename Strategy>
static inline void
apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry)
apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry, Strategy const& strategy)
{
boost::apply_visitor(visitor(), geometry);
boost::apply_visitor(visitor<Strategy>(strategy), geometry);
}
};
@ -325,7 +332,37 @@ struct correct<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
template <typename Geometry>
inline void correct(Geometry& geometry)
{
resolve_variant::correct<Geometry>::apply(geometry);
typedef typename point_type<Geometry>::type point_type;
typedef typename strategy::area::services::default_strategy
<
typename cs_tag<point_type>::type,
point_type
>::type strategy_type;
resolve_variant::correct<Geometry>::apply(geometry, strategy_type());
}
/*!
\brief Corrects a geometry
\details Corrects a geometry: all rings which are wrongly oriented with respect
to their expected orientation are reversed. To all rings which do not have a
closing point and are typed as they should have one, the first point is
appended. Also boxes can be corrected.
\ingroup correct
\tparam Geometry \tparam_geometry
\tparam Strategy \tparam_strategy{Area}
\param geometry \param_geometry which will be corrected if necessary
\param strategy \param_strategy{area}
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/correct.qbk]}
*/
template <typename Geometry, typename Strategy>
inline void correct(Geometry& geometry, Strategy const& strategy)
{
resolve_variant::correct<Geometry>::apply(geometry, strategy);
}
#if defined(_MSC_VER)

View File

@ -142,10 +142,20 @@ struct buffered_piece_collection
robust_point_type
>::type robust_comparable_radius_type;
typedef typename strategy::side::services::default_strategy
typedef typename IntersectionStrategy::side_strategy_type side_strategy_type;
typedef typename IntersectionStrategy::template area_strategy
<
typename cs_tag<point_type>::type
>::type side_strategy;
point_type
>::type area_strategy_type;
typedef typename IntersectionStrategy::template area_strategy
<
robust_point_type
>::type robust_area_strategy_type;
typedef typename area_strategy_type::return_type area_result_type;
typedef typename robust_area_strategy_type::return_type robust_area_result_type;
typedef typename geometry::rescale_policy_type
<
@ -306,7 +316,10 @@ struct buffered_piece_collection
cluster_type m_clusters;
IntersectionStrategy const& m_intersection_strategy;
IntersectionStrategy m_intersection_strategy;
side_strategy_type m_side_strategy;
area_strategy_type m_area_strategy;
robust_area_strategy_type m_robust_area_strategy;
RobustPolicy const& m_robust_policy;
struct redundant_turn
@ -321,6 +334,9 @@ struct buffered_piece_collection
RobustPolicy const& robust_policy)
: m_first_piece_index(-1)
, m_intersection_strategy(intersection_strategy)
, m_side_strategy(intersection_strategy.get_side_strategy())
, m_area_strategy(intersection_strategy.template get_area_strategy<point_type>())
, m_robust_area_strategy(intersection_strategy.template get_area_strategy<robust_point_type>())
, m_robust_policy(robust_policy)
{}
@ -699,7 +715,7 @@ struct buffered_piece_collection
++it)
{
piece& pc = *it;
if (geometry::area(pc.robust_ring) < 0)
if (geometry::area(pc.robust_ring, m_robust_area_strategy) < 0)
{
// Rings can be ccw:
// - in a concave piece
@ -1220,14 +1236,9 @@ struct buffered_piece_collection
inline void enrich()
{
typedef typename strategy::side::services::default_strategy
<
typename cs_tag<Ring>::type
>::type side_strategy_type;
enrich_intersection_points<false, false, overlay_buffer>(m_turns,
m_clusters, offsetted_rings, offsetted_rings,
m_robust_policy, side_strategy_type());
m_robust_policy, m_side_strategy);
}
// Discards all rings which do have not-OK intersection points only.
@ -1314,7 +1325,7 @@ struct buffered_piece_collection
buffered_ring<Ring>& ring = *it;
if (! ring.has_intersections()
&& boost::size(ring) > 0u
&& geometry::area(ring) < 0)
&& geometry::area(ring, m_area_strategy) < 0)
{
if (! point_coveredby_original(geometry::range::front(ring)))
{
@ -1391,7 +1402,7 @@ struct buffered_piece_collection
template <typename GeometryOutput, typename OutputIterator>
inline OutputIterator assign(OutputIterator out) const
{
typedef detail::overlay::ring_properties<point_type> properties;
typedef detail::overlay::ring_properties<point_type, area_result_type> properties;
std::map<ring_identifier, properties> selected;
@ -1407,7 +1418,7 @@ struct buffered_piece_collection
if (! it->has_intersections()
&& ! it->is_untouched_outside_original)
{
properties p = properties(*it);
properties p = properties(*it, m_area_strategy);
if (p.valid)
{
ring_identifier id(0, index, -1);
@ -1423,7 +1434,7 @@ struct buffered_piece_collection
it != boost::end(traversed_rings);
++it, ++index)
{
properties p = properties(*it);
properties p = properties(*it, m_area_strategy);
if (p.valid)
{
ring_identifier id(2, index, -1);

View File

@ -115,7 +115,10 @@ struct is_properly_oriented
geometry::closure<Ring>::value
> ring_area_type;
typedef typename default_area_result<Ring>::type area_result_type;
typedef typename Strategy::template area_strategy
<
point_type
>::type::return_type area_result_type;
typename ring_area_predicate
<

View File

@ -4,6 +4,10 @@
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2017.
// Modifications copyright (c) 2017 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.
@ -40,6 +44,18 @@ struct multi_modify
Policy::apply(*it);
}
}
template <typename Strategy>
static inline void apply(MultiGeometry& multi, Strategy const& strategy)
{
typedef typename boost::range_iterator<MultiGeometry>::type iterator_type;
for (iterator_type it = boost::begin(multi);
it != boost::end(multi);
++it)
{
Policy::apply(*it, strategy);
}
}
};

View File

@ -107,21 +107,19 @@ static inline bool within_selected_input(Item const& item2,
}
template <typename Point>
template <typename Point, typename AreaType>
struct ring_info_helper
{
typedef typename geometry::default_area_result<Point>::type area_type;
ring_identifier id;
area_type real_area;
area_type abs_area;
AreaType real_area;
AreaType abs_area;
model::box<Point> envelope;
inline ring_info_helper()
: real_area(0), abs_area(0)
{}
inline ring_info_helper(ring_identifier i, area_type a)
inline ring_info_helper(ring_identifier i, AreaType const& a)
: id(i), real_area(a), abs_area(geometry::math::abs(a))
{}
};
@ -234,11 +232,15 @@ inline void assign_parents(Geometry1 const& geometry1,
typedef typename RingMap::mapped_type ring_info_type;
typedef typename ring_info_type::point_type point_type;
typedef model::box<point_type> box_type;
typedef typename Strategy::template area_strategy
<
point_type
>::type::return_type area_result_type;
typedef typename RingMap::iterator map_iterator_type;
{
typedef ring_info_helper<point_type> helper;
typedef ring_info_helper<point_type, area_result_type> helper;
typedef std::vector<helper> vector_type;
typedef typename boost::range_iterator<vector_type const>::type vector_iterator_type;

View File

@ -197,7 +197,16 @@ inline OutputIterator return_if_one_input_is_empty(Geometry1 const& geometry1,
typename geometry::ring_type<GeometryOut>::type
> ring_container_type;
typedef ring_properties<typename geometry::point_type<Geometry1>::type> properties;
typedef typename geometry::point_type<Geometry1>::type point_type1;
typedef ring_properties
<
point_type1,
typename Strategy::template area_strategy
<
point_type1
>::type::return_type
> properties;
// Silence warning C4127: conditional expression is constant
#if defined(_MSC_VER)
@ -309,7 +318,7 @@ std::cout << "get turns" << std::endl;
#ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE
std::cout << "enrich" << std::endl;
#endif
typename Strategy::side_strategy_type side_strategy;
typename Strategy::side_strategy_type side_strategy = strategy.get_side_strategy();
cluster_type clusters;
geometry::enrich_intersection_points<Reverse1, Reverse2, OverlayType>(turns,
@ -341,10 +350,13 @@ std::cout << "traverse" << std::endl;
std::map<ring_identifier, ring_turn_info> turn_info_per_ring;
get_ring_turn_info<OverlayType>(turn_info_per_ring, turns, clusters);
typedef typename Strategy::template area_strategy<point_type>::type area_strategy_type;
typedef ring_properties
<
typename geometry::point_type<GeometryOut>::type
> properties;
<
point_type,
typename area_strategy_type::return_type
> properties;
// Select all rings which are NOT touched by any intersection point
std::map<ring_identifier, properties> selected_ring_properties;
@ -353,13 +365,15 @@ std::cout << "traverse" << std::endl;
// Add rings created during traversal
{
area_strategy_type const area_strategy = strategy.template get_area_strategy<point_type>();
ring_identifier id(2, 0, -1);
for (typename boost::range_iterator<ring_container_type>::type
it = boost::begin(rings);
it != boost::end(rings);
++it)
{
selected_ring_properties[id] = properties(*it);
selected_ring_properties[id] = properties(*it, area_strategy);
selected_ring_properties[id].reversed = ReverseOut;
id.multi_index++;
}

View File

@ -27,11 +27,11 @@ namespace boost { namespace geometry
namespace detail { namespace overlay
{
template <typename Point>
template <typename Point, typename AreaType>
struct ring_properties
{
typedef Point point_type;
typedef typename default_area_result<Point>::type area_type;
typedef AreaType area_type;
bool valid;
@ -56,13 +56,13 @@ struct ring_properties
, parent_area(-1)
{}
template <typename RingOrBox>
inline ring_properties(RingOrBox const& ring_or_box)
template <typename RingOrBox, typename AreaStrategy>
inline ring_properties(RingOrBox const& ring_or_box, AreaStrategy const& strategy)
: reversed(false)
, discarded(false)
, parent_area(-1)
{
this->area = geometry::area(ring_or_box);
this->area = geometry::area(ring_or_box, strategy);
valid = geometry::point_on_border(this->point, ring_or_box);
}

View File

@ -59,41 +59,45 @@ namespace dispatch
template <typename Box>
struct select_rings<box_tag, Box>
{
template <typename Geometry, typename RingPropertyMap>
template <typename Geometry, typename RingPropertyMap, typename AreaStrategy>
static inline void apply(Box const& box, Geometry const& ,
ring_identifier const& id, RingPropertyMap& ring_properties)
ring_identifier const& id, RingPropertyMap& ring_properties,
AreaStrategy const& strategy)
{
ring_properties[id] = typename RingPropertyMap::mapped_type(box);
ring_properties[id] = typename RingPropertyMap::mapped_type(box, strategy);
}
template <typename RingPropertyMap>
template <typename RingPropertyMap, typename AreaStrategy>
static inline void apply(Box const& box,
ring_identifier const& id, RingPropertyMap& ring_properties)
ring_identifier const& id, RingPropertyMap& ring_properties,
AreaStrategy const& strategy)
{
ring_properties[id] = typename RingPropertyMap::mapped_type(box);
ring_properties[id] = typename RingPropertyMap::mapped_type(box, strategy);
}
};
template <typename Ring>
struct select_rings<ring_tag, Ring>
{
template <typename Geometry, typename RingPropertyMap>
template <typename Geometry, typename RingPropertyMap, typename AreaStrategy>
static inline void apply(Ring const& ring, Geometry const& ,
ring_identifier const& id, RingPropertyMap& ring_properties)
ring_identifier const& id, RingPropertyMap& ring_properties,
AreaStrategy const& strategy)
{
if (boost::size(ring) > 0)
{
ring_properties[id] = typename RingPropertyMap::mapped_type(ring);
ring_properties[id] = typename RingPropertyMap::mapped_type(ring, strategy);
}
}
template <typename RingPropertyMap>
template <typename RingPropertyMap, typename AreaStrategy>
static inline void apply(Ring const& ring,
ring_identifier const& id, RingPropertyMap& ring_properties)
ring_identifier const& id, RingPropertyMap& ring_properties,
AreaStrategy const& strategy)
{
if (boost::size(ring) > 0)
{
ring_properties[id] = typename RingPropertyMap::mapped_type(ring);
ring_properties[id] = typename RingPropertyMap::mapped_type(ring, strategy);
}
}
};
@ -102,14 +106,15 @@ namespace dispatch
template <typename Polygon>
struct select_rings<polygon_tag, Polygon>
{
template <typename Geometry, typename RingPropertyMap>
template <typename Geometry, typename RingPropertyMap, typename AreaStrategy>
static inline void apply(Polygon const& polygon, Geometry const& geometry,
ring_identifier id, RingPropertyMap& ring_properties)
ring_identifier id, RingPropertyMap& ring_properties,
AreaStrategy const& strategy)
{
typedef typename geometry::ring_type<Polygon>::type ring_type;
typedef select_rings<ring_tag, ring_type> per_ring;
per_ring::apply(exterior_ring(polygon), geometry, id, ring_properties);
per_ring::apply(exterior_ring(polygon), geometry, id, ring_properties, strategy);
typename interior_return_type<Polygon const>::type
rings = interior_rings(polygon);
@ -117,18 +122,19 @@ namespace dispatch
it = boost::begin(rings); it != boost::end(rings); ++it)
{
id.ring_index++;
per_ring::apply(*it, geometry, id, ring_properties);
per_ring::apply(*it, geometry, id, ring_properties, strategy);
}
}
template <typename RingPropertyMap>
template <typename RingPropertyMap, typename AreaStrategy>
static inline void apply(Polygon const& polygon,
ring_identifier id, RingPropertyMap& ring_properties)
ring_identifier id, RingPropertyMap& ring_properties,
AreaStrategy const& strategy)
{
typedef typename geometry::ring_type<Polygon>::type ring_type;
typedef select_rings<ring_tag, ring_type> per_ring;
per_ring::apply(exterior_ring(polygon), id, ring_properties);
per_ring::apply(exterior_ring(polygon), id, ring_properties, strategy);
typename interior_return_type<Polygon const>::type
rings = interior_rings(polygon);
@ -136,7 +142,7 @@ namespace dispatch
it = boost::begin(rings); it != boost::end(rings); ++it)
{
id.ring_index++;
per_ring::apply(*it, id, ring_properties);
per_ring::apply(*it, id, ring_properties, strategy);
}
}
};
@ -144,9 +150,10 @@ namespace dispatch
template <typename Multi>
struct select_rings<multi_polygon_tag, Multi>
{
template <typename Geometry, typename RingPropertyMap>
template <typename Geometry, typename RingPropertyMap, typename AreaStrategy>
static inline void apply(Multi const& multi, Geometry const& geometry,
ring_identifier id, RingPropertyMap& ring_properties)
ring_identifier id, RingPropertyMap& ring_properties,
AreaStrategy const& strategy)
{
typedef typename boost::range_iterator
<
@ -159,7 +166,7 @@ namespace dispatch
for (iterator_type it = boost::begin(multi); it != boost::end(multi); ++it)
{
id.ring_index = -1;
per_polygon::apply(*it, geometry, id, ring_properties);
per_polygon::apply(*it, geometry, id, ring_properties, strategy);
id.multi_index++;
}
}
@ -311,12 +318,16 @@ inline void select_rings(Geometry1 const& geometry1, Geometry2 const& geometry2,
{
typedef typename geometry::tag<Geometry1>::type tag1;
typedef typename geometry::tag<Geometry2>::type tag2;
typedef typename geometry::point_type<Geometry1>::type point1_type;
typedef typename geometry::point_type<Geometry2>::type point2_type;
RingPropertyMap all_ring_properties;
dispatch::select_rings<tag1, Geometry1>::apply(geometry1, geometry2,
ring_identifier(0, -1, -1), all_ring_properties);
ring_identifier(0, -1, -1), all_ring_properties,
strategy.template get_area_strategy<point1_type>());
dispatch::select_rings<tag2, Geometry2>::apply(geometry2, geometry1,
ring_identifier(1, -1, -1), all_ring_properties);
ring_identifier(1, -1, -1), all_ring_properties,
strategy.template get_area_strategy<point2_type>());
update_ring_selection<OverlayType>(geometry1, geometry2, turn_info_per_ring,
all_ring_properties, selected_ring_properties,
@ -337,10 +348,12 @@ inline void select_rings(Geometry const& geometry,
Strategy const& strategy)
{
typedef typename geometry::tag<Geometry>::type tag;
typedef typename geometry::point_type<Geometry>::type point_type;
RingPropertyMap all_ring_properties;
dispatch::select_rings<tag, Geometry>::apply(geometry,
ring_identifier(0, -1, -1), all_ring_properties);
ring_identifier(0, -1, -1), all_ring_properties,
strategy.template get_area_strategy<point_type>());
update_ring_selection<OverlayType>(geometry, geometry, turn_info_per_ring,
all_ring_properties, selected_ring_properties,

View File

@ -226,7 +226,13 @@ struct dissolve_ring_or_polygon
std::map<ring_identifier, detail::overlay::ring_turn_info> map;
detail::overlay::get_ring_turn_info<overlay_dissolve>(map, turns, clusters);
typedef detail::overlay::ring_properties<typename geometry::point_type<Geometry>::type> properties;
typedef typename geometry::point_type<Geometry>::type point_type;
typedef typename Strategy::template area_strategy
<
point_type
>::type area_strategy_type;
typedef typename area_strategy_type::return_type area_result_type;
typedef detail::overlay::ring_properties<point_type, area_result_type> properties;
std::map<ring_identifier, properties> selected;
@ -234,13 +240,15 @@ struct dissolve_ring_or_polygon
// Add intersected rings
{
area_strategy_type const area_strategy = strategy.template get_area_strategy<point_type>();
ring_identifier id(2, 0, -1);
for (typename boost::range_iterator<std::vector<ring_type> const>::type
it = boost::begin(rings);
it != boost::end(rings);
++it)
{
selected[id] = properties(*it);
selected[id] = properties(*it, area_strategy);
id.multi_index++;
}
}

View File

@ -1,6 +1,11 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
//
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
//
// This file was modified by Oracle on 2017.
// Modifications copyright (c) 2017 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)
@ -36,7 +41,11 @@ template
void test_geometry(std::string const& wkt1, std::string const& wkt2,
RingIdVector const& expected_ids)
{
typedef bg::detail::overlay::ring_properties<typename bg::point_type<Geometry1>::type> properties;
typedef bg::detail::overlay::ring_properties
<
typename bg::point_type<Geometry1>::type,
double
> properties;
Geometry1 geometry1;
Geometry2 geometry2;