diff --git a/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp b/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp index 46a7c0f7a..97e8a2668 100644 --- a/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp @@ -979,8 +979,7 @@ struct buffered_piece_collection return; } - geometry::detail::envelope::envelope_range<>::apply(pc.robust_ring, - pc.robust_envelope); + geometry::envelope(pc.robust_ring, pc.robust_envelope); geometry::assign_inverse(pc.robust_offsetted_envelope); for (signed_size_type i = 0; i < pc.offsetted_count; i++) diff --git a/include/boost/geometry/algorithms/detail/envelope/box.hpp b/include/boost/geometry/algorithms/detail/envelope/box.hpp index 0b3f17709..379026294 100644 --- a/include/boost/geometry/algorithms/detail/envelope/box.hpp +++ b/include/boost/geometry/algorithms/detail/envelope/box.hpp @@ -9,25 +9,25 @@ // Contributed and/or modified by Menelaos Karavelas, 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. - -// Use, modification and distribution is subject to the Boost Software License, -// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// Distributed under 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) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_BOX_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_BOX_HPP +#include + #include +#include #include #include -#include +#include -#include -#include +#include #include +#include #include @@ -40,37 +40,97 @@ namespace detail { namespace envelope { -struct envelope_box_on_spheroid +template +< + std::size_t Index, + std::size_t Dimension, + std::size_t DimensionCount +> +struct envelope_indexed_box { - template + template static inline void apply(BoxIn const& box_in, BoxOut& mbr) { - BoxIn box_in_normalized = detail::return_normalized(box_in); + detail::indexed_point_view box_in_corner(box_in); + detail::indexed_point_view mbr_corner(mbr); - geometry::transform(box_in_normalized, mbr); + detail::conversion::point_to_point + < + detail::indexed_point_view, + detail::indexed_point_view, + Dimension, + DimensionCount + >::apply(box_in_corner, mbr_corner); + } +}; + +template +< + std::size_t Index, + std::size_t DimensionCount +> +struct envelope_indexed_box_on_spheroid +{ + template + static inline void apply(BoxIn const& box_in, BoxOut& mbr) + { + // transform() does not work with boxes of dimension higher + // than 2; to account for such boxes we transform the min/max + // points of the boxes using the indexed_point_view + detail::indexed_point_view box_in_corner(box_in); + detail::indexed_point_view mbr_corner(mbr); + + // first transform the units + transform_units(box_in_corner, mbr_corner); + + // now transform the remaining coordinates + detail::conversion::point_to_point + < + detail::indexed_point_view, + detail::indexed_point_view, + 2, + DimensionCount + >::apply(box_in_corner, mbr_corner); } }; -template struct envelope_box { template static inline void apply(BoxIn const& box_in, BoxOut& mbr) { - geometry::convert(box_in, mbr); + envelope_indexed_box + < + min_corner, 0, dimension::value + >::apply(box_in, mbr); + + envelope_indexed_box + < + max_corner, 0, dimension::value + >::apply(box_in, mbr); } }; -template <> -struct envelope_box - : envelope_box_on_spheroid -{}; -template <> -struct envelope_box - : envelope_box_on_spheroid -{}; +struct envelope_box_on_spheroid +{ + template + static inline void apply(BoxIn const& box_in, BoxOut& mbr) + { + BoxIn box_in_normalized = detail::return_normalized(box_in); + + envelope_indexed_box_on_spheroid + < + min_corner, dimension::value + >::apply(box_in_normalized, mbr); + + envelope_indexed_box_on_spheroid + < + max_corner, dimension::value + >::apply(box_in_normalized, mbr); + } +}; }} // namespace detail::envelope @@ -81,14 +141,26 @@ namespace dispatch { +template +struct envelope + : detail::envelope::envelope_box +{}; + + template -struct envelope - : detail::envelope::envelope_box::type> +struct envelope + : detail::envelope::envelope_box_on_spheroid +{}; + + +template +struct envelope + : detail::envelope::envelope_box_on_spheroid {}; } // namespace dispatch -#endif +#endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry diff --git a/include/boost/geometry/algorithms/detail/envelope/implementation.hpp b/include/boost/geometry/algorithms/detail/envelope/implementation.hpp index c88adac7a..c1dbf8e58 100644 --- a/include/boost/geometry/algorithms/detail/envelope/implementation.hpp +++ b/include/boost/geometry/algorithms/detail/envelope/implementation.hpp @@ -12,21 +12,21 @@ // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. -// Use, modification and distribution is subject to the Boost Software License, -// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// Distributed under 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) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_IMPLEMENTATION_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_IMPLEMENTATION_HPP #include +#include #include -#include +#include #include -#include -#include +#include #include #include #include @@ -43,27 +43,28 @@ namespace detail { namespace envelope { -struct exterior_ring_expand_policy -{ - template - static inline void apply(Box& mbr, Geometry const& geometry) - { - Box ring_mbr; - envelope_range<>::apply(exterior_ring(geometry), ring_mbr); - geometry::expand(mbr, ring_mbr); - } -}; - - struct envelope_polygon { template - static inline void apply(Polygon const& poly, Box& mbr) + static inline void apply(Polygon const& polygon, Box& mbr) { - // For polygon, inspecting outer ring is sufficient - envelope_range<>::apply(exterior_ring(poly), mbr); - } + typename ring_return_type::type ext_ring + = exterior_ring(polygon); + if (geometry::is_empty(ext_ring)) + { + // if the exterior ring is empty, consider the interior rings + envelope_multi_range + < + envelope_range + >::apply(interior_rings(polygon), mbr); + } + else + { + // otherwise, consider only the exterior ring + envelope_range::apply(ext_ring, mbr); + } + } }; @@ -77,7 +78,7 @@ namespace dispatch template struct envelope - : detail::envelope::envelope_range<> + : detail::envelope::envelope_range {}; @@ -89,15 +90,16 @@ struct envelope template struct envelope - : detail::envelope::envelope_range + : detail::envelope::envelope_multi_range < - detail::envelope::exterior_ring_expand_policy + detail::envelope::envelope_polygon > {}; } // namespace dispatch -#endif +#endif // DOXYGEN_NO_DISPATCH + }} // namespace boost::geometry diff --git a/include/boost/geometry/algorithms/detail/envelope/initialize.hpp b/include/boost/geometry/algorithms/detail/envelope/initialize.hpp new file mode 100644 index 000000000..d8e252b53 --- /dev/null +++ b/include/boost/geometry/algorithms/detail/envelope/initialize.hpp @@ -0,0 +1,86 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2015, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Distributed under 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) + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_INITIALIZE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_INITIALIZE_HPP + +#include + +#include + +#include +#include +#include + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace envelope +{ + +template +struct initialize_loop +{ + template + static inline void apply(Box& box, + CoordinateType min_value, + CoordinateType max_value) + { + geometry::set(box, min_value); + geometry::set(box, max_value); + + initialize_loop + < + Dimension + 1, DimensionCount + >::apply(box, min_value, max_value); + } +}; + +template +struct initialize_loop +{ + template + static inline void apply(Box&, CoordinateType, CoordinateType) + { + } +}; + + +template +< + typename Box, + std::size_t Dimension = 0, + std::size_t DimensionCount = dimension::value +> +struct initialize +{ + typedef typename coordinate_type::type coordinate_type; + + static inline void apply(Box& box, + coordinate_type min_value + = boost::numeric::bounds::highest(), + coordinate_type max_value + = boost::numeric::bounds::lowest()) + { + initialize_loop + < + Dimension, DimensionCount + >::apply(box, min_value, max_value); + } +}; + +}} // namespace detail::envelope +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_INITIALIZE_HPP diff --git a/include/boost/geometry/algorithms/detail/envelope/interface.hpp b/include/boost/geometry/algorithms/detail/envelope/interface.hpp index 3c1b2b9fe..997ac1b23 100644 --- a/include/boost/geometry/algorithms/detail/envelope/interface.hpp +++ b/include/boost/geometry/algorithms/detail/envelope/interface.hpp @@ -12,8 +12,8 @@ // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. -// Use, modification and distribution is subject to the Boost Software License, -// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// Distributed under 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) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_INTERFACE_HPP diff --git a/include/boost/geometry/algorithms/detail/envelope/intersects_antimeridian.hpp b/include/boost/geometry/algorithms/detail/envelope/intersects_antimeridian.hpp index 4bd917796..47937bf74 100644 --- a/include/boost/geometry/algorithms/detail/envelope/intersects_antimeridian.hpp +++ b/include/boost/geometry/algorithms/detail/envelope/intersects_antimeridian.hpp @@ -4,8 +4,9 @@ // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle -// Licensed under the Boost Software License version 1.0. -// http://www.boost.org/users/license.html +// Distributed under 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) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_INTERSECTS_ANTIMERIDIAN_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_INTERSECTS_ANTIMERIDIAN_HPP diff --git a/include/boost/geometry/algorithms/detail/envelope/linear.hpp b/include/boost/geometry/algorithms/detail/envelope/linear.hpp new file mode 100644 index 000000000..49c3cf313 --- /dev/null +++ b/include/boost/geometry/algorithms/detail/envelope/linear.hpp @@ -0,0 +1,96 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2015 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2015 Mateusz Loskot, London, UK. + +// This file was modified by Oracle on 2015. +// Modifications copyright (c) 2015, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Distributed under 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) + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_LINEAR_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_LINEAR_HPP + +#include +#include + +#include + +#include + +#include + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace envelope +{ + + +struct envelope_linestring_on_spheroid +{ + template + static inline void apply(Linestring const& linestring, Box& mbr) + { + envelope_range::apply(geometry::segments_begin(linestring), + geometry::segments_end(linestring), + mbr); + } +}; + + +}} // namespace detail::envelope +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template +struct envelope + : detail::envelope::envelope_range +{}; + +template +struct envelope + : detail::envelope::envelope_linestring_on_spheroid +{}; + + +template +struct envelope + < + MultiLinestring, multi_linestring_tag, CS_Tag + > : detail::envelope::envelope_multi_range + < + detail::envelope::envelope_range + > +{}; + +template +struct envelope + < + MultiLinestring, multi_linestring_tag, spherical_equatorial_tag + > : detail::envelope::envelope_multi_range_on_spheroid + < + detail::envelope::envelope_linestring_on_spheroid + > +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_LINEAR_HPP diff --git a/include/boost/geometry/algorithms/detail/envelope/linestring.hpp b/include/boost/geometry/algorithms/detail/envelope/linestring.hpp deleted file mode 100644 index 379bd7890..000000000 --- a/include/boost/geometry/algorithms/detail/envelope/linestring.hpp +++ /dev/null @@ -1,182 +0,0 @@ -// Boost.Geometry (aka GGL, Generic Geometry Library) - -// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. -// Copyright (c) 2008-2015 Bruno Lalande, Paris, France. -// Copyright (c) 2009-2015 Mateusz Loskot, London, UK. - -// This file was modified by Oracle on 2015. -// Modifications copyright (c) 2015, Oracle and/or its affiliates. - -// Contributed and/or modified by Menelaos Karavelas, 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. - -// 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) - -#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_LINESTRING_HPP -#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_LINESTRING_HPP - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include -#include - -#include -#include - -#include - - -namespace boost { namespace geometry -{ - -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace envelope -{ - - -struct envelope_linear_on_spheroid -{ - template - static inline OutputIterator push_interval(Longitude const& lon1, - Longitude const& lon2, - OutputIterator oit) - { - typedef longitude_interval interval_type; - - typedef math::detail::constants_on_spheroid - < - Longitude, Units - > constants; - - BOOST_GEOMETRY_ASSERT(! math::larger(lon1, lon2)); - BOOST_GEOMETRY_ASSERT(! math::larger(lon1, constants::max_longitude())); - - if (math::larger(lon2, constants::max_longitude())) - { - *oit++ = interval_type(lon1, constants::max_longitude()); - *oit++ = interval_type(constants::min_longitude(), - lon2 - constants::period()); - } - else - { - *oit++ = interval_type(lon1, lon2); - } - return oit; - } - - template - static inline void apply(Linear const& linear, Box& mbr) - { - typedef typename coordinate_type::type box_coordinate_type; - typedef longitude_interval interval_type; - - typedef typename geometry::segment_iterator - < - Linear const - > iterator_type; - - BOOST_GEOMETRY_ASSERT(! geometry::is_empty(linear)); - - std::vector longitude_intervals; - std::back_insert_iterator - < - std::vector - > oit(longitude_intervals); - - box_coordinate_type lat_min = 0, lat_max = 0; - bool first = true; - for (iterator_type seg_it = geometry::segments_begin(linear); - seg_it != geometry::segments_end(linear); - ++seg_it, first = false) - { - Box segment_mbr; - dispatch::envelope - < - typename std::iterator_traits::value_type - >::apply(*seg_it, segment_mbr); - - oit = push_interval - < - typename coordinate_system::type::units - >(geometry::get(segment_mbr), - geometry::get(segment_mbr), - oit); - - if (first) - { - lat_min = geometry::get(segment_mbr); - lat_max = geometry::get(segment_mbr); - } - - // update min and max latitude, if needed - if (math::smaller(geometry::get(segment_mbr), - lat_min)) - { - lat_min = geometry::get(segment_mbr); - } - - if (math::larger(geometry::get(segment_mbr), - lat_max)) - { - lat_max = geometry::get(segment_mbr); - } - } - - box_coordinate_type lon_min = 0, lon_max = 0; - envelope_range_of_longitudes - < - typename coordinate_system::type::units - >::apply(longitude_intervals, lon_min, lon_max); - - assign_values(mbr, lon_min, lat_min, lon_max, lat_max); - } -}; - - -template -struct envelope_linestring - : envelope_range<> -{}; - -template <> -struct envelope_linestring - : envelope_linear_on_spheroid -{}; - - -}} // namespace detail::envelope -#endif // DOXYGEN_NO_DETAIL - - -#ifndef DOXYGEN_NO_DISPATCH -namespace dispatch -{ - -template -struct envelope - : detail::envelope::envelope_linestring::type> -{}; - -} // namespace dispatch -#endif - - -}} // namespace boost::geometry - -#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_LINESTRING_HPP diff --git a/include/boost/geometry/algorithms/detail/envelope/multilinestring.hpp b/include/boost/geometry/algorithms/detail/envelope/multilinestring.hpp deleted file mode 100644 index fc15baa47..000000000 --- a/include/boost/geometry/algorithms/detail/envelope/multilinestring.hpp +++ /dev/null @@ -1,86 +0,0 @@ -// Boost.Geometry (aka GGL, Generic Geometry Library) - -// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. -// Copyright (c) 2008-2015 Bruno Lalande, Paris, France. -// Copyright (c) 2009-2015 Mateusz Loskot, London, UK. - -// This file was modified by Oracle on 2015. -// Modifications copyright (c) 2015, Oracle and/or its affiliates. - -// Contributed and/or modified by Menelaos Karavelas, 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. - -// 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) - -#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_MULTILINESTRING_HPP -#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_MULTILINESTRING_HPP - -#include -#include - -#include - -#include -#include - -#include - - -namespace boost { namespace geometry -{ - -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace envelope -{ - - -struct envelope_range_expand_policy -{ - template - static inline void apply(Box& mbr, Geometry const& geometry) - { - Box mbr2; - envelope_range<>::apply(geometry, mbr2); - geometry::expand(mbr, mbr2); - } -}; - - -template -struct envelope_multilinestring - : envelope_range -{}; - -template <> -struct envelope_multilinestring - : envelope_linear_on_spheroid -{}; - - -}} // namespace detail::envelope -#endif // DOXYGEN_NO_DETAIL - -#ifndef DOXYGEN_NO_DISPATCH -namespace dispatch -{ - - -template -struct envelope - : detail::envelope::envelope_multilinestring - < - typename cs_tag::type - > -{}; - - -} // namespace dispatch -#endif - -}} // namespace boost::geometry - -#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_MULTILINESTRING_HPP diff --git a/include/boost/geometry/algorithms/detail/envelope/multipoint.hpp b/include/boost/geometry/algorithms/detail/envelope/multipoint.hpp index 3574e5420..210debfdb 100644 --- a/include/boost/geometry/algorithms/detail/envelope/multipoint.hpp +++ b/include/boost/geometry/algorithms/detail/envelope/multipoint.hpp @@ -4,12 +4,14 @@ // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle -// Licensed under the Boost Software License version 1.0. -// http://www.boost.org/users/license.html +// Distributed under 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) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_MULTIPOINT_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_MULTIPOINT_HPP +#include #include #include #include @@ -28,14 +30,13 @@ #include -#include - -#include -#include - #include +#include +#include #include +#include + #include @@ -50,14 +51,14 @@ namespace detail { namespace envelope class envelope_multipoint_on_spheroid { private: - template + template struct coordinate_less { template inline bool operator()(Point const& point1, Point const& point2) const { - return math::smaller(geometry::get(point1), - geometry::get(point2)); + return math::smaller(geometry::get(point1), + geometry::get(point2)); } }; @@ -230,6 +231,10 @@ public: { typedef typename point_type::type point_type; typedef typename coordinate_type::type coordinate_type; + typedef typename boost::range_iterator + < + MultiPoint const + >::type iterator_type; typedef math::detail::constants_on_spheroid < @@ -237,12 +242,14 @@ public: typename coordinate_system::type::units > constants; - if (boost::empty(multipoint)) { + initialize::value>::apply(mbr); return; } + initialize::apply(mbr); + if (boost::size(multipoint) == 1) { return dispatch::envelope @@ -302,16 +309,37 @@ public: lat_max); } - typename helper_geometry + typedef typename helper_geometry < Box, coordinate_type, typename coordinate_system::type::units - >::type helper_mbr; + >::type helper_box_type; - assign_values(helper_mbr, lon_min, lat_min, lon_max, lat_max); + helper_box_type helper_mbr; - geometry::transform(helper_mbr, mbr); + geometry::set(helper_mbr, lon_min); + geometry::set(helper_mbr, lat_min); + geometry::set(helper_mbr, lon_max); + geometry::set(helper_mbr, lat_max); + + // now transform to output MBR (per index) + envelope_indexed_box_on_spheroid::apply(helper_mbr, mbr); + envelope_indexed_box_on_spheroid::apply(helper_mbr, mbr); + + // compute envelope for higher coordinates + iterator_type it = boost::begin(multipoint); + envelope_one_point<2, dimension::value>::apply(*it, mbr); + + for (++it; it != boost::end(multipoint); ++it) + { + detail::expand::point_loop + < + strategy::compare::default_strategy, + strategy::compare::default_strategy, + 2, dimension::value + >::apply(mbr, *it); + } } }; @@ -319,6 +347,8 @@ public: }} // namespace detail::envelope #endif // DOXYGEN_NO_DETAIL + + #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { @@ -326,7 +356,7 @@ namespace dispatch template struct envelope - : detail::envelope::envelope_range<> + : detail::envelope::envelope_range {}; template @@ -341,7 +371,7 @@ struct envelope } // namespace dispatch -#endif +#endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry diff --git a/include/boost/geometry/algorithms/detail/envelope/point.hpp b/include/boost/geometry/algorithms/detail/envelope/point.hpp index 9e9b01d22..e914e7e8a 100644 --- a/include/boost/geometry/algorithms/detail/envelope/point.hpp +++ b/include/boost/geometry/algorithms/detail/envelope/point.hpp @@ -9,27 +9,28 @@ // Contributed and/or modified by Menelaos Karavelas, 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. - -// Use, modification and distribution is subject to the Boost Software License, -// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// Distributed under 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) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_POINT_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_POINT_HPP +#include + +#include #include +#include #include #include -#include - -#include -#include +#include +#include #include +#include + #include @@ -40,6 +41,32 @@ namespace boost { namespace geometry namespace detail { namespace envelope { + +template +struct envelope_one_point +{ + template + static inline void apply(Point const& point, Box& mbr) + { + detail::indexed_point_view box_corner(mbr); + detail::conversion::point_to_point + < + Point, + detail::indexed_point_view, + Dimension, + DimensionCount + >::apply(point, box_corner); + } + + template + static inline void apply(Point const& point, Box& mbr) + { + apply(point, mbr); + apply(point, mbr); + } +}; + + struct envelope_point_on_spheroid { template @@ -49,34 +76,23 @@ struct envelope_point_on_spheroid typename point_type::type box_point; - // transform input point to a point of the same type as box's point - geometry::transform(normalized_point, box_point); + // transform units of input point to units of a box point + transform_units(normalized_point, box_point); - geometry::convert(box_point, mbr); + geometry::set(mbr, geometry::get<0>(box_point)); + geometry::set(mbr, geometry::get<1>(box_point)); + + geometry::set(mbr, geometry::get<0>(box_point)); + geometry::set(mbr, geometry::get<1>(box_point)); + + envelope_one_point + < + 2, dimension::value + >::apply(normalized_point, mbr); } }; -template -struct envelope_one_point -{ - template - static inline void apply(Point const& point, Box& mbr) - { - geometry::convert(point, mbr); - } -}; - -template <> -struct envelope_one_point - : envelope_point_on_spheroid -{}; - -template <> -struct envelope_one_point - : envelope_point_on_spheroid -{}; - }} // namespace detail::envelope #endif // DOXYGEN_NO_DETAIL @@ -85,14 +101,26 @@ namespace dispatch { +template +struct envelope + : detail::envelope::envelope_one_point<0, dimension::value> +{}; + + template -struct envelope - : detail::envelope::envelope_one_point::type> +struct envelope + : detail::envelope::envelope_point_on_spheroid +{}; + + +template +struct envelope + : detail::envelope::envelope_point_on_spheroid {}; } // namespace dispatch -#endif +#endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry diff --git a/include/boost/geometry/algorithms/detail/envelope/range.hpp b/include/boost/geometry/algorithms/detail/envelope/range.hpp index b2023f338..63b518114 100644 --- a/include/boost/geometry/algorithms/detail/envelope/range.hpp +++ b/include/boost/geometry/algorithms/detail/envelope/range.hpp @@ -12,17 +12,30 @@ // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. -// Use, modification and distribution is subject to the Boost Software License, -// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// Distributed under 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) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_RANGE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_RANGE_HPP +#include +#include + #include + +#include + #include -#include +#include + +#include +#include + +#include +#include +#include #include @@ -35,51 +48,124 @@ namespace detail { namespace envelope { -struct default_expand_policy +// implementation for simple ranges +struct envelope_range { - template - static inline void apply(Box& mbr, Geometry const& geometry) + template + static inline void apply(Iterator first, Iterator last, Box& mbr) { - geometry::expand(mbr, geometry); + typedef typename std::iterator_traits::value_type value_type; + + // initialize MBR + initialize::value>::apply(mbr); + + Iterator it = first; + if (it != last) + { + // initialize box with first element in range + dispatch::envelope::apply(*it, mbr); + + // consider now the remaining elements in the range (if any) + for (++it; it != last; ++it) + { + dispatch::expand::apply(mbr, *it); + } + } + } + + template + static inline void apply(Range const& range, Box& mbr) + { + return apply(boost::begin(range), boost::end(range), mbr); } }; -template -inline void envelope_iterators(Iterator first, Iterator last, Box& mbr) +// implementation for multi-ranges +template +struct envelope_multi_range { - for (Iterator it = first; it != last; ++it) + template + static inline void apply(MultiRange const& multirange, Box& mbr) { - ExpandPolicy::apply(mbr, *it); - } -} + typedef typename boost::range_iterator + < + MultiRange const + >::type iterator_type; - -template -struct envelope_range -{ - /// Calculate envelope of range using a strategy - template - static inline void apply(Range const& range, Box& mbr) - { - typename boost::range_iterator::type it - = boost::begin(range); - - if (it != boost::end(range)) + bool initialized = false; + for (iterator_type it = boost::begin(multirange); + it != boost::end(multirange); + ++it) { - // initialize box with first element in range - dispatch::envelope - < - typename boost::range_value::type - >::apply(*it, mbr); + if (! geometry::is_empty(*it)) + { + if (initialized) + { + Box helper_mbr; + EnvelopePolicy::apply(*it, helper_mbr); - // consider now the remaining elements in the range (if any) - ++it; - envelope_iterators - < - ExpandPolicy - >(it, boost::end(range), mbr); + dispatch::expand::apply(mbr, helper_mbr); + } + else + { + // compute the initial envelope + EnvelopePolicy::apply(*it, mbr); + initialized = true; + } + } } + + if (! initialized) + { + // if not already initialized, initialize MBR + initialize::value>::apply(mbr); + } + } +}; + + +// implementation for multi-range on a spheroid (longitude is periodic) +template +struct envelope_multi_range_on_spheroid +{ + template + static inline void apply(MultiRange const& multirange, Box& mbr) + { + typedef typename boost::range_iterator + < + MultiRange const + >::type iterator_type; + + // due to the periodicity of longitudes we need to compute the boxes + // of all the single geometries and keep them in a container + std::vector boxes; + for (iterator_type it = boost::begin(multirange); + it != boost::end(multirange); + ++it) + { + if (! geometry::is_empty(*it)) + { + Box helper_box; + EnvelopePolicy::apply(*it, helper_box); + boxes.push_back(helper_box); + } + } + + // now we need to compute the envelope of the range of boxes + // (cannot be done in an incremental fashion as in the + // Cartesian coordinate system) + // if all single geometries are empty no boxes have been found + // and the MBR is simply initialized + if (! boxes.empty()) + { + envelope_range_of_boxes::apply(boxes, mbr); + } + else + { + initialize::value>::apply(mbr); + } + } }; diff --git a/include/boost/geometry/algorithms/detail/envelope/range_of_boxes.hpp b/include/boost/geometry/algorithms/detail/envelope/range_of_boxes.hpp index 90a1b099b..64bdb9b9c 100644 --- a/include/boost/geometry/algorithms/detail/envelope/range_of_boxes.hpp +++ b/include/boost/geometry/algorithms/detail/envelope/range_of_boxes.hpp @@ -4,8 +4,9 @@ // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle -// Licensed under the Boost Software License version 1.0. -// http://www.boost.org/users/license.html +// Distributed under 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) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_RANGE_OF_BOXES_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_RANGE_OF_BOXES_HPP @@ -23,9 +24,11 @@ #include #include +#include -#include +#include #include +#include namespace boost { namespace geometry @@ -92,8 +95,6 @@ struct envelope_range_of_longitudes Longitude const zero = 0; Longitude const period = constants::period(); - Longitude const min_longitude = constants::min_longitude(); - Longitude const max_longitude = constants::max_longitude(); lon_min = lon_max = zero; @@ -118,12 +119,17 @@ struct envelope_range_of_longitudes max_gap_right); BOOST_GEOMETRY_ASSERT(! math::larger(lon_min, lon_max)); - BOOST_GEOMETRY_ASSERT(! math::larger(lon_max, max_longitude)); - BOOST_GEOMETRY_ASSERT(! math::smaller(lon_min, min_longitude)); + BOOST_GEOMETRY_ASSERT + (! math::larger(lon_max, constants::max_longitude())); + BOOST_GEOMETRY_ASSERT + (! math::smaller(lon_min, constants::min_longitude())); - BOOST_GEOMETRY_ASSERT(! math::larger(max_gap_left, max_gap_right)); - BOOST_GEOMETRY_ASSERT(! math::larger(max_gap_right, max_longitude)); - BOOST_GEOMETRY_ASSERT(! math::smaller(max_gap_left, min_longitude)); + BOOST_GEOMETRY_ASSERT + (! math::larger(max_gap_left, max_gap_right)); + BOOST_GEOMETRY_ASSERT + (! math::larger(max_gap_right, constants::max_longitude())); + BOOST_GEOMETRY_ASSERT + (! math::smaller(max_gap_left, constants::min_longitude())); if (math::larger(max_gap, zero)) { @@ -140,6 +146,72 @@ struct envelope_range_of_longitudes }; +template +struct envelope_range_of_boxes_by_expansion +{ + template + static inline void apply(RangeOfBoxes const& range_of_boxes, Box& mbr) + { + typedef typename boost::range_value::type box_type; + + typedef typename boost::range_iterator + < + RangeOfBoxes const + >::type iterator_type; + + // first initialize MBR + detail::indexed_point_view mbr_min(mbr); + detail::indexed_point_view mbr_max(mbr); + + detail::indexed_point_view + first_box_min(range::front(range_of_boxes)); + + detail::indexed_point_view + first_box_max(range::front(range_of_boxes)); + + detail::conversion::point_to_point + < + detail::indexed_point_view, + detail::indexed_point_view, + Dimension, + DimensionCount + >::apply(first_box_min, mbr_min); + + detail::conversion::point_to_point + < + detail::indexed_point_view, + detail::indexed_point_view, + Dimension, + DimensionCount + >::apply(first_box_max, mbr_max); + + // now expand using the remaining boxes + iterator_type it = boost::begin(range_of_boxes); + for (++it; it != boost::end(range_of_boxes); ++it) + { + detail::expand::indexed_loop + < + strategy::compare::default_strategy, + strategy::compare::default_strategy, + min_corner, + Dimension, + DimensionCount + >::apply(mbr, *it); + + detail::expand::indexed_loop + < + strategy::compare::default_strategy, + strategy::compare::default_strategy, + max_corner, + Dimension, + DimensionCount + >::apply(mbr, *it); + } + } + +}; + + struct envelope_range_of_boxes { template @@ -217,7 +289,8 @@ struct envelope_range_of_boxes } } - coordinate_type lon_min(0), lon_max(0); + coordinate_type lon_min = 0; + coordinate_type lon_max = 0; envelope_range_of_longitudes < units_type @@ -225,11 +298,22 @@ struct envelope_range_of_boxes // do not convert units; conversion will be performed at a // higher level - assign_values(mbr, - lon_min, - geometry::get(*it_min), - lon_max, - geometry::get(*it_max)); + + // assign now the min/max longitude/latitude values + detail::indexed_point_view mbr_min(mbr); + detail::indexed_point_view mbr_max(mbr); + + geometry::set<0>(mbr_min, lon_min); + geometry::set<1>(mbr_min, geometry::get(*it_min)); + geometry::set<0>(mbr_max, lon_max); + geometry::set<1>(mbr_max, geometry::get(*it_max)); + + // what remains to be done is to compute the envelope range + // for the remaining dimensions (if any) + envelope_range_of_boxes_by_expansion + < + 2, dimension::value + >::apply(range_of_boxes, mbr); } }; diff --git a/include/boost/geometry/algorithms/detail/envelope/segment.hpp b/include/boost/geometry/algorithms/detail/envelope/segment.hpp index 9b53c84f9..570f0e1a4 100644 --- a/include/boost/geometry/algorithms/detail/envelope/segment.hpp +++ b/include/boost/geometry/algorithms/detail/envelope/segment.hpp @@ -9,16 +9,14 @@ // Contributed and/or modified by Menelaos Karavelas, 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. - -// Use, modification and distribution is subject to the Boost Software License, -// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// Distributed under 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) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_SEGMENT_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_SEGMENT_HPP +#include #include #include @@ -35,15 +33,15 @@ #include -#include - -#include -#include -#include +#include +#include #include #include +#include + +#include #include @@ -55,6 +53,25 @@ namespace boost { namespace geometry namespace detail { namespace envelope { + +template +struct envelope_one_segment +{ + template + static inline void apply(Point const& p1, Point const& p2, Box& mbr) + { + envelope_one_point::apply(p1, mbr); + detail::expand::point_loop + < + strategy::compare::default_strategy, + strategy::compare::default_strategy, + Dimension, + DimensionCount + >::apply(mbr, p2); + } +}; + + // Computes the MBR of a segment given by (lon1, lat1) and (lon2, // lat2), and with azimuths a1 and a2 at the two endpoints of the // segment. @@ -255,29 +272,47 @@ public: { typedef typename coordinate_type::type box_coordinate_type; - typename helper_geometry + typedef typename helper_geometry < Box, box_coordinate_type, radian - >::type radian_mbr; + >::type helper_box_type; + + helper_box_type radian_mbr; apply(lon1, lat1, lon2, lat2); - assign_values(radian_mbr, - boost::numeric_cast(lon1), - boost::numeric_cast(lat1), - boost::numeric_cast(lon2), - boost::numeric_cast(lat2)); + geometry::set + < + min_corner, 0 + >(radian_mbr, boost::numeric_cast(lon1)); - geometry::transform(radian_mbr, mbr); + geometry::set + < + min_corner, 1 + >(radian_mbr, boost::numeric_cast(lat1)); + + geometry::set + < + max_corner, 0 + >(radian_mbr, boost::numeric_cast(lon2)); + + geometry::set + < + max_corner, 1 + >(radian_mbr, boost::numeric_cast(lat2)); + + transform_units(radian_mbr, mbr); } }; -struct envelope_segment_on_spheroid +template +struct envelope_segment_on_sphere { template static inline void apply(Point const& p1, Point const& p2, Box& mbr) { + // first compute the envelope range for the first two coordinates Point p1_normalized = detail::return_normalized(p1); Point p2_normalized = detail::return_normalized(p2); @@ -286,25 +321,37 @@ struct envelope_segment_on_spheroid geometry::get_as_radian<0>(p2_normalized), geometry::get_as_radian<1>(p2_normalized), mbr); - } -}; -template -struct envelope_one_segment -{ - template - static inline void apply(Point const& p1, Point const& p2, Box& mbr) + // now compute the envelope range for coordinates of + // dimension 2 and higher + envelope_one_segment<2, DimensionCount>::apply(p1, p2, mbr); + } + + template + static inline void apply(Segment const& segment, Box& mbr) { - envelope_one_point::apply(p1, mbr); - geometry::expand(mbr, p2); + typename point_type::type p[2]; + detail::assign_point_from_index<0>(segment, p[0]); + detail::assign_point_from_index<1>(segment, p[1]); + apply(p[0], p[1], mbr); } }; -template <> -struct envelope_one_segment - : envelope_segment_on_spheroid + + +template +struct envelope_segment + : envelope_one_segment<0, DimensionCount> {}; + +template +struct envelope_segment + : envelope_segment_on_sphere +{}; + + + }} // namespace detail::envelope #endif // DOXYGEN_NO_DETAIL @@ -314,8 +361,8 @@ namespace dispatch { -template -struct envelope +template +struct envelope { template static inline void apply(Segment const& segment, Box& mbr) @@ -323,16 +370,16 @@ struct envelope typename point_type::type p[2]; detail::assign_point_from_index<0>(segment, p[0]); detail::assign_point_from_index<1>(segment, p[1]); - detail::envelope::envelope_one_segment + detail::envelope::envelope_segment < - typename cs_tag::type + dimension::value, CS_Tag >::apply(p[0], p[1], mbr); } }; } // namespace dispatch -#endif +#endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry diff --git a/include/boost/geometry/algorithms/detail/envelope/transform_units.hpp b/include/boost/geometry/algorithms/detail/envelope/transform_units.hpp new file mode 100644 index 000000000..0c5382a47 --- /dev/null +++ b/include/boost/geometry/algorithms/detail/envelope/transform_units.hpp @@ -0,0 +1,103 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2015, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Distributed under 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) + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_TRANSFORM_UNITS_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_TRANSFORM_UNITS_HPP + +#include + +#include +#include + +#include + +#include +#include + +#include +#include + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace envelope +{ + + +template +< + typename GeometryIn, + typename GeometryOut, + typename TagIn = typename tag::type, + typename TagOut = typename tag::type +> +struct transform_units_impl + : not_implemented +{}; + +template +struct transform_units_impl +{ + static inline void apply(PointIn const& point_in, PointOut& point_out) + { + detail::two_dimensional_view view_in(point_in); + detail::two_dimensional_view view_out(point_out); + + geometry::transform(view_in, view_out); + } +}; + +template +struct transform_units_impl +{ + template + static inline void apply(BoxIn const& box_in, BoxOut& box_out) + { + typedef detail::indexed_point_view view_in_type; + typedef detail::indexed_point_view view_out_type; + + view_in_type view_in(box_in); + view_out_type view_out(box_out); + + transform_units_impl + < + view_in_type, view_out_type + >::apply(view_in, view_out); + } + + static inline void apply(BoxIn const& box_in, BoxOut& box_out) + { + apply(box_in, box_out); + apply(box_in, box_out); + } +}; + + +// Short utility to transform the units of the first two coordinates of +// geometry_in to the units of geometry_out +template +inline void transform_units(GeometryIn const& geometry_in, + GeometryOut& geometry_out) +{ + transform_units_impl + < + GeometryIn, GeometryOut + >::apply(geometry_in, geometry_out); +}; + + +}} // namespace detail::envelope +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost:geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_TRANSFORM_UNITS_HPP diff --git a/include/boost/geometry/algorithms/detail/expand/box.hpp b/include/boost/geometry/algorithms/detail/expand/box.hpp index 94ea10d50..4c89e6f1d 100644 --- a/include/boost/geometry/algorithms/detail/expand/box.hpp +++ b/include/boost/geometry/algorithms/detail/expand/box.hpp @@ -10,24 +10,27 @@ // Contributed and/or modified by Menelaos Karavelas, 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. - -// Use, modification and distribution is subject to the Boost Software License, -// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// Distributed under 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) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_BOX_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_BOX_HPP +#include #include -#include +#include +#include + +#include #include #include #include + #include + #include @@ -72,10 +75,19 @@ template > struct expand < - BoxOut, BoxIn, StrategyLess, StrategyGreater, - box_tag, box_tag, CSTagOut, CSTag - > : detail::expand::expand_indexed -{}; + BoxOut, BoxIn, + StrategyLess, StrategyGreater, + box_tag, box_tag, + CSTagOut, CSTag + > : detail::expand::expand_indexed + < + 0, dimension::value, StrategyLess, StrategyGreater + > +{ + BOOST_MPL_ASSERT_MSG((boost::is_same::value), + COORDINATE_SYSTEMS_MUST_BE_THE_SAME, + (types())); +}; template < @@ -84,8 +96,10 @@ template > struct expand < - BoxOut, BoxIn, StrategyLess, StrategyGreater, - box_tag, box_tag, spherical_equatorial_tag, spherical_equatorial_tag + BoxOut, BoxIn, + StrategyLess, StrategyGreater, + box_tag, box_tag, + spherical_equatorial_tag, spherical_equatorial_tag > : detail::expand::box_on_spheroid {}; @@ -96,8 +110,10 @@ template > struct expand < - BoxOut, BoxIn, StrategyLess, StrategyGreater, - box_tag, box_tag, geographic_tag, geographic_tag + BoxOut, BoxIn, + StrategyLess, StrategyGreater, + box_tag, box_tag, + geographic_tag, geographic_tag > : detail::expand::box_on_spheroid {}; diff --git a/include/boost/geometry/algorithms/detail/expand/implementation.hpp b/include/boost/geometry/algorithms/detail/expand/implementation.hpp index c48f2e681..95de1b504 100644 --- a/include/boost/geometry/algorithms/detail/expand/implementation.hpp +++ b/include/boost/geometry/algorithms/detail/expand/implementation.hpp @@ -13,8 +13,8 @@ // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. -// Use, modification and distribution is subject to the Boost Software License, -// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// Distributed under 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) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_IMPLEMENTATION_HPP diff --git a/include/boost/geometry/algorithms/detail/expand/indexed.hpp b/include/boost/geometry/algorithms/detail/expand/indexed.hpp index 10b85b183..bdd6eb450 100644 --- a/include/boost/geometry/algorithms/detail/expand/indexed.hpp +++ b/include/boost/geometry/algorithms/detail/expand/indexed.hpp @@ -13,8 +13,8 @@ // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. -// Use, modification and distribution is subject to the Boost Software License, -// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// Distributed under 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) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_INDEXED_HPP @@ -23,7 +23,6 @@ #include #include -#include #include #include @@ -113,6 +112,7 @@ struct indexed_loop // Changes a box such that the other box is also contained by the box template < + std::size_t Dimension, std::size_t DimensionCount, typename StrategyLess, typename StrategyGreater > struct expand_indexed @@ -123,13 +123,13 @@ struct expand_indexed indexed_loop < StrategyLess, StrategyGreater, - 0, 0, dimension::type::value + 0, Dimension, DimensionCount >::apply(box, geometry); indexed_loop < StrategyLess, StrategyGreater, - 1, 0, dimension::type::value + 1, Dimension, DimensionCount >::apply(box, geometry); } }; diff --git a/include/boost/geometry/algorithms/detail/expand/interface.hpp b/include/boost/geometry/algorithms/detail/expand/interface.hpp index 3064f1236..01936387a 100644 --- a/include/boost/geometry/algorithms/detail/expand/interface.hpp +++ b/include/boost/geometry/algorithms/detail/expand/interface.hpp @@ -13,8 +13,8 @@ // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. -// Use, modification and distribution is subject to the Boost Software License, -// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// Distributed under 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) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_INTERFACE_HPP diff --git a/include/boost/geometry/algorithms/detail/expand/point.hpp b/include/boost/geometry/algorithms/detail/expand/point.hpp index a510e37ed..56b7f1c73 100644 --- a/include/boost/geometry/algorithms/detail/expand/point.hpp +++ b/include/boost/geometry/algorithms/detail/expand/point.hpp @@ -13,8 +13,8 @@ // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. -// Use, modification and distribution is subject to the Boost Software License, -// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// Distributed under 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) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_POINT_HPP @@ -23,6 +23,9 @@ #include #include +#include +#include + #include #include #include @@ -33,14 +36,10 @@ #include #include -#include #include -#include -#include - #include -#include +#include #include @@ -53,11 +52,81 @@ namespace detail { namespace expand { -struct point_on_spheroid +template +< + typename StrategyLess, typename StrategyGreater, + std::size_t Dimension, std::size_t DimensionCount +> +struct point_loop +{ + template + static inline void apply(Box& box, Point const& source) + { + typedef typename strategy::compare::detail::select_strategy + < + StrategyLess, 1, Point, Dimension + >::type less_type; + + typedef typename strategy::compare::detail::select_strategy + < + StrategyGreater, -1, Point, Dimension + >::type greater_type; + + typedef typename select_coordinate_type + < + Point, Box + >::type coordinate_type; + + less_type less; + greater_type greater; + + coordinate_type const coord = get(source); + + if (less(coord, get(box))) + { + set(box, coord); + } + + if (greater(coord, get(box))) + { + set(box, coord); + } + + point_loop + < + StrategyLess, StrategyGreater, Dimension + 1, DimensionCount + >::apply(box, source); + } +}; + + +template +< + typename StrategyLess, typename StrategyGreater, std::size_t DimensionCount +> +struct point_loop + < + StrategyLess, StrategyGreater, DimensionCount, DimensionCount + > +{ + template + static inline void apply(Box&, Point const&) {} +}; + + +// implementation for the spherical equatorial and geographic coordinate systems +template +< + typename StrategyLess, + typename StrategyGreater, + std::size_t DimensionCount +> +struct point_loop_on_spheroid { template static inline void apply(Box& box, Point const& point) { + typedef typename point_type::type box_point_type; typedef typename coordinate_type::type box_coordinate_type; typedef math::detail::constants_on_spheroid @@ -70,9 +139,9 @@ struct point_on_spheroid Point p_normalized = detail::return_normalized(point); detail::normalize(box, box); - // transform input point to be the same type as the box point - typename point_type::type box_point; - geometry::transform(p_normalized, box_point); + // transform input point to be of the same type as the box point + box_point_type box_point; + detail::envelope::transform_units(p_normalized, box_point); box_coordinate_type p_lon = geometry::get<0>(box_point); box_coordinate_type p_lat = geometry::get<1>(box_point); @@ -89,11 +158,8 @@ struct point_on_spheroid // south pole; the only important coordinate here is the // pole's latitude, as the longitude can be anything; // we, thus, take into account the point's latitude only and return - assign_values(box, - b_lon_min, - (std::min)(p_lat, b_lat_min), - b_lon_max, - (std::max)(p_lat, b_lat_max)); + geometry::set(box, (std::min)(p_lat, b_lat_min)); + geometry::set(box, (std::max)(p_lat, b_lat_max)); return; } @@ -104,11 +170,10 @@ struct point_on_spheroid // the only important coordinate here is the pole's latitude, // as the longitude can be anything; // we thus take into account the box's latitude only and return - assign_values(box, - p_lon, - (std::min)(p_lat, b_lat_min), - p_lon, - (std::max)(p_lat, b_lat_max)); + geometry::set(box, p_lon); + geometry::set(box, (std::min)(p_lat, b_lat_min)); + geometry::set(box, p_lon); + geometry::set(box, (std::max)(p_lat, b_lat_max)); return; } @@ -151,71 +216,19 @@ struct point_on_spheroid } } - assign_values(box, b_lon_min, b_lat_min, b_lon_max, b_lat_max); - } -}; - - -template -< - typename StrategyLess, typename StrategyGreater, - std::size_t Dimension, std::size_t DimensionCount -> -struct point_loop -{ - template - static inline void apply(Box& box, Point const& source) - { - typedef typename strategy::compare::detail::select_strategy - < - StrategyLess, 1, Point, Dimension - >::type less_type; - - typedef typename strategy::compare::detail::select_strategy - < - StrategyGreater, -1, Point, Dimension - >::type greater_type; - - typedef typename select_coordinate_type::type coordinate_type; - - less_type less; - greater_type greater; - - coordinate_type const coord = get(source); - - if (less(coord, get(box))) - { - set(box, coord); - } - - if (greater(coord, get(box))) - { - set(box, coord); - } + geometry::set(box, b_lon_min); + geometry::set(box, b_lat_min); + geometry::set(box, b_lon_max); + geometry::set(box, b_lat_max); point_loop < - StrategyLess, StrategyGreater, - Dimension + 1, DimensionCount - >::apply(box, source); + StrategyLess, StrategyGreater, 2, DimensionCount + >::apply(box, point); } }; -template -< - typename StrategyLess, typename StrategyGreater, std::size_t DimensionCount -> -struct point_loop - < - StrategyLess, StrategyGreater, DimensionCount, DimensionCount - > -{ - template - static inline void apply(Box&, Point const&) {} -}; - - }} // namespace detail::expand #endif // DOXYGEN_NO_DETAIL @@ -223,6 +236,7 @@ struct point_loop namespace dispatch { + // Box + point -> new box containing also point template < @@ -232,12 +246,34 @@ template > struct expand < - BoxOut, Point, StrategyLess, StrategyGreater, - box_tag, point_tag, CSTagOut, CSTag + BoxOut, Point, + StrategyLess, StrategyGreater, + box_tag, point_tag, + CSTagOut, CSTag > : detail::expand::point_loop < - StrategyLess, StrategyGreater, - 0, dimension::type::value + StrategyLess, StrategyGreater, 0, dimension::value + > +{ + BOOST_MPL_ASSERT_MSG((boost::is_same::value), + COORDINATE_SYSTEMS_MUST_BE_THE_SAME, + (types())); +}; + +template +< + typename BoxOut, typename Point, + typename StrategyLess, typename StrategyGreater +> +struct expand + < + BoxOut, Point, + StrategyLess, StrategyGreater, + box_tag, point_tag, + spherical_equatorial_tag, spherical_equatorial_tag + > : detail::expand::point_loop_on_spheroid + < + StrategyLess, StrategyGreater, dimension::value > {}; @@ -248,22 +284,16 @@ template > struct expand < - BoxOut, Point, StrategyLess, StrategyGreater, - box_tag, point_tag, spherical_equatorial_tag, spherical_equatorial_tag - > : detail::expand::point_on_spheroid + BoxOut, Point, + StrategyLess, StrategyGreater, + box_tag, point_tag, + geographic_tag, geographic_tag + > : detail::expand::point_loop_on_spheroid + < + StrategyLess, StrategyGreater, dimension::value + > {}; -template -< - typename BoxOut, typename Point, - typename StrategyLess, typename StrategyGreater -> -struct expand - < - BoxOut, Point, StrategyLess, StrategyGreater, - box_tag, point_tag, geographic_tag, geographic_tag - > : detail::expand::point_on_spheroid -{}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH diff --git a/include/boost/geometry/algorithms/detail/expand/segment.hpp b/include/boost/geometry/algorithms/detail/expand/segment.hpp index 917ab2002..041c1e175 100644 --- a/include/boost/geometry/algorithms/detail/expand/segment.hpp +++ b/include/boost/geometry/algorithms/detail/expand/segment.hpp @@ -10,21 +10,25 @@ // Contributed and/or modified by Menelaos Karavelas, 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. - -// Use, modification and distribution is subject to the Boost Software License, -// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// Distributed under 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) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_SEGMENT_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_SEGMENT_HPP +#include +#include + +#include #include +#include +#include #include -#include + #include + #include @@ -36,14 +40,24 @@ namespace detail { namespace expand { -struct segment_on_spheroid +struct segment_on_sphere { template static inline void apply(Box& box, Segment const& segment) { - Box segment_envelope; - dispatch::envelope::apply(segment, segment_envelope); - box_on_spheroid::apply(box, segment_envelope); + Box mbrs[2]; + + // compute the envelope of the segment + detail::envelope::envelope_segment_on_sphere + < + dimension::value + >::apply(segment, mbrs[0]); + + // normalize the box + detail::envelope::envelope_box_on_spheroid::apply(box, mbrs[1]); + + // compute the envelope of the two boxes + detail::envelope::envelope_range_of_boxes::apply(mbrs, box); } }; @@ -64,10 +78,19 @@ template > struct expand < - Box, Segment, StrategyLess, StrategyGreater, - box_tag, segment_tag, CSTagOut, CSTag - > : detail::expand::expand_indexed -{}; + Box, Segment, + StrategyLess, StrategyGreater, + box_tag, segment_tag, + CSTagOut, CSTag + > : detail::expand::expand_indexed + < + 0, dimension::value, StrategyLess, StrategyGreater + > +{ + BOOST_MPL_ASSERT_MSG((boost::is_same::value), + COORDINATE_SYSTEMS_MUST_BE_THE_SAME, + (types())); +}; template < @@ -76,10 +99,11 @@ template > struct expand < - Box, Segment, StrategyLess, StrategyGreater, + Box, Segment, + StrategyLess, StrategyGreater, box_tag, segment_tag, spherical_equatorial_tag, spherical_equatorial_tag - > : detail::expand::segment_on_spheroid + > : detail::expand::segment_on_sphere {}; diff --git a/include/boost/geometry/algorithms/detail/is_valid/has_spikes.hpp b/include/boost/geometry/algorithms/detail/is_valid/has_spikes.hpp index d12838de6..aa90e52db 100644 --- a/include/boost/geometry/algorithms/detail/is_valid/has_spikes.hpp +++ b/include/boost/geometry/algorithms/detail/is_valid/has_spikes.hpp @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -77,13 +78,24 @@ struct not_equal_to template struct has_spikes { + template + static inline Iterator find_different_from_first(Iterator first, + Iterator last) + { + typedef not_equal_to::type> not_equal; + + BOOST_GEOMETRY_ASSERT(first != last); + + Iterator second = first; + ++second; + return std::find_if(second, last, not_equal(*first)); + } + template static inline bool apply(Range const& range, VisitPolicy& visitor) { boost::ignore_unused(visitor); - typedef not_equal_to::type> not_equal; - typedef typename closeable_view::type view_type; typedef typename boost::range_iterator::type iterator; @@ -94,23 +106,23 @@ struct has_spikes iterator prev = boost::begin(view); - iterator cur = std::find_if(prev, boost::end(view), not_equal(*prev)); - if ( cur == boost::end(view) ) + iterator cur = find_different_from_first(prev, boost::end(view)); + if (cur == boost::end(view)) { // the range has only one distinct point, so it // cannot have a spike return ! visitor.template apply(); } - iterator next = std::find_if(cur, boost::end(view), not_equal(*cur)); - if ( next == boost::end(view) ) + iterator next = find_different_from_first(cur, boost::end(view)); + if (next == boost::end(view)) { // the range has only two distinct points, so it // cannot have a spike return ! visitor.template apply(); } - while ( next != boost::end(view) ) + while (next != boost::end(view)) { if ( geometry::detail::point_is_spike_or_equal(*prev, *next, @@ -121,20 +133,19 @@ struct has_spikes } prev = cur; cur = next; - next = std::find_if(cur, boost::end(view), not_equal(*cur)); + next = find_different_from_first(cur, boost::end(view)); } - if ( geometry::equals(range::front(view), range::back(view)) ) + if (geometry::equals(range::front(view), range::back(view))) { iterator cur = boost::begin(view); typename boost::range_reverse_iterator < view_type const - >::type prev = std::find_if(boost::rbegin(view), - boost::rend(view), - not_equal(range::back(view))); - iterator next = - std::find_if(cur, boost::end(view), not_equal(*cur)); + >::type prev = find_different_from_first(boost::rbegin(view), + boost::rend(view)); + + iterator next = find_different_from_first(cur, boost::end(view)); if (detail::point_is_spike_or_equal(*prev, *next, *cur)) { return diff --git a/include/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp b/include/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp index e0d75108b..fdae07842 100644 --- a/include/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp @@ -217,7 +217,9 @@ public: : base_t(pi, pj, pk, qi, qj, qk, robust_policy) , m_result(strategy::apply(segment_type1(pi, pj), segment_type2(qi, qj), - robust_policy)) + robust_policy, + base_t::rpi(), base_t::rpj(), + base_t::rqi(), base_t::rqj())) , m_robust_policy(robust_policy) {} diff --git a/include/boost/geometry/algorithms/dispatch/envelope.hpp b/include/boost/geometry/algorithms/dispatch/envelope.hpp index 8b1324d72..bb8a99f5a 100644 --- a/include/boost/geometry/algorithms/dispatch/envelope.hpp +++ b/include/boost/geometry/algorithms/dispatch/envelope.hpp @@ -12,8 +12,8 @@ // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. -// Use, modification and distribution is subject to the Boost Software License, -// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// Distributed under 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) #ifndef BOOST_GEOMETRY_ALGORITHMS_DISPATCH_ENVELOPE_HPP @@ -36,7 +36,7 @@ template < typename Geometry, typename Tag = typename tag::type, - typename CSTag = typename cs_tag::type + typename CS_Tag = typename cs_tag::type > struct envelope : not_implemented {}; diff --git a/include/boost/geometry/algorithms/dispatch/expand.hpp b/include/boost/geometry/algorithms/dispatch/expand.hpp index e290080ac..2c23d6a1c 100644 --- a/include/boost/geometry/algorithms/dispatch/expand.hpp +++ b/include/boost/geometry/algorithms/dispatch/expand.hpp @@ -13,8 +13,8 @@ // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. -// Use, modification and distribution is subject to the Boost Software License, -// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// Distributed under 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) #ifndef BOOST_GEOMETRY_ALGORITHMS_DISPATCH_EXPAND_HPP diff --git a/include/boost/geometry/algorithms/envelope.hpp b/include/boost/geometry/algorithms/envelope.hpp index 2f5c7430b..00981224b 100644 --- a/include/boost/geometry/algorithms/envelope.hpp +++ b/include/boost/geometry/algorithms/envelope.hpp @@ -12,8 +12,8 @@ // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. -// Use, modification and distribution is subject to the Boost Software License, -// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// Distributed under 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) #ifndef BOOST_GEOMETRY_ALGORITHMS_ENVELOPE_HPP diff --git a/include/boost/geometry/algorithms/expand.hpp b/include/boost/geometry/algorithms/expand.hpp index 6b4820d8a..f41df5380 100644 --- a/include/boost/geometry/algorithms/expand.hpp +++ b/include/boost/geometry/algorithms/expand.hpp @@ -13,8 +13,8 @@ // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. -// Use, modification and distribution is subject to the Boost Software License, -// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// Distributed under 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) #ifndef BOOST_GEOMETRY_ALGORITHMS_EXPAND_HPP diff --git a/include/boost/geometry/strategies/cartesian/cart_intersect.hpp b/include/boost/geometry/strategies/cartesian/cart_intersect.hpp index 4b3010a40..8a9857376 100644 --- a/include/boost/geometry/strategies/cartesian/cart_intersect.hpp +++ b/include/boost/geometry/strategies/cartesian/cart_intersect.hpp @@ -119,15 +119,10 @@ struct relate_cartesian_segments boost::ignore_unused_variable_warning(robust_policy); - typedef typename select_calculation_type - ::type coordinate_type; - using geometry::detail::equals::equals_point_point; bool const a_is_point = equals_point_point(robust_a1, robust_a2); bool const b_is_point = equals_point_point(robust_b1, robust_b2); - typedef side::side_by_triangle side; - if(a_is_point && b_is_point) { return equals_point_point(robust_a1, robust_b2) @@ -136,20 +131,32 @@ struct relate_cartesian_segments ; } + typedef typename select_calculation_type + ::type coordinate_type; + + typedef side::side_by_triangle side; + side_info sides; sides.set<0>(side::apply(robust_b1, robust_b2, robust_a1), side::apply(robust_b1, robust_b2, robust_a2)); - sides.set<1>(side::apply(robust_a1, robust_a2, robust_b1), - side::apply(robust_a1, robust_a2, robust_b2)); - bool collinear = sides.collinear(); - - if (sides.same<0>() || sides.same<1>()) + if (sides.same<0>()) { // Both points are at same side of other segment, we can leave return Policy::disjoint(); } + sides.set<1>(side::apply(robust_a1, robust_a2, robust_b1), + side::apply(robust_a1, robust_a2, robust_b2)); + + if (sides.same<1>()) + { + // Both points are at same side of other segment, we can leave + return Policy::disjoint(); + } + + bool collinear = sides.collinear(); + typedef typename select_most_precise < coordinate_type, double diff --git a/include/boost/geometry/views/detail/two_dimensional_view.hpp b/include/boost/geometry/views/detail/two_dimensional_view.hpp new file mode 100644 index 000000000..b33ede8e1 --- /dev/null +++ b/include/boost/geometry/views/detail/two_dimensional_view.hpp @@ -0,0 +1,194 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2015, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_VIEWS_DETAIL_TWO_DIMENSIONAL_VIEW_HPP +#define BOOST_GEOMETRY_VIEWS_DETAIL_TWO_DIMENSIONAL_VIEW_HPP + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +template +< + typename Geometry, + std::size_t Dimension1 = 0, + std::size_t Dimension2 = 1, + typename Tag = typename tag::type +> +struct two_dimensional_view + : not_implemented +{}; + + +// View that enables to choose two dimensions of a point and see it as +// a two-dimensional point +template +struct two_dimensional_view +{ + BOOST_MPL_ASSERT_MSG((Dimension1 < dimension::value), + COORDINATE_DIMENSION1_IS_LARGER_THAN_POINT_DIMENSION, + (boost::mpl::int_)); + + BOOST_MPL_ASSERT_MSG((Dimension2 < dimension::value), + COORDINATE_DIMENSION2_IS_LARGER_THAN_POINT_DIMENSION, + (boost::mpl::int_)); + + two_dimensional_view(Point& point) + : m_point(point) + {} + + Point& m_point; +}; + + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS +namespace traits +{ + + +template +struct tag + < + geometry::detail::two_dimensional_view + < + Point, Dimension1, Dimension2, point_tag + > + > +{ + typedef point_tag type; +}; + +template +struct coordinate_system + < + geometry::detail::two_dimensional_view + < + Point, Dimension1, Dimension2, point_tag + > + > : coordinate_system::type> +{}; + +template +struct coordinate_type + < + geometry::detail::two_dimensional_view + < + Point, Dimension1, Dimension2, point_tag + > + > : coordinate_type::type> +{}; + +template +struct dimension + < + geometry::detail::two_dimensional_view + < + Point, Dimension1, Dimension2, point_tag + > + > : boost::mpl::int_<2> +{}; + +template +struct point_type + < + geometry::detail::two_dimensional_view + < + Point, Dimension1, Dimension2, point_tag + > + > +{ + typedef typename geometry::point_type::type type; +}; + + +template +struct access + < + geometry::detail::two_dimensional_view + < + Point, Dimension1, Dimension2, point_tag + >, + 0 + > +{ + typedef typename geometry::coordinate_type::type coordinate_type; + typedef geometry::detail::two_dimensional_view + < + Point, Dimension1, Dimension2, point_tag + > view_type; + + static inline coordinate_type get(view_type const& view) + { + return geometry::get(view.m_point); + } + + static inline void set(view_type& view, coordinate_type const& value) + { + geometry::set(view.m_point, value); + } +}; + +template +struct access + < + geometry::detail::two_dimensional_view + < + Point, Dimension1, Dimension2, point_tag + >, + 1 + > +{ + typedef typename geometry::coordinate_type::type coordinate_type; + typedef geometry::detail::two_dimensional_view + < + Point, Dimension1, Dimension2, point_tag + > view_type; + + static inline coordinate_type get(view_type const& view) + { + return geometry::get(view.m_point); + } + + static inline void set(view_type& view, coordinate_type const& value) + { + geometry::set(view.m_point, value); + } +}; + + +} // namespace traits +#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_VIEWS_DETAIL_TWO_DIMENSIONAL_VIEW_HPP diff --git a/test/algorithms/envelope.cpp b/test/algorithms/envelope.cpp index 92d69e8ac..1cb989786 100644 --- a/test/algorithms/envelope.cpp +++ b/test/algorithms/envelope.cpp @@ -1,9 +1,14 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // Unit Test -// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. -// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2015 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2015 Mateusz Loskot, London, UK. + +// This file was modified by Oracle on 2015. +// Modifications copyright (c) 2015, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, 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. @@ -12,6 +17,7 @@ // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +#include #include @@ -57,6 +63,144 @@ void test_3d() test_envelope >("BOX(1 1 1,3 3 3)", 1, 3, 1, 3, 1, 3); } +template +void test_empty_geometry(std::string const& wkt) +{ + typedef typename bg::coordinate_type::type ct; + ct high_val = boost::numeric::bounds::highest(); + ct low_val = boost::numeric::bounds::lowest(); + + test_envelope(wkt, high_val, low_val, high_val, low_val); +} + +template +void test_empty() +{ + test_empty_geometry >("LINESTRING()"); + test_empty_geometry >("POLYGON(())"); + + test_empty_geometry >("POLYGON(())"); + + test_empty_geometry >("MULTIPOINT()"); + + test_empty_geometry + < + bg::model::multi_linestring > + >("MULTILINESTRING()"); + + test_empty_geometry + < + bg::model::multi_polygon > + >("MULTIPOLYGON()"); +} + +template +void test_invalid() +{ + // polygon with empty exterior and interior rings + test_empty_geometry >("POLYGON((),(),())"); + + // polygon with empty interior rings + test_envelope + < + bg::model::polygon

+ >("POLYGON((1 2,1 20,22 20,22 2,1 2),(),())", + 1, 22, 2, 20); + + // another polygon with empty interior rings + test_envelope + < + bg::model::polygon

+ >("POLYGON((1 2,1 20,22 20,22 2,1 2),(),(3 4,19 4,19 18,3 18,3 4),())", + 1, 22, 2, 20); + + // polygon with empty exterior ring + test_envelope + < + bg::model::polygon

+ >("POLYGON((),(),(3 4,19 4,19 18,3 18,3 4),())", + 3, 19, 4, 18); + + // another polygon with empty exterior ring + test_envelope + < + bg::model::polygon

+ >("POLYGON((),(),(3 4,19 4,19 18,3 18,3 4),(4 5,18 5,18 17,4 17,4 5))", + 3, 19, 4, 18); + + // yet one more polygon with empty exterior ring + test_envelope + < + bg::model::polygon

+ >("POLYGON((),(),(4 5,18 5,18 17,4 17,4 5),(3 4,19 4,19 18,3 18,3 4))", + 3, 19, 4, 18); + + // multilinestring with empty linestrings + test_empty_geometry + < + bg::model::multi_linestring > + >("MULTILINESTRING((),(),())"); + + // multilinestring with empty and non-empty linestrings + test_envelope + < + bg::model::multi_linestring > + >("MULTILINESTRING((),(10 20),())", 10, 10, 20, 20); + + // multipolygon with empty polygon + test_empty_geometry + < + bg::model::multi_polygon > + >("MULTIPOLYGON((()))"); + + // multipolygon with many empty polygons + test_empty_geometry + < + bg::model::multi_polygon > + >("MULTIPOLYGON(((),(),()),(()),((),(),(),(),()))"); + + // multipolygon with empty polygons and non-empty (valid) polygon + test_envelope + < + bg::model::multi_polygon > + >("MULTIPOLYGON(((),(),()),((10 30,10 40,20 30,10 30)),\ + ((),(),()),(()))", 10, 20, 30, 40); + + // multipolygon with empty polygons and non-empty (valid) polygon + // that has an interior ring + test_envelope + < + bg::model::multi_polygon > + >("MULTIPOLYGON(((),(),()),(()),\ + ((1 2,1 20,22 20,22 2,1 2),(3 4,19 4,19 18,3 18,3 4)),(()))", + 1, 22, 2, 20); + + // multipolygon with empty polygons and non-empty (invalid) polygon + // that has an interior ring but empty exterior ring + test_envelope + < + bg::model::multi_polygon > + >("MULTIPOLYGON(((),(),()),(()),((),(3 4,19 4,19 18,3 18,3 4)),(()))", + 3, 19, 4, 18); + + // multipolygon with empty polygons and non-empty (invalid) polygon + // that has an interior ring but empty exterior ring + test_envelope + < + bg::model::multi_polygon > + >("MULTIPOLYGON(((),(),()),((),(),(3 4,19 4,19 18,3 18,3 4),()),(()))", + 3, 19, 4, 18); + + // multipolygon with empty polygons and non-empty (invalid) polygon + // that has two non-empty interior rings but empty exterior ring + test_envelope + < + bg::model::multi_polygon > + >("MULTIPOLYGON(((),(),()),\ + ((),(),(3 4,19 4,19 18,3 18,3 4),(4 5,18 5,18 17,4 17,4 5),()),\ + (()))", + 3, 19, 4, 18); +} int test_main(int, char* []) { @@ -71,6 +215,16 @@ int test_main(int, char* []) test_3d(); test_3d >(); + test_empty >(); + test_empty >(); + test_empty >(); + test_empty >(); + + test_invalid >(); + test_invalid >(); + test_invalid >(); + test_invalid >(); + #ifdef HAVE_TTMATH test_2d >(); test_3d >(); diff --git a/test/algorithms/envelope_on_spheroid.cpp b/test/algorithms/envelope_on_spheroid.cpp index 3938418ed..182c0bffc 100644 --- a/test/algorithms/envelope_on_spheroid.cpp +++ b/test/algorithms/envelope_on_spheroid.cpp @@ -15,6 +15,7 @@ #include +#include #include #include #include @@ -22,8 +23,10 @@ #include #include +#include #include +#include #include #include @@ -38,125 +41,53 @@ #include #include - -typedef bg::cs::spherical_equatorial se_rad_type; -typedef bg::cs::spherical_equatorial se_deg_type; - -typedef bg::model::point rad_point_type; -typedef bg::model::point deg_point_type; - -typedef bg::model::multi_point rad_multipoint_type; -typedef bg::model::multi_point deg_multipoint_type; - -typedef bg::model::segment rad_segment_type; -typedef bg::model::segment deg_segment_type; - -typedef bg::model::box rad_box_type; -typedef bg::model::box deg_box_type; - -typedef bg::model::linestring rad_linestring_type; -typedef bg::model::linestring deg_linestring_type; - -typedef bg::model::multi_linestring - < - rad_linestring_type - > rad_multilinestring_type; - -typedef bg::model::multi_linestring - < - deg_linestring_type - > deg_multilinestring_type; - - -typedef bg::model::ring rad_cw_ring_type; -typedef bg::model::ring deg_cw_ring_type; - -typedef bg::model::ring rad_ccw_ring_type; -typedef bg::model::ring deg_ccw_ring_type; - - -template -char const* units2string() -{ - if (BOOST_GEOMETRY_CONDITION((boost::is_same::value))) - { - return "degrees"; - } - return "radians"; -} - -template -struct other_system_info -{ - typedef bg::degree units; - typedef bg::cs::spherical_equatorial type; - - template - static inline T convert(T const& value) - { - return value * bg::math::r2d(); - } -}; - -template <> -struct other_system_info -{ - typedef bg::radian units; - typedef bg::cs::spherical_equatorial type; - - template - static inline T convert(T const& value) - { - return value * bg::math::d2r(); - } -}; - - -class equals_with_tolerance -{ -private: - double m_tolerance; - - template - static inline T const& get_max(T const& a, T const& b, T const& c) - { - return (std::max)((std::max)(a, b), c); - } - - template - static inline bool check_close(T const& a, T const& b, double tol) - { - return (a == b) - || (std::abs(a - b) <= tol * get_max(std::abs(a), std::abs(b), 1.0)); - } - -public: - equals_with_tolerance(double tolerance) : m_tolerance(tolerance) {} - - template - inline bool operator()(T const& value1, T const& value2) const - { - return check_close(value1, value2, m_tolerance); - } -}; - - -template -inline bool box_equals(Box1 const& box1, Box2 const& box2, double tol) -{ - equals_with_tolerance equals(tol); - - return equals(bg::get<0, 0>(box1), bg::get<0, 0>(box2)) - && equals(bg::get<0, 1>(box1), bg::get<0, 1>(box2)) - && equals(bg::get<1, 0>(box1), bg::get<1, 0>(box2)) - && equals(bg::get<1, 1>(box1), bg::get<1, 1>(box2)); -} +#include "test_envelope_expand_on_spheroid.hpp" template class envelope_on_spheroid_basic_tester { private: + template + < + typename Geometry, + typename Tag = typename bg::tag::type + > + struct write_geometry + { + template + static inline OutputStream& apply(OutputStream& os, + Geometry const& geometry) + { + os << bg::wkt(geometry); + return os; + } + }; + + template + struct write_geometry + { + template + static inline OutputStream& apply(OutputStream& os, + Segment const& segment) + { + os << "SEGMENT" << bg::dsv(segment); + return os; + } + }; + + template + struct write_geometry + { + template + static inline OutputStream& apply(OutputStream& os, + Box const& box) + { + os << "BOX" << bg::dsv(box); + return os; + } + }; + template static inline void check_message(bool same_boxes, std::string const& case_id, @@ -165,33 +96,12 @@ private: Box const& expected, Box const& detected) { - bool const is_box = boost::is_same - < - typename bg::tag::type, bg::box_tag - >::value; - - bool const is_segment = boost::is_same - < - typename bg::tag::type, bg::segment_tag - >::value; - std::ostringstream stream; stream << "case ID: " << case_id << ", " << "MBR units: " << units_str << "; " << "geometry: "; - if (BOOST_GEOMETRY_CONDITION(is_box)) - { - stream << "BOX" << bg::dsv(geometry); - } - else if (BOOST_GEOMETRY_CONDITION(is_segment)) - { - stream << "SEGMENT" << bg::dsv(geometry); - } - else - { - stream << bg::wkt(geometry); - } + write_geometry::apply(stream, geometry); stream << "; " << "expected: " << bg::dsv(expected) << ", " << "detected: " << bg::dsv(detected); @@ -202,8 +112,8 @@ private: template static inline void base_test(std::string const& case_id, Geometry const& geometry, - double lon_min, double lat_min, - double lon_max, double lat_max, + double lon_min, double lat_min, double height_min, + double lon_max, double lat_max, double height_max, double tolerance) { typedef typename bg::coordinate_system::type::units box_units_type; @@ -214,32 +124,13 @@ private: bg::envelope(geometry, detected); Box expected; - bg::assign_values(expected, lon_min, lat_min, lon_max, lat_max); + initialize_box::apply(expected, + lon_min, lat_min, height_min, + lon_max, lat_max, height_max); #ifdef BOOST_GEOMETRY_TEST_DEBUG - bool const is_box = boost::is_same - < - typename bg::tag::type, bg::box_tag - >::value; - - bool const is_segment = boost::is_same - < - typename bg::tag::type, bg::segment_tag - >::value; - std::cout << "geometry: "; - if (BOOST_GEOMETRY_CONDITION(is_box)) - { - std::cout << "BOX" << bg::dsv(geometry); - } - else if(BOOST_GEOMETRY_CONDITION(is_segment)) - { - std::cout << "SEGMENT" << bg::dsv(geometry); - } - else - { - std::cout << bg::wkt(geometry); - } + write_geometry::apply(std::cout, geometry); std::cout << std::endl << "MBR units: " << units_str @@ -250,7 +141,7 @@ private: << std::endl << std::endl; #endif - check_message(box_equals(detected, expected, tolerance), + check_message(box_equals::apply(detected, expected, tolerance), case_id, units_str, geometry, expected, detected); } @@ -259,13 +150,13 @@ public: template static inline void apply(std::string const& case_id, Geometry const& geometry, - double lon_min, double lat_min, - double lon_max, double lat_max, + double lon_min, double lat_min, double height_min, + double lon_max, double lat_max, double height_max, double tolerance) { typedef other_system_info < - typename bg::coordinate_system::type::units + typename bg::coordinate_system::type > other; typedef bg::model::box @@ -273,7 +164,7 @@ public: bg::model::point < typename bg::coordinate_type::type, - 2, + bg::dimension::value, typename other::type > > other_mbr_type; @@ -284,15 +175,30 @@ public: #endif base_test(case_id, geometry, - lon_min, lat_min, lon_max, lat_max, + lon_min, lat_min, height_min, + lon_max, lat_max, height_max, tolerance); - base_test(case_id, geometry, - other::convert(lon_min), - other::convert(lat_min), - other::convert(lon_max), - other::convert(lat_max), - tolerance); + if (lon_max < lon_min) + { + // we are in the case were a special MBR is returned; + // makes no sense to change units + base_test(case_id, geometry, + lon_min, lat_min, height_min, + lon_max, lat_max, height_max, + tolerance); + } + else + { + base_test(case_id, geometry, + other::convert(lon_min), + other::convert(lat_min), + height_min, + other::convert(lon_max), + other::convert(lat_max), + height_max, + tolerance); + } } }; @@ -331,17 +237,18 @@ struct test_envelope_on_spheroid { static inline void apply(std::string const& case_id, Geometry const& geometry, - double lon_min1, double lat_min1, - double lon_max1, double lat_max1, - double lon_min2, double lat_min2, - double lon_max2, double lat_max2, + double lon_min1, double lat_min1, double height_min1, + double lon_max1, double lat_max1, double height_max1, + double lon_min2, double lat_min2, double height_min2, + double lon_max2, double lat_max2, double height_max2, double tolerance = std::numeric_limits::epsilon()) { envelope_on_spheroid_basic_tester < MBR >::apply(case_id, geometry, - lon_min1, lat_min1, lon_max1, lat_max1, + lon_min1, lat_min1, height_min1, + lon_max1, lat_max1, height_max1, tolerance); if (BOOST_GEOMETRY_CONDITION(TestReverse)) @@ -354,7 +261,8 @@ struct test_envelope_on_spheroid < MBR >::apply(reversed_case_id, reversed_geometry, - lon_min2, lat_min2, lon_max2, lat_max2, + lon_min2, lat_min2, height_min2, + lon_max2, lat_max2, height_max2, tolerance); } @@ -364,6 +272,34 @@ struct test_envelope_on_spheroid #endif } + static inline void apply(std::string const& case_id, + Geometry const& geometry, + double lon_min1, double lat_min1, + double lon_max1, double lat_max1, + double lon_min2, double lat_min2, + double lon_max2, double lat_max2, + double tolerance = std::numeric_limits::epsilon()) + { + apply(case_id, geometry, + lon_min1, lat_min1, 0, lon_max1, lat_max1, 0, + lon_min2, lat_min2, 0, lon_max2, lat_max2, 0, + tolerance); + } + + static inline void apply(std::string const& case_id, + Geometry const& geometry, + double lon_min, double lat_min, double height_min, + double lon_max, double lat_max, double height_max, + double tolerance = std::numeric_limits::epsilon()) + { + apply(case_id, geometry, + lon_min, lat_min, height_min, + lon_max, lat_max, height_max, + lon_min, lat_min, height_min, + lon_max, lat_max, height_max, + tolerance); + } + static inline void apply(std::string const& case_id, Geometry const& geometry, double lon_min, double lat_min, @@ -371,8 +307,7 @@ struct test_envelope_on_spheroid double tolerance = std::numeric_limits::epsilon()) { apply(case_id, geometry, - lon_min, lat_min, lon_max, lat_max, - lon_min, lat_min, lon_max, lat_max, + lon_min, lat_min, 0, lon_max, lat_max, 0, tolerance); } }; @@ -399,7 +334,10 @@ struct test_envelope_on_spheroid std::string ccw_case_id = case_id + "-2ccw"; - deg_ccw_ring_type ccw_ring; + bg::model::ring + < + typename bg::point_type::type, false + > ccw_ring; bg::convert(geometry, ccw_ring); envelope_on_spheroid_basic_tester @@ -429,10 +367,41 @@ struct test_envelope_on_spheroid }; -BOOST_AUTO_TEST_CASE( envelope_point ) +template +void test_empty_geometry(std::string const& case_id, std::string const& wkt) { - typedef deg_point_type G; - typedef test_envelope_on_spheroid tester; + std::size_t const dim = bg::dimension::value; + + typedef bg::model::point point_type; + typedef bg::model::box B; + typedef test_envelope_on_spheroid tester; + + typedef typename bg::coordinate_type::type ct; + ct high_val = boost::numeric::bounds::highest(); + ct low_val = boost::numeric::bounds::lowest(); + + if (BOOST_GEOMETRY_CONDITION(dim == 2)) + { + tester::apply(case_id, + from_wkt(wkt), + high_val, high_val, low_val, low_val); + } + else + { + tester::apply(case_id, + from_wkt(wkt), + high_val, high_val, high_val, low_val, low_val, low_val); + } +} + + +template +void test_envelope_point() +{ + typedef bg::model::point point_type; + typedef point_type G; + typedef bg::model::box B; + typedef test_envelope_on_spheroid tester; tester::apply("p01", from_wkt("POINT(10 10)"), @@ -506,11 +475,43 @@ BOOST_AUTO_TEST_CASE( envelope_point ) 0, -90, 0, -90); } +BOOST_AUTO_TEST_CASE( envelope_point ) +{ + test_envelope_point >(); + test_envelope_point >(); +} + + +template +void test_envelope_point_with_height() +{ + typedef bg::model::point point_type; + typedef point_type G; + typedef bg::model::box B; + typedef test_envelope_on_spheroid tester; + + tester::apply("ph01", + from_wkt("POINT(10 10 1256)"), + 10, 10, 1256, 10, 10, 1256); +} + +BOOST_AUTO_TEST_CASE( envelope_point_with_height ) +{ + test_envelope_point_with_height + < + bg::cs::spherical_equatorial + >(); + test_envelope_point_with_height >(); +} + BOOST_AUTO_TEST_CASE( envelope_segment ) { - typedef deg_segment_type G; - typedef test_envelope_on_spheroid tester; + typedef bg::cs::spherical_equatorial coordinate_system_type; + typedef bg::model::point point_type; + typedef bg::model::segment G; + typedef bg::model::box B; + typedef test_envelope_on_spheroid tester; tester::apply("s01", from_wkt("SEGMENT(10 10,40 40)"), @@ -661,10 +662,34 @@ BOOST_AUTO_TEST_CASE( envelope_segment ) } -BOOST_AUTO_TEST_CASE( envelope_multipoint ) +BOOST_AUTO_TEST_CASE( envelope_segment_with_height ) { - typedef deg_multipoint_type G; - typedef test_envelope_on_spheroid tester; + typedef bg::cs::spherical_equatorial coordinate_system_type; + typedef bg::model::point point_type; + typedef bg::model::segment G; + typedef bg::model::box B; + typedef test_envelope_on_spheroid tester; + + tester::apply("sh01", + from_wkt("SEGMENT(10 10 567,40 40 1356)"), + 10, 10, 567, 40, 40, 1356); + + tester::apply("sh02", + from_wkt("SEGMENT(10 10 1356,40 40 567)"), + 10, 10, 567, 40, 40, 1356); +} + + +template +void test_envelope_multipoint() +{ + typedef bg::model::point point_type; + typedef bg::model::multi_point G; + typedef bg::model::box B; + typedef test_envelope_on_spheroid tester; + + // empty multipoint + test_empty_geometry("mp00", "MULTIPOINT()"); tester::apply("mp01", from_wkt("MULTIPOINT(0 0,10 10)"), @@ -791,11 +816,51 @@ BOOST_AUTO_TEST_CASE( envelope_multipoint ) #endif } - -BOOST_AUTO_TEST_CASE( envelope_box ) +BOOST_AUTO_TEST_CASE( envelope_multipoint ) { - typedef deg_box_type G; - typedef test_envelope_on_spheroid tester; + test_envelope_multipoint >(); + test_envelope_multipoint >(); +} + + +template +void test_envelope_multipoint_with_height() +{ + typedef bg::model::point point_type; + typedef bg::model::multi_point G; + typedef bg::model::box B; + typedef test_envelope_on_spheroid tester; + + // empty multipoint + test_empty_geometry("mph00", "MULTIPOINT()"); + + tester::apply("mph01", + from_wkt("MULTIPOINT(0 0 567,10 10 1456)"), + 0, 0, 567, 10, 10, 1456); + + tester::apply("mph02", + from_wkt("MULTIPOINT(0 0 567,10 10 1456,20 90 967)"), + 0, 0, 567, 10, 90, 1456); +} + +BOOST_AUTO_TEST_CASE( envelope_multipoint_with_height ) +{ + test_envelope_multipoint_with_height + < + bg::cs::spherical_equatorial + >(); + test_envelope_multipoint_with_height >(); +} + + +template +void test_envelope_box() +{ + typedef bg::cs::spherical_equatorial coordinate_system_type; + typedef bg::model::point point_type; + typedef bg::model::box G; + typedef bg::model::box B; + typedef test_envelope_on_spheroid tester; tester::apply("b01", from_wkt("BOX(10 10,20 20)"), @@ -976,11 +1041,52 @@ BOOST_AUTO_TEST_CASE( envelope_box ) 0, -90, 0, -90); } +BOOST_AUTO_TEST_CASE( envelope_box ) +{ + test_envelope_box >(); + test_envelope_box >(); +} + + +template +void test_envelope_box_with_height() +{ + typedef bg::cs::spherical_equatorial coordinate_system_type; + typedef bg::model::point point_type; + typedef bg::model::box G; + typedef bg::model::box B; + typedef test_envelope_on_spheroid tester; + + tester::apply("bh01", + from_wkt("BOX(10 10 567,20 20 2834)"), + 10, 10, 567, 20, 20, 2834); + + tester::apply("bh02", + from_wkt("BOX(10 10 567,20 20 567)"), + 10, 10, 567, 20, 20, 567); + + tester::apply("bh03", + from_wkt("BOX(0 10 567,170 90 1567)"), + 0, 10, 567, 170, 90, 1567); +} + +BOOST_AUTO_TEST_CASE( envelope_box_with_height ) +{ + test_envelope_box_with_height >(); + test_envelope_box_with_height >(); +} + BOOST_AUTO_TEST_CASE( envelope_linestring ) { - typedef deg_linestring_type G; - typedef test_envelope_on_spheroid tester; + typedef bg::cs::spherical_equatorial coordinate_system_type; + typedef bg::model::point point_type; + typedef bg::model::linestring G; + typedef bg::model::box B; + typedef test_envelope_on_spheroid tester; + + // empty linestring + test_empty_geometry("l00", "LINESTRING()"); tester::apply("l01", from_wkt("LINESTRING(10 15)"), @@ -1086,14 +1192,61 @@ BOOST_AUTO_TEST_CASE( envelope_linestring ) } +BOOST_AUTO_TEST_CASE( envelope_linestring_with_height ) +{ + typedef bg::cs::spherical_equatorial coordinate_system_type; + typedef bg::model::point point_type; + typedef bg::model::linestring G; + typedef bg::model::box B; + typedef test_envelope_on_spheroid tester; + + // empty linestring + test_empty_geometry("lh00", "LINESTRING()"); + + tester::apply("lh01", + from_wkt("LINESTRING(10 15 30,20 25 434,30 35 186)"), + 10, 15, 30, 30, 35, 434); +} + + BOOST_AUTO_TEST_CASE( envelope_multilinestring ) { - typedef deg_multilinestring_type G; - typedef test_envelope_on_spheroid tester; + typedef bg::cs::spherical_equatorial coordinate_system_type; + typedef bg::model::point point_type; + typedef bg::model::multi_linestring > G; + typedef bg::model::box B; + typedef test_envelope_on_spheroid tester; + + // empty multilinestring + test_empty_geometry("ml00", "MULTILINESTRING()"); + + // invalid multilinestring + test_empty_geometry("ml00a", + "MULTILINESTRING(())"); + + // invalid multilinestring + test_empty_geometry("ml00b", + "MULTILINESTRING((),())"); + + // invalid multilinestring + tester::apply("ml00c", + from_wkt("MULTILINESTRING((10 15),(),())"), + 10, 15, 10, 15); + + // invalid multilinestring + tester::apply("ml00d", + from_wkt("MULTILINESTRING((),(10 15),())"), + 10, 15, 10, 15); tester::apply("ml01", + from_wkt("MULTILINESTRING((10 15))"), + 10, 15, 10, 15); + +#ifdef BOOST_GEOMETRY_INCLUDE_FAILING_TESTS + tester::apply("ml01a", from_wkt("MULTILINESTRING((),(),(10 15),())"), 10, 15, 10, 15); +#endif // BOOST_GEOMETRY_INCLUDE_FAILING_TESTS tester::apply("ml02", from_wkt("MULTILINESTRING((-170 40,-100 80,10 40),(-10 25,10 35,100 45),(50 30,150 45,-160 30))"), @@ -1121,6 +1274,30 @@ BOOST_AUTO_TEST_CASE( envelope_multilinestring ) } +BOOST_AUTO_TEST_CASE( envelope_multilinestring_with_height ) +{ + typedef bg::cs::spherical_equatorial coordinate_system_type; + typedef bg::model::point point_type; + typedef bg::model::multi_linestring > G; + typedef bg::model::box B; + typedef test_envelope_on_spheroid tester; + + tester::apply("mlh01", + from_wkt("MULTILINESTRING((10 15 1000))"), + 10, 15, 1000, 10, 15, 1000); + +#ifdef BOOST_GEOMETRY_INCLUDE_FAILING_TESTS + tester::apply("mlh01a", + from_wkt("MULTILINESTRING((),(),(10 15 1000),())"), + 10, 15, 1000, 10, 15, 1000); +#endif // BOOST_GEOMETRY_INCLUDE_FAILING_TESTS + + tester::apply("mlh02", + from_wkt("MULTILINESTRING((-170 40 400,-100 80 300),(-10 25 600,10 35 700,120 45 450))"), + -10, 25, 300, 260, 80, 700); +} + + #if 0 // unit test for rings de-activated for now (current implementation // for area on the spherical equatorial coordinate system is not complete) diff --git a/test/algorithms/expand_on_spheroid.cpp b/test/algorithms/expand_on_spheroid.cpp index 98db446ad..60692869d 100644 --- a/test/algorithms/expand_on_spheroid.cpp +++ b/test/algorithms/expand_on_spheroid.cpp @@ -8,13 +8,14 @@ // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html - #ifndef BOOST_TEST_MODULE #define BOOST_TEST_MODULE test_expand_on_spheroid #endif #include +#include + #include #include @@ -23,112 +24,70 @@ #include +#include #include #include #include +#include + #include #include #include +#include #include +#include +#include -typedef bg::cs::spherical_equatorial se_rad_type; -typedef bg::cs::spherical_equatorial se_deg_type; - -typedef bg::model::point rad_point_type; -typedef bg::model::point deg_point_type; - -typedef bg::model::segment rad_segment_type; -typedef bg::model::segment deg_segment_type; - -typedef bg::model::box rad_box_type; -typedef bg::model::box deg_box_type; - - -template -char const* units2string() -{ - if (BOOST_GEOMETRY_CONDITION((boost::is_same::value))) - { - return "degrees"; - } - return "radians"; -} - -template -struct other_system_info -{ - typedef bg::degree units; - typedef bg::cs::spherical_equatorial type; - - template - static inline T convert(T const& value) - { - return value * bg::math::r2d(); - } -}; - -template <> -struct other_system_info -{ - typedef bg::radian units; - typedef bg::cs::spherical_equatorial type; - - template - static inline T convert(T const& value) - { - return value * bg::math::d2r(); - } -}; - - -class equals_with_tolerance -{ -private: - double m_tolerence; - - template - static inline T const& get_max(T const& a, T const& b, T const& c) - { - return (std::max)((std::max)(a, b), c); - } - - template - static inline bool check_close(T const& a, T const& b, double tol) - { - return (a == b) - || (std::abs(a - b) <= tol * get_max(std::abs(a), std::abs(b), 1.0)); - } - -public: - equals_with_tolerance(double tolerence) : m_tolerence(tolerence) {} - - template - inline bool operator()(T const& value1, T const& value2) const - { - return check_close(value1, value2, m_tolerence); - } -}; - - -template -inline bool box_equals(Box1 const& box1, Box2 const& box2, double tol) -{ - equals_with_tolerance equals(tol); - - return equals(bg::get<0, 0>(box1), bg::get<0, 0>(box2)) - && equals(bg::get<0, 1>(box1), bg::get<0, 1>(box2)) - && equals(bg::get<1, 0>(box1), bg::get<1, 0>(box2)) - && equals(bg::get<1, 1>(box1), bg::get<1, 1>(box2)); -} +#include "test_envelope_expand_on_spheroid.hpp" class test_expand_on_spheroid { private: + template + < + typename Geometry, + typename Tag = typename bg::tag::type + > + struct write_geometry + { + template + static inline OutputStream& apply(OutputStream& os, + Geometry const& geometry) + { + os << bg::wkt(geometry); + return os; + } + }; + + template + struct write_geometry + { + template + static inline OutputStream& apply(OutputStream& os, + Segment const& segment) + { + os << "SEGMENT" << bg::dsv(segment); + return os; + } + }; + + template + struct write_geometry + { + template + static inline OutputStream& apply(OutputStream& os, + Box const& box) + { + os << "BOX" << bg::dsv(box); + return os; + } + }; + template static inline void check_message(bool same_boxes, std::string const& case_id, @@ -140,34 +99,13 @@ private: Box const& expected2, Box const& detected) { - bool const is_box = boost::is_same - < - typename bg::tag::type, bg::box_tag - >::value; - - bool const is_segment = boost::is_same - < - typename bg::tag::type, bg::segment_tag - >::value; - std::ostringstream stream; stream << "case ID: " << case_id << ", " << "MBR units: " << units_str << "; " << "input box: BOX" << bg::dsv(box) << ", " << "geometry: "; - if (BOOST_GEOMETRY_CONDITION(is_box)) - { - stream << "BOX" << bg::dsv(geometry); - } - else if (BOOST_GEOMETRY_CONDITION(is_segment)) - { - stream << "SEGMENT" << bg::dsv(geometry); - } - else - { - stream << bg::wkt(geometry); - } + write_geometry::apply(stream, geometry); stream << "; " << "expected: " << bg::dsv(expected1); if (expected_are_different) @@ -188,9 +126,13 @@ private: Box const& box, Geometry const& geometry, double lon_min1, double lat_min1, + double height_min1, double lon_max1, double lat_max1, + double height_max1, double lon_min2, double lat_min2, + double height_min2, double lon_max2, double lat_max2, + double height_max2, double tolerance) { typedef typename bg::coordinate_system @@ -209,39 +151,20 @@ private: || (lon_max1 != lon_max2) || (lat_max1 != lat_max2); Box expected1; - bg::assign_values(expected1, - lon_min1, lat_min1, lon_max1, lat_max1); + initialize_box::apply(expected1, + lon_min1, lat_min1, height_min1, + lon_max1, lat_max1, height_max1); Box expected2; - bg::assign_values(expected2, - lon_min2, lat_min2, lon_max2, lat_max2); + initialize_box::apply(expected2, + lon_min2, lat_min2, height_min2, + lon_max2, lat_max2, height_max2); #ifdef BOOST_GEOMETRY_TEST_DEBUG - bool const is_box = boost::is_same - < - typename bg::tag::type, bg::box_tag - >::value; - - bool const is_segment = boost::is_same - < - typename bg::tag::type, bg::segment_tag - >::value; - std::cout << "input box: BOX" << bg::dsv(box) << std::endl; std::cout << "geometry: "; - if (BOOST_GEOMETRY_CONDITION(is_box)) - { - std::cout << "BOX" << bg::dsv(geometry); - } - else if(BOOST_GEOMETRY_CONDITION(is_segment)) - { - std::cout << "SEGMENT" << bg::dsv(geometry); - } - else - { - std::cout << bg::wkt(geometry); - } + write_geometry::apply(std::cout, geometry); std::cout << std::endl << "MBR units: " << units_str @@ -257,11 +180,13 @@ private: << "detected: " << bg::dsv(detected) << std::endl << std::endl; #endif - bool same_boxes = box_equals(detected, expected1, tolerance); + bool same_boxes + = box_equals::apply(detected, expected1, tolerance); + if (expected_are_different) { same_boxes = same_boxes - || box_equals(detected, expected2, tolerance); + || box_equals::apply(detected, expected2, tolerance); } check_message(same_boxes, case_id, units_str, @@ -274,14 +199,18 @@ private: Box const& box, Geometry const& geometry, double lon_min1, double lat_min1, + double height_min1, double lon_max1, double lat_max1, + double height_max1, double lon_min2, double lat_min2, + double height_min2, double lon_max2, double lat_max2, + double height_max2, double tolerance) { typedef other_system_info < - typename bg::coordinate_system::type::units + typename bg::coordinate_system::type > other; typedef bg::model::box @@ -289,7 +218,7 @@ private: bg::model::point < typename bg::coordinate_type::type, - 2, + bg::dimension::value, typename other::type > > other_mbr_type; @@ -300,26 +229,41 @@ private: #endif base_test(case_id, box, geometry, - lon_min1, lat_min1, lon_max1, lat_max1, - lon_min2, lat_min2, lon_max2, lat_max2, + lon_min1, lat_min1, height_min1, + lon_max1, lat_max1, height_max1, + lon_min2, lat_min2, height_min2, + lon_max2, lat_max2, height_max2, tolerance); other_mbr_type other_box; - bg::assign_values(other_box, - other::convert(bg::get<0, 0>(box)), - other::convert(bg::get<0, 1>(box)), - other::convert(bg::get<1, 0>(box)), - other::convert(bg::get<1, 1>(box))); + bg::detail::indexed_point_view p_min(box); + bg::detail::indexed_point_view p_max(box); + bg::detail::indexed_point_view + < + other_mbr_type, 0 + > other_min(other_box); + + bg::detail::indexed_point_view + < + other_mbr_type, 1 + > other_max(other_box); + + bg::transform(p_min, other_min); + bg::transform(p_max, other_max); base_test(case_id, other_box, geometry, other::convert(lon_min1), other::convert(lat_min1), + height_min1, other::convert(lon_max1), other::convert(lat_max1), + height_max1, other::convert(lon_min2), other::convert(lat_min2), + height_min2, other::convert(lon_max2), other::convert(lat_max2), + height_max2, tolerance); #ifdef BOOST_GEOMETRY_TEST_DEBUG @@ -337,17 +281,23 @@ private: Box const& box, Geometry const& geometry, double lon_min1, double lat_min1, + double height_min1, double lon_max1, double lat_max1, + double height_max1, double lon_min2, double lat_min2, + double height_min2, double lon_max2, double lat_max2, + double height_max2, double tolerance) { basic_tester < false >::apply(case_id, box, geometry, - lon_min1, lat_min1, lon_max1, lat_max1, - lon_min2, lat_min2, lon_max2, lat_max2, + lon_min1, lat_min1, height_min1, + lon_max1, lat_max1, height_max1, + lon_min2, lat_min2, height_min1, + lon_max2, lat_max2, height_max2, tolerance); std::string case_id_r = case_id + "[R]"; @@ -356,8 +306,10 @@ private: < false >::apply(case_id_r, geometry, box, - lon_min1, lat_min1, lon_max1, lat_max1, - lon_min2, lat_min2, lon_max2, lat_max2, + lon_min1, lat_min1, height_min1, + lon_max1, lat_max1, height_max1, + lon_min2, lat_min2, height_min2, + lon_max2, lat_max2, height_max2, tolerance); } }; @@ -368,10 +320,10 @@ public: static inline void apply(std::string const& case_id, Box const& box, Geometry const& geometry, - double lon_min1, double lat_min1, - double lon_max1, double lat_max1, - double lon_min2, double lat_min2, - double lon_max2, double lat_max2, + double lon_min1, double lat_min1, double height_min1, + double lon_max1, double lat_max1, double height_max1, + double lon_min2, double lat_min2, double height_min2, + double lon_max2, double lat_max2, double height_max2, double tolerance = std::numeric_limits::epsilon()) { @@ -383,11 +335,29 @@ public: bg::box_tag >::value >::apply(case_id, box, geometry, - lon_min1, lat_min1, lon_max1, lat_max1, - lon_min2, lat_min2, lon_max2, lat_max2, + lon_min1, lat_min1, height_min1, + lon_max1, lat_max1, height_max1, + lon_min2, lat_min2, height_min2, + lon_max2, lat_max2, height_max2, tolerance); } + template + static inline void apply(std::string const& case_id, + Box const& box, + Geometry const& geometry, + double lon_min1, double lat_min1, + double lon_max1, double lat_max1, + double lon_min2, double lat_min2, + double lon_max2, double lat_max2, + double tolerance = std::numeric_limits::epsilon()) + { + apply(case_id, box, geometry, + lon_min1, lat_min1, 0, lon_max1, lat_max1, 0, + lon_min2, lat_min2, 0, lon_max2, lat_max2, 0, + tolerance); + } + template static inline void apply(std::string const& case_id, Box const& box, @@ -397,17 +367,33 @@ public: double tolerance = std::numeric_limits::epsilon()) { apply(case_id, box, geometry, - lon_min, lat_min, lon_max, lat_max, - lon_min, lat_min, lon_max, lat_max, + lon_min, lat_min, 0, lon_max, lat_max, 0, + lon_min, lat_min, 0, lon_max, lat_max, 0, + tolerance); + } + + template + static inline void apply(std::string const& case_id, + Box const& box, + Geometry const& geometry, + double lon_min, double lat_min, double height_min, + double lon_max, double lat_max, double height_max, + double tolerance = std::numeric_limits::epsilon()) + { + apply(case_id, box, geometry, + lon_min, lat_min, height_min, lon_max, lat_max, height_max, + lon_min, lat_min, height_min, lon_max, lat_max, height_max, tolerance); } }; -BOOST_AUTO_TEST_CASE( expand_point ) +template +void test_expand_point() { - typedef deg_box_type B; - typedef deg_point_type G; + typedef bg::model::point point_type; + typedef bg::model::box B; + typedef point_type G; typedef test_expand_on_spheroid tester; tester::apply("p01", @@ -596,11 +582,51 @@ BOOST_AUTO_TEST_CASE( expand_point ) 10, -90, 100, 90); } +BOOST_AUTO_TEST_CASE( expand_point ) +{ + test_expand_point >(); + test_expand_point >(); +} + + +template +void test_expand_point_with_height() +{ + typedef bg::model::point point_type; + typedef bg::model::box B; + typedef point_type G; + typedef test_expand_on_spheroid tester; + + // deactivate this for now + tester::apply("ph01", + from_wkt("BOX(0 0 20,5 5 100)"), + from_wkt("POINT(10 10 80)"), + 0, 0, 20, 10, 10, 100); + + tester::apply("ph02", + from_wkt("BOX(0 0 20,5 5 100)"), + from_wkt("POINT(10 10 120)"), + 0, 0, 20, 10, 10, 120); + + tester::apply("ph03", + from_wkt("BOX(0 0 20,5 5 100)"), + from_wkt("POINT(10 10 5)"), + 0, 0, 5, 10, 10, 100); +} + +BOOST_AUTO_TEST_CASE( expand_point_with_height ) +{ + test_expand_point_with_height >(); + test_expand_point_with_height >(); +} + BOOST_AUTO_TEST_CASE( expand_segment ) { - typedef deg_box_type B; - typedef deg_segment_type G; + typedef bg::cs::spherical_equatorial coordinate_system_type; + typedef bg::model::point point_type; + typedef bg::model::box B; + typedef bg::model::segment G; typedef test_expand_on_spheroid tester; tester::apply("s01", @@ -675,10 +701,42 @@ BOOST_AUTO_TEST_CASE( expand_segment ) } -BOOST_AUTO_TEST_CASE( expand_box ) +BOOST_AUTO_TEST_CASE( expand_segment_with_height ) { - typedef deg_box_type B; - typedef deg_box_type G; + typedef bg::cs::spherical_equatorial coordinate_system_type; + typedef bg::model::point point_type; + typedef bg::model::box B; + typedef bg::model::segment G; + typedef test_expand_on_spheroid tester; + + tester::apply("sh01", + from_wkt("BOX(20 20 100,50 50 1000)"), + from_wkt("SEGMENT(10 10 150,40 40 500)"), + 10, 10, 100, 50, 50, 1000); + + tester::apply("sh02", + from_wkt("BOX(20 20 100,50 50 1000)"), + from_wkt("SEGMENT(10 10 60,40 40 1500)"), + 10, 10, 60, 50, 50, 1500); + + tester::apply("sh03", + from_wkt("BOX(20 20 100,50 50 1000)"), + from_wkt("SEGMENT(10 10 150,40 40 1500)"), + 10, 10, 100, 50, 50, 1500); + + tester::apply("sh04", + from_wkt("BOX(20 20 100,50 50 1000)"), + from_wkt("SEGMENT(10 10 60,40 40 800)"), + 10, 10, 60, 50, 50, 1000); +} + + +template +void test_expand_box() +{ + typedef bg::model::point point_type; + typedef bg::model::box B; + typedef bg::model::box G; typedef test_expand_on_spheroid tester; tester::apply("b01", @@ -846,3 +904,45 @@ BOOST_AUTO_TEST_CASE( expand_box ) from_wkt("BOX(0 -10,185 50)"), -180, -40, 180, 50); } + +BOOST_AUTO_TEST_CASE( expand_box ) +{ + test_expand_box >(); + test_expand_box >(); +} + + +template +void test_expand_box_with_height() +{ + typedef bg::model::point point_type; + typedef bg::model::box B; + typedef bg::model::box G; + typedef test_expand_on_spheroid tester; + + tester::apply("bh01", + from_wkt("BOX(11 11 100,19 19 1000)"), + from_wkt("BOX(10 10 200,20 20 800)"), + 10, 10, 100, 20, 20, 1000); + + tester::apply("bh02", + from_wkt("BOX(11 11 200,19 19 1000)"), + from_wkt("BOX(10 10 100,20 20 800)"), + 10, 10, 100, 20, 20, 1000); + + tester::apply("bh03", + from_wkt("BOX(11 11 100,19 19 800)"), + from_wkt("BOX(10 10 200,20 20 1000)"), + 10, 10, 100, 20, 20, 1000); + + tester::apply("bh04", + from_wkt("BOX(11 11 200,19 19 1000)"), + from_wkt("BOX(10 10 100,20 20 800)"), + 10, 10, 100, 20, 20, 1000); +} + +BOOST_AUTO_TEST_CASE( expand_box_with_height ) +{ + test_expand_box_with_height >(); + test_expand_box_with_height >(); +} diff --git a/test/algorithms/is_simple.cpp b/test/algorithms/is_simple.cpp index bd6ceb668..f73d6309c 100644 --- a/test/algorithms/is_simple.cpp +++ b/test/algorithms/is_simple.cpp @@ -33,6 +33,7 @@ #include +#include #include #include @@ -296,6 +297,27 @@ BOOST_AUTO_TEST_CASE( test_is_simple_areal ) false); } +BOOST_AUTO_TEST_CASE( test_geometry_with_NaN_coordinates ) +{ +#ifdef BOOST_GEOMETRY_TEST_DEBUG + std::cout << std::endl << std::endl; + std::cout << "************************************" << std::endl; + std::cout << " is_valid: geometry with NaN coordinates" << std::endl; + std::cout << "************************************" << std::endl; +#endif + + linestring_type ls1, ls2; + bg::read_wkt("LINESTRING(1 1,1.115235e+308 1.738137e+308)", ls1); + bg::read_wkt("LINESTRING(-1 1,1.115235e+308 1.738137e+308)", ls2); + + // the intersection of the two linestrings is a new linestring + // (multilinestring with a single element) that has NaN coordinates + multi_linestring_type mls; + bg::intersection(ls1, ls2, mls); + + test_simple(mls, true); +} + BOOST_AUTO_TEST_CASE( test_is_simple_variant ) { #ifdef BOOST_GEOMETRY_TEST_DEBUG diff --git a/test/algorithms/is_valid.cpp b/test/algorithms/is_valid.cpp index e4ead8d4d..7ec61eece 100644 --- a/test/algorithms/is_valid.cpp +++ b/test/algorithms/is_valid.cpp @@ -20,6 +20,7 @@ #include "test_is_valid.hpp" #include +#include #include BOOST_AUTO_TEST_CASE( test_is_valid_point ) @@ -1114,6 +1115,38 @@ BOOST_AUTO_TEST_CASE( test_is_valid_multipolygon ) test_open_multipolygons(); } +BOOST_AUTO_TEST_CASE( test_geometry_with_NaN_coordinates ) +{ +#ifdef BOOST_GEOMETRY_TEST_DEBUG + std::cout << std::endl << std::endl; + std::cout << "************************************" << std::endl; + std::cout << " is_valid: geometry with NaN coordinates" << std::endl; + std::cout << "************************************" << std::endl; +#endif + + linestring_type ls1, ls2; + bg::read_wkt("LINESTRING(1 1,1.115235e+308 1.738137e+308)", ls1); + bg::read_wkt("LINESTRING(-1 1,1.115235e+308 1.738137e+308)", ls2); + + // the intersection of the two linestrings is a new linestring + // (multilinestring with a single element) that has NaN coordinates + multi_linestring_type mls; + bg::intersection(ls1, ls2, mls); + + typedef validity_tester_linear tester_allow_spikes; + typedef validity_tester_linear tester_disallow_spikes; + + test_valid + < + tester_allow_spikes, multi_linestring_type + >::apply("mls-NaN", mls, true); + + test_valid + < + tester_disallow_spikes, multi_linestring_type + >::apply("mls-NaN", mls, true); +} + BOOST_AUTO_TEST_CASE( test_is_valid_variant ) { #ifdef BOOST_GEOMETRY_TEST_DEBUG diff --git a/test/algorithms/test_envelope_expand_on_spheroid.hpp b/test/algorithms/test_envelope_expand_on_spheroid.hpp new file mode 100644 index 000000000..316b9cae2 --- /dev/null +++ b/test/algorithms/test_envelope_expand_on_spheroid.hpp @@ -0,0 +1,192 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) +// Unit Test + +// Copyright (c) 2015, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_TEST_ENVELOPE_EXPAND_ON_SPHEROID_HPP +#define BOOST_GEOMETRY_TEST_ENVELOPE_EXPAND_ON_SPHEROID_HPP + +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include + +#include + +#include + + +template +char const* units2string() +{ + if (BOOST_GEOMETRY_CONDITION((boost::is_same::value))) + { + return "degrees"; + } + return "radians"; +} + +template +struct other_system_info +{}; + +template <> +struct other_system_info > +{ + typedef bg::degree units; + typedef bg::cs::spherical_equatorial type; + + template + static inline T convert(T const& value) + { + return value * bg::math::r2d(); + } +}; + +template <> +struct other_system_info > +{ + typedef bg::radian units; + typedef bg::cs::spherical_equatorial type; + + template + static inline T convert(T const& value) + { + return value * bg::math::d2r(); + } +}; + +template <> +struct other_system_info > +{ + typedef bg::degree units; + typedef bg::cs::geographic type; + + template + static inline T convert(T const& value) + { + return value * bg::math::r2d(); + } +}; + +template <> +struct other_system_info > +{ + typedef bg::radian units; + typedef bg::cs::geographic type; + + template + static inline T convert(T const& value) + { + return value * bg::math::d2r(); + } +}; + + + +class equals_with_tolerance +{ +private: + double m_tolerence; + + template + static inline T const& get_max(T const& a, T const& b, T const& c) + { + return (std::max)((std::max)(a, b), c); + } + + template + static inline bool check_close(T const& a, T const& b, double tol) + { + return (a == b) + || (std::abs(a - b) <= tol * get_max(std::abs(a), std::abs(b), 1.0)); + } + +public: + equals_with_tolerance(double tolerence) : m_tolerence(tolerence) {} + + template + inline bool operator()(T const& value1, T const& value2) const + { + return check_close(value1, value2, m_tolerence); + } +}; + + +template +< + typename Box1, + typename Box2 = Box1, + std::size_t DimensionCount = bg::dimension::value +> +struct box_equals +{ + static inline bool apply(Box1 const& box1, Box2 const& box2, double tol) + { + equals_with_tolerance equals(tol); + + return equals(bg::get<0, 0>(box1), bg::get<0, 0>(box2)) + && equals(bg::get<0, 1>(box1), bg::get<0, 1>(box2)) + && equals(bg::get<1, 0>(box1), bg::get<1, 0>(box2)) + && equals(bg::get<1, 1>(box1), bg::get<1, 1>(box2)); + } +}; + +template +struct box_equals +{ + static inline bool apply(Box1 const& box1, Box2 const& box2, double tol) + { + equals_with_tolerance equals(tol); + + return box_equals::apply(box1, box2, tol) + && equals(bg::get<0, 2>(box1), bg::get<0, 2>(box2)) + && equals(bg::get<1, 2>(box1), bg::get<1, 2>(box2)); + } +}; + + +template ::value> +struct initialize_box +{ + static inline void apply(Box& box, + double lon_min, double lat_min, double, + double lon_max, double lat_max, double) + { + bg::detail::indexed_point_view p_min(box); + bg::detail::indexed_point_view p_max(box); + + bg::assign_values(p_min, lon_min, lat_min); + bg::assign_values(p_max, lon_max, lat_max); + } +}; + +template +struct initialize_box +{ + static inline void apply(Box& box, + double lon_min, double lat_min, double height_min, + double lon_max, double lat_max, double height_max) + { + bg::detail::indexed_point_view p_min(box); + bg::detail::indexed_point_view p_max(box); + + bg::assign_values(p_min, lon_min, lat_min, height_min); + bg::assign_values(p_max, lon_max, lat_max, height_max); + } +}; + +#endif // BOOST_GEOMETRY_TEST_ENVELOPE_EXPAND_ON_SPHEROID_HPP