// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
-// This file was modified by Oracle on 2018.
-// Modifications copyright (c) 2018 Oracle and/or its affiliates.
+// This file was modified by Oracle on 2018-2020.
+// Modifications copyright (c) 2018-2020 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
#include <boost/array.hpp>
#include <boost/core/ignore_unused.hpp>
+
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
+
#include <boost/geometry/algorithms/assign.hpp>
-#include <boost/geometry/strategies/covered_by.hpp>
+
#include <boost/geometry/strategies/side.hpp>
+
+#include <boost/geometry/strategies/covered_by.hpp>
#include <boost/geometry/strategies/within.hpp>
+#include <boost/geometry/strategies/geographic/side.hpp>
+#include <boost/geometry/strategies/spherical/ssf.hpp>
namespace boost { namespace geometry { namespace strategy
namespace within
{
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail
+{
+
struct decide_within
{
static inline bool apply(int side, bool& result)
// This strategy is not suitable for boxes in non-cartesian CSes having edges
// longer than 180deg because e.g. the SSF formula picks the side of the closer
// longitude, so for long edges the side is the opposite.
-template <typename Decide = decide_within>
-struct point_in_box_by_side
+// Actually it is not suitable for shorter edges either because the edges of
+// boxes are defined by meridians and parallels, not great circles or geodesics.
+template <typename Decide, typename Point, typename Box, typename Strategy>
+inline bool point_in_box_by_side(Point const& point, Box const& box,
+ Strategy const& strategy)
+{
+ boost::ignore_unused(strategy);
+
+ // Create (counterclockwise) array of points, the fifth one closes it
+ // Every point should be on the LEFT side (=1), or ON the border (=0),
+ // So >= 1 or >= 0
+ boost::array<typename point_type<Box>::type, 5> bp;
+ geometry::detail::assign_box_corners_oriented<true>(box, bp);
+ bp[4] = bp[0];
+
+ bool result = true;
+ for (int i = 1; i < 5; i++)
+ {
+ int const side = strategy.apply(point, bp[i - 1], bp[i]);
+ if (! Decide::apply(side, result))
+ {
+ return result;
+ }
+ }
+
+ return result;
+}
+
+
+} // namespace detail
+#endif // DOXYGEN_NO_DETAIL
+
+
+// There should probably be another category of geometry different than box,
+// e.g. rectangle or convex_ring. This strategy should probably be an
+// algorithm calling side strategy.
+
+template <typename CalculationType = void>
+struct cartesian_point_box_by_side
+{
+ template <typename Point, typename Box>
+ static inline bool apply(Point const& point, Box const& box)
+ {
+ using side_strategy_type
+ = typename strategy::side::services::default_strategy
+ <cartesian_tag, CalculationType>::type;
+
+ return within::detail::point_in_box_by_side
+ <
+ within::detail::decide_within
+ >(point, box, side_strategy_type());
+ }
+};
+
+template <typename CalculationType = void>
+struct spherical_point_box_by_side
{
template <typename Point, typename Box>
static inline bool apply(Point const& point, Box const& box)
{
- typedef typename strategy::side::services::default_strategy
+ return within::detail::point_in_box_by_side
<
- typename cs_tag<Box>::type
- >::type side_strategy_type;
+ within::detail::decide_within
+ >(point, box,
+ strategy::side::spherical_side_formula<CalculationType>());
+ }
+};
- // Create (counterclockwise) array of points, the fifth one closes it
- // Every point should be on the LEFT side (=1), or ON the border (=0),
- // So >= 1 or >= 0
- boost::array<typename point_type<Box>::type, 5> bp;
- geometry::detail::assign_box_corners_oriented<true>(box, bp);
- bp[4] = bp[0];
+template
+<
+ typename FormulaPolicy = strategy::andoyer,
+ typename Spheroid = srs::spheroid<double>,
+ typename CalculationType = void
+>
+struct geographic_point_box_by_side
+{
+ geographic_point_box_by_side() = default;
- bool result = true;
- side_strategy_type strategy;
- boost::ignore_unused(strategy);
+ explicit geographic_point_box_by_side(Spheroid const& spheroid)
+ : m_side(spheroid)
+ {}
- for (int i = 1; i < 5; i++)
- {
- int const side = strategy.apply(point, bp[i - 1], bp[i]);
- if (! Decide::apply(side, result))
- {
- return result;
- }
- }
+ template <typename Point, typename Box>
+ bool apply(Point const& point, Box const& box) const
+ {
+ return within::detail::point_in_box_by_side
+ <
+ within::detail::decide_within
+ >(point, box, m_side);
+ }
- return result;
+ Spheroid const& model() const
+ {
+ return m_side.model();
}
+
+private:
+ strategy::side::geographic
+ <
+ FormulaPolicy, Spheroid, CalculationType
+ > m_side;
};
} // namespace within
+namespace covered_by
+{
+
+
+template <typename CalculationType = void>
+struct cartesian_point_box_by_side
+{
+ template <typename Point, typename Box>
+ static bool apply(Point const& point, Box const& box)
+ {
+ using side_strategy_type
+ = typename strategy::side::services::default_strategy
+ <cartesian_tag, CalculationType>::type;
+ return within::detail::point_in_box_by_side
+ <
+ within::detail::decide_covered_by
+ >(point, box, side_strategy_type());
+ }
+};
+
+template <typename CalculationType = void>
+struct spherical_point_box_by_side
+{
+ template <typename Point, typename Box>
+ static bool apply(Point const& point, Box const& box)
+ {
+ return within::detail::point_in_box_by_side
+ <
+ within::detail::decide_covered_by
+ >(point, box,
+ strategy::side::spherical_side_formula<CalculationType>());
+ }
+};
+
+template
+<
+ typename FormulaPolicy = strategy::andoyer,
+ typename Spheroid = srs::spheroid<double>,
+ typename CalculationType = void
+>
+struct geographic_point_box_by_side
+{
+ geographic_point_box_by_side() = default;
+
+ explicit geographic_point_box_by_side(Spheroid const& spheroid)
+ : m_side(spheroid)
+ {}
+
+ template <typename Point, typename Box>
+ bool apply(Point const& point, Box const& box) const
+ {
+ return within::detail::point_in_box_by_side
+ <
+ within::detail::decide_covered_by
+ >(point, box, m_side);
+ }
+
+ Spheroid const& model() const
+ {
+ return m_side.model();
+ }
+
+private:
+ strategy::side::geographic
+ <
+ FormulaPolicy, Spheroid, CalculationType
+ > m_side;
+};
+
+
+}
+
+
}}} // namespace boost::geometry::strategy