mirror of
https://github.com/boostorg/geometry.git
synced 2026-03-05 02:52:12 +00:00
[envelope] Add separate strategies for linestrings and rings.
This commit is contained in:
@@ -5,8 +5,8 @@
|
||||
// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
|
||||
// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
|
||||
|
||||
// This file was modified by Oracle on 2013-2020.
|
||||
// Modifications copyright (c) 2013-2020, Oracle and/or its affiliates.
|
||||
// This file was modified by Oracle on 2013-2021.
|
||||
// Modifications copyright (c) 2013-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
|
||||
@@ -33,7 +33,6 @@
|
||||
#include <boost/geometry/algorithms/detail/envelope/segment.hpp>
|
||||
#include <boost/geometry/algorithms/detail/normalize.hpp>
|
||||
#include <boost/geometry/algorithms/dispatch/disjoint.hpp>
|
||||
#include <boost/geometry/algorithms/envelope.hpp>
|
||||
|
||||
#include <boost/geometry/formulas/vertex_longitude.hpp>
|
||||
|
||||
|
||||
@@ -39,6 +39,11 @@ struct envelope_polygon
|
||||
|
||||
if (geometry::is_empty(ext_ring))
|
||||
{
|
||||
// TODO: In spherical and geographic this is ambiguous. A hole technically is a ring
|
||||
// defining the outside so the envelope would cover more than half of the globe.
|
||||
// So depending on what we want we could consider reversing holes before passing them
|
||||
// below.
|
||||
|
||||
// use dummy multi polygon to get the strategy because there is no multi ring concept
|
||||
using strategy_t = decltype(strategy.envelope(detail::dummy_multi_polygon(),
|
||||
detail::dummy_box()));
|
||||
|
||||
@@ -76,16 +76,25 @@ public:
|
||||
>(base_t::m_spheroid);
|
||||
}
|
||||
|
||||
template <typename Geometry, typename Box>
|
||||
auto envelope(Geometry const&, Box const&,
|
||||
util::enable_if_linestring_t<Geometry> * = nullptr) const
|
||||
{
|
||||
return strategy::envelope::geographic_linestring
|
||||
<
|
||||
FormulaPolicy, Spheroid, CalculationType
|
||||
>(base_t::m_spheroid);
|
||||
}
|
||||
|
||||
template <typename Geometry, typename Box>
|
||||
auto envelope(Geometry const&, Box const&,
|
||||
std::enable_if_t
|
||||
<
|
||||
util::is_linestring<Geometry>::value
|
||||
|| util::is_ring<Geometry>::value
|
||||
util::is_ring<Geometry>::value
|
||||
|| util::is_polygon<Geometry>::value
|
||||
> * = nullptr) const
|
||||
{
|
||||
return strategy::envelope::geographic_range
|
||||
return strategy::envelope::geographic_ring
|
||||
<
|
||||
FormulaPolicy, Spheroid, CalculationType
|
||||
>(base_t::m_spheroid);
|
||||
|
||||
@@ -74,16 +74,22 @@ struct spherical
|
||||
return strategy::envelope::spherical_segment<CalculationType>();
|
||||
}
|
||||
|
||||
template <typename Geometry, typename Box>
|
||||
static auto envelope(Geometry const&, Box const&,
|
||||
util::enable_if_linestring_t<Geometry> * = nullptr)
|
||||
{
|
||||
return strategy::envelope::spherical_linestring<CalculationType>();
|
||||
}
|
||||
|
||||
template <typename Geometry, typename Box>
|
||||
static auto envelope(Geometry const&, Box const&,
|
||||
std::enable_if_t
|
||||
<
|
||||
util::is_linestring<Geometry>::value
|
||||
|| util::is_ring<Geometry>::value
|
||||
util::is_ring<Geometry>::value
|
||||
|| util::is_polygon<Geometry>::value
|
||||
> * = nullptr)
|
||||
{
|
||||
return strategy::envelope::spherical_range<CalculationType>();
|
||||
return strategy::envelope::spherical_ring<CalculationType>();
|
||||
}
|
||||
|
||||
template <typename Geometry, typename Box>
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <type_traits>
|
||||
|
||||
#include <boost/geometry/algorithms/detail/distance/segment_to_box.hpp>
|
||||
#include <boost/geometry/algorithms/envelope.hpp>
|
||||
|
||||
#include <boost/geometry/strategies/distance.hpp>
|
||||
#include <boost/geometry/strategies/normalize.hpp>
|
||||
|
||||
@@ -14,44 +14,92 @@
|
||||
#include <boost/geometry/strategy/geographic/expand_segment.hpp>
|
||||
#include <boost/geometry/strategy/spherical/envelope_range.hpp>
|
||||
|
||||
// TEMP - get rid of this dependency
|
||||
#include <boost/geometry/strategies/geographic/point_in_poly_winding.hpp>
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
namespace strategy { namespace envelope
|
||||
{
|
||||
|
||||
// TODO: divide into geographic_linestring and geographic_ring
|
||||
|
||||
template
|
||||
<
|
||||
typename FormulaPolicy = strategy::andoyer,
|
||||
typename Spheroid = geometry::srs::spheroid<double>,
|
||||
typename CalculationType = void
|
||||
>
|
||||
class geographic_range
|
||||
class geographic_linestring
|
||||
{
|
||||
public:
|
||||
using model_type = Spheroid;
|
||||
|
||||
geographic_range()
|
||||
geographic_linestring()
|
||||
: m_spheroid()
|
||||
{}
|
||||
|
||||
explicit geographic_range(Spheroid const& spheroid)
|
||||
explicit geographic_linestring(Spheroid const& spheroid)
|
||||
: m_spheroid(spheroid)
|
||||
{}
|
||||
|
||||
template <typename Range, typename Box>
|
||||
void apply(Range const& range, Box& mbr) const
|
||||
{
|
||||
detail::spheroidal_range(range, mbr,
|
||||
envelope::geographic_segment
|
||||
detail::spheroidal_linestring(range, mbr,
|
||||
envelope::geographic_segment
|
||||
<
|
||||
FormulaPolicy, Spheroid, CalculationType
|
||||
>(m_spheroid),
|
||||
expand::geographic_segment
|
||||
<
|
||||
FormulaPolicy, Spheroid, CalculationType
|
||||
>(m_spheroid));
|
||||
}
|
||||
|
||||
Spheroid model() const
|
||||
{
|
||||
return m_spheroid;
|
||||
}
|
||||
|
||||
private:
|
||||
Spheroid m_spheroid;
|
||||
};
|
||||
|
||||
template
|
||||
<
|
||||
typename FormulaPolicy = strategy::andoyer,
|
||||
typename Spheroid = geometry::srs::spheroid<double>,
|
||||
typename CalculationType = void
|
||||
>
|
||||
class geographic_ring
|
||||
{
|
||||
public:
|
||||
using model_type = Spheroid;
|
||||
|
||||
geographic_ring()
|
||||
: m_spheroid()
|
||||
{}
|
||||
|
||||
explicit geographic_ring(Spheroid const& spheroid)
|
||||
: m_spheroid(spheroid)
|
||||
{}
|
||||
|
||||
template <typename Range, typename Box>
|
||||
void apply(Range const& range, Box& mbr) const
|
||||
{
|
||||
detail::spheroidal_ring(range, mbr,
|
||||
envelope::geographic_segment
|
||||
<
|
||||
FormulaPolicy, Spheroid, CalculationType
|
||||
>(m_spheroid),
|
||||
expand::geographic_segment
|
||||
expand::geographic_segment
|
||||
<
|
||||
FormulaPolicy, Spheroid, CalculationType
|
||||
>(m_spheroid),
|
||||
within::geographic_winding
|
||||
<
|
||||
void, void,
|
||||
FormulaPolicy, Spheroid, CalculationType
|
||||
>(m_spheroid));
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#ifndef BOOST_GEOMETRY_STRATEGY_SPHERICAL_ENVELOPE_RANGE_HPP
|
||||
#define BOOST_GEOMETRY_STRATEGY_SPHERICAL_ENVELOPE_RANGE_HPP
|
||||
|
||||
#include <boost/geometry/algorithms/assign.hpp>
|
||||
#include <boost/geometry/algorithms/detail/envelope/initialize.hpp>
|
||||
#include <boost/geometry/geometries/segment.hpp>
|
||||
#include <boost/geometry/strategy/spherical/envelope_point.hpp>
|
||||
@@ -17,6 +18,11 @@
|
||||
#include <boost/geometry/strategy/spherical/expand_segment.hpp>
|
||||
#include <boost/geometry/views/closeable_view.hpp>
|
||||
|
||||
// TEMP - get rid of these dependencies
|
||||
#include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp>
|
||||
#include <boost/geometry/strategies/spherical/point_in_poly_winding.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
@@ -28,14 +34,12 @@ namespace detail
|
||||
{
|
||||
|
||||
template <typename Range, typename Box, typename EnvelopeStrategy, typename ExpandStrategy>
|
||||
inline void spheroidal_range(Range const& range, Box& mbr,
|
||||
EnvelopeStrategy const& envelope_strategy,
|
||||
ExpandStrategy const& expand_strategy)
|
||||
inline void spheroidal_linestring(Range const& range, Box& mbr,
|
||||
EnvelopeStrategy const& envelope_strategy,
|
||||
ExpandStrategy const& expand_strategy)
|
||||
{
|
||||
geometry::detail::closed_view<Range const> closed_range(range);
|
||||
|
||||
auto it = boost::begin(closed_range);
|
||||
auto const end = boost::end(closed_range);
|
||||
auto it = boost::begin(range);
|
||||
auto const end = boost::end(range);
|
||||
if (it == end)
|
||||
{
|
||||
// initialize box (assign inverse)
|
||||
@@ -68,21 +72,125 @@ inline void spheroidal_range(Range const& range, Box& mbr,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <typename Ring, typename WithinStrategy>
|
||||
inline bool pole_within(bool north_pole, Ring const& ring, WithinStrategy const& within_strategy)
|
||||
{
|
||||
if (boost::size(ring) < core_detail::closure::minimum_ring_size
|
||||
<
|
||||
geometry::closure<Ring>::value
|
||||
>::value)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
using point_t = typename geometry::point_type<Ring>::type;
|
||||
using coord_t = typename geometry::coordinate_type<point_t>::type;
|
||||
using units_t = typename geometry::detail::cs_angular_units<point_t>::type;
|
||||
using constants_t = math::detail::constants_on_spheroid<coord_t, units_t>;
|
||||
point_t point;
|
||||
geometry::assign_zero(point);
|
||||
if (north_pole)
|
||||
{
|
||||
geometry::set<1>(point, constants_t::max_latitude());
|
||||
}
|
||||
else
|
||||
{
|
||||
geometry::set<1>(point, constants_t::min_latitude());
|
||||
}
|
||||
geometry::detail::closed_clockwise_view<Ring const> view(ring);
|
||||
return geometry::detail::within::point_in_range(point, view, within_strategy) > 0;
|
||||
}
|
||||
|
||||
template <typename Range, typename Box, typename EnvelopeStrategy, typename ExpandStrategy, typename WithinStrategy>
|
||||
inline void spheroidal_ring(Range const& range, Box& mbr,
|
||||
EnvelopeStrategy const& envelope_strategy,
|
||||
ExpandStrategy const& expand_strategy,
|
||||
WithinStrategy const& within_strategy)
|
||||
{
|
||||
geometry::detail::closed_view<Range const> closed_range(range);
|
||||
|
||||
spheroidal_linestring(closed_range, mbr, envelope_strategy, expand_strategy);
|
||||
|
||||
using coord_t = typename geometry::coordinate_type<Box>::type;
|
||||
using point_t = typename geometry::point_type<Box>::type;
|
||||
using units_t = typename geometry::detail::cs_angular_units<point_t>::type;
|
||||
using constants_t = math::detail::constants_on_spheroid<coord_t, units_t>;
|
||||
coord_t const two_pi = constants_t::period();
|
||||
coord_t const lon_min = geometry::get<0, 0>(mbr);
|
||||
coord_t const lon_max = geometry::get<1, 0>(mbr);
|
||||
// If box covers the whole longitude range it is possible that the ring contains
|
||||
// one of the poles.
|
||||
// TODO: Technically it is possible that a reversed ring may cover more than
|
||||
// half of the globe and mbr of it's linear ring may be small and not cover the
|
||||
// longitude range.
|
||||
if (lon_max - lon_min >= two_pi)
|
||||
{
|
||||
coord_t const lat_n_pole = constants_t::max_latitude();
|
||||
coord_t const lat_s_pole = constants_t::min_latitude();
|
||||
coord_t lat_min = geometry::get<0, 1>(mbr);
|
||||
coord_t lat_max = geometry::get<1, 1>(mbr);
|
||||
// Normalize box latitudes, just in case
|
||||
if (math::equals(lat_min, lat_s_pole))
|
||||
{
|
||||
lat_min = lat_s_pole;
|
||||
}
|
||||
if (math::equals(lat_max, lat_n_pole))
|
||||
{
|
||||
lat_max = lat_n_pole;
|
||||
}
|
||||
|
||||
// TODO - implement something simpler than within strategy because here
|
||||
// we know that neither min nor max is a pole so there is no segment which
|
||||
// contains a pole, no endpoint, no vertex at pole, there are no antipodal
|
||||
// points. So many special cases can be ignored.
|
||||
if (lat_max < lat_n_pole)
|
||||
{
|
||||
if (pole_within(true, range, within_strategy))
|
||||
{
|
||||
lat_max = lat_n_pole;
|
||||
}
|
||||
}
|
||||
if (lat_min > lat_s_pole)
|
||||
{
|
||||
if (pole_within(false, range, within_strategy))
|
||||
{
|
||||
lat_min = lat_s_pole;
|
||||
}
|
||||
}
|
||||
|
||||
geometry::set<0, 1>(mbr, lat_min);
|
||||
geometry::set<1, 1>(mbr, lat_max);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
// TODO: divide into spherical_linestring and spherical_ring
|
||||
|
||||
template <typename CalculationType = void>
|
||||
class spherical_range
|
||||
class spherical_linestring
|
||||
{
|
||||
public:
|
||||
template <typename Range, typename Box>
|
||||
static inline void apply(Range const& range, Box& mbr)
|
||||
{
|
||||
detail::spheroidal_range(range, mbr,
|
||||
envelope::spherical_segment<CalculationType>(),
|
||||
expand::spherical_segment<CalculationType>());
|
||||
detail::spheroidal_linestring(range, mbr,
|
||||
envelope::spherical_segment<CalculationType>(),
|
||||
expand::spherical_segment<CalculationType>());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename CalculationType = void>
|
||||
class spherical_ring
|
||||
{
|
||||
public:
|
||||
template <typename Range, typename Box>
|
||||
static inline void apply(Range const& range, Box& mbr)
|
||||
{
|
||||
detail::spheroidal_ring(range, mbr,
|
||||
envelope::spherical_segment<CalculationType>(),
|
||||
expand::spherical_segment<CalculationType>(),
|
||||
within::spherical_winding<void, void, CalculationType>());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user