[strategies] Support non-cartesian CSes in box_in_box strategy.

This commit is contained in:
Adam Wulkiewicz
2016-03-08 04:38:48 +01:00
parent 183d32f2e3
commit d04acacc74

View File

@@ -25,6 +25,7 @@
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/strategies/covered_by.hpp>
#include <boost/geometry/strategies/within.hpp>
#include <boost/geometry/util/normalize_spheroidal_coordinates.hpp>
namespace boost { namespace geometry { namespace strategy
@@ -34,6 +35,8 @@ namespace boost { namespace geometry { namespace strategy
namespace within
{
template <typename Geometry, std::size_t Dimension, typename CSTag>
struct box_within_range
{
template <typename BoxContainedValue, typename BoxContainingValue>
@@ -48,6 +51,7 @@ struct box_within_range
};
template <typename Geometry, std::size_t Dimension, typename CSTag>
struct box_covered_by_range
{
template <typename BoxContainedValue, typename BoxContainingValue>
@@ -61,9 +65,103 @@ struct box_covered_by_range
};
// spherical_equatorial_tag and spherical_polar_tag is casted to spherical_tag
template <typename Geometry>
struct box_within_range<Geometry, 0, spherical_tag>
{
template <typename BoxContainedValue, typename BoxContainingValue>
static inline bool apply(BoxContainedValue const& bed_min,
BoxContainedValue const& bed_max,
BoxContainingValue const& bing_min,
BoxContainingValue const& bing_max)
{
typedef typename select_most_precise
<
BoxContainedValue,
BoxContainingValue
>::type calc_t;
typedef typename coordinate_system<Geometry>::type::units units_t;
typedef math::detail::constants_on_spheroid<calc_t, units_t> constants;
// min <= max <=> diff >= 0
calc_t diff_ed = bed_max - bed_min;
calc_t diff_ing = bing_max - bing_min;
// if containing is smaller it cannot contain
// or interiors doesn't overlap (no interior in contained)
if (diff_ing < diff_ed || diff_ed == 0)
return false;
// if containing covers the whole globe it contains all
if (!math::smaller(diff_ing, constants::period())) // >= period
return true;
// calculate positive longitude translation with bing_min as origin
calc_t const c0 = 0;
calc_t diff_min = bed_min - bing_min;
math::normalize_longitude<units_t, calc_t>(diff_min);
if (diff_min < c0) // [-180, 180] -> [0, 360]
diff_min += constants::period();
return bing_min + diff_min + diff_ed <= bing_max;
}
};
template <typename Geometry>
struct box_covered_by_range<Geometry, 0, spherical_tag>
{
template <typename BoxContainedValue, typename BoxContainingValue>
static inline bool apply(BoxContainedValue const& bed_min,
BoxContainedValue const& bed_max,
BoxContainingValue const& bing_min,
BoxContainingValue const& bing_max)
{
typedef typename select_most_precise
<
BoxContainedValue,
BoxContainingValue
>::type calc_t;
typedef typename coordinate_system<Geometry>::type::units units_t;
typedef math::detail::constants_on_spheroid<calc_t, units_t> constants;
// min <= max <=> diff >= 0
calc_t diff_ed = bed_max - bed_min;
calc_t diff_ing = bing_max - bing_min;
// if containing is smaller it cannot contain
if (diff_ing < diff_ed)
return false;
// if containing covers the whole globe it contains all
if (!math::smaller(diff_ing, constants::period())) // >= period
return true;
// calculate positive longitude translation with bing_min as origin
calc_t const c0 = 0;
calc_t diff_min = bed_min - bing_min;
math::normalize_longitude<units_t, calc_t>(diff_min);
if (diff_min < c0) // [-180, 180] -> [0, 360]
diff_min += constants::period();
return bing_min + diff_min + diff_ed <= bing_max;
}
};
template <typename Geometry>
struct box_within_range<Geometry, 0, geographic_tag>
: box_within_range<Geometry, 0, spherical_tag>
{};
template <typename Geometry>
struct box_covered_by_range<Geometry, 0, geographic_tag>
: box_covered_by_range<Geometry, 0, spherical_tag>
{};
template
<
typename SubStrategy,
template <typename, std::size_t, typename> class SubStrategy,
typename Box1,
typename Box2,
std::size_t Dimension,
@@ -74,8 +172,9 @@ struct relate_box_box_loop
static inline bool apply(Box1 const& b_contained, Box2 const& b_containing)
{
assert_dimension_equal<Box1, Box2>();
typedef typename tag_cast<typename cs_tag<Box1>::type, spherical_tag>::type cs_tag_t;
if (! SubStrategy::apply(
if (! SubStrategy<Box1, Dimension, cs_tag_t>::apply(
get<min_corner, Dimension>(b_contained),
get<max_corner, Dimension>(b_contained),
get<min_corner, Dimension>(b_containing),
@@ -97,7 +196,7 @@ struct relate_box_box_loop
template
<
typename SubStrategy,
template <typename, std::size_t, typename> class SubStrategy,
typename Box1,
typename Box2,
std::size_t DimensionCount
@@ -114,7 +213,7 @@ template
<
typename Box1,
typename Box2,
typename SubStrategy = box_within_range
template <typename, std::size_t, typename> class SubStrategy = box_within_range
>
struct box_in_box
{
@@ -150,6 +249,30 @@ struct default_strategy
typedef within::box_in_box<BoxContained, BoxContaining> type;
};
template <typename BoxContained, typename BoxContaining>
struct default_strategy
<
box_tag, box_tag,
box_tag, areal_tag,
spherical_tag, spherical_tag,
BoxContained, BoxContaining
>
{
typedef within::box_in_box<BoxContained, BoxContaining> type;
};
template <typename BoxContained, typename BoxContaining>
struct default_strategy
<
box_tag, box_tag,
box_tag, areal_tag,
geographic_tag, geographic_tag,
BoxContained, BoxContaining
>
{
typedef within::box_in_box<BoxContained, BoxContaining> type;
};
}} // namespace within::services
@@ -172,6 +295,38 @@ struct default_strategy
> type;
};
template <typename BoxContained, typename BoxContaining>
struct default_strategy
<
box_tag, box_tag,
box_tag, areal_tag,
spherical_tag, spherical_tag,
BoxContained, BoxContaining
>
{
typedef within::box_in_box
<
BoxContained, BoxContaining,
within::box_covered_by_range
> type;
};
template <typename BoxContained, typename BoxContaining>
struct default_strategy
<
box_tag, box_tag,
box_tag, areal_tag,
geographic_tag, geographic_tag,
BoxContained, BoxContaining
>
{
typedef within::box_in_box
<
BoxContained, BoxContaining,
within::box_covered_by_range
> type;
};
}} // namespace covered_by::services