Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:35:04

0001 // Boost.Geometry (aka GGL, Generic Geometry Library)
0002 
0003 // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
0004 // Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
0005 // Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
0006 // Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
0007 
0008 // This file was modified by Oracle on 2013-2021.
0009 // Modifications copyright (c) 2013-2021, Oracle and/or its affiliates.
0010 
0011 // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
0012 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
0013 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
0014 
0015 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
0016 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
0017 
0018 // Use, modification and distribution is subject to the Boost Software License,
0019 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
0020 // http://www.boost.org/LICENSE_1_0.txt)
0021 
0022 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_SEGMENT_BOX_HPP
0023 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_SEGMENT_BOX_HPP
0024 
0025 #include <cstddef>
0026 
0027 #include <boost/geometry/core/tags.hpp>
0028 #include <boost/geometry/core/radian_access.hpp>
0029 
0030 #include <boost/geometry/algorithms/detail/assign_indexed_point.hpp>
0031 #include <boost/geometry/algorithms/detail/disjoint/point_box.hpp>
0032 #include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
0033 #include <boost/geometry/algorithms/detail/envelope/segment.hpp>
0034 #include <boost/geometry/algorithms/detail/normalize.hpp>
0035 #include <boost/geometry/algorithms/dispatch/disjoint.hpp>
0036 
0037 #include <boost/geometry/formulas/vertex_longitude.hpp>
0038 
0039 #include <boost/geometry/geometries/box.hpp>
0040 
0041 // Temporary, for envelope_segment_impl
0042 #include <boost/geometry/strategy/spherical/envelope_segment.hpp>
0043 
0044 namespace boost { namespace geometry
0045 {
0046 
0047 
0048 #ifndef DOXYGEN_NO_DETAIL
0049 namespace detail { namespace disjoint
0050 {
0051 
0052 template <typename CS_Tag>
0053 struct disjoint_segment_box_sphere_or_spheroid
0054 {
0055     struct disjoint_info
0056     {
0057         enum type
0058         {
0059             intersect,
0060             disjoint_no_vertex,
0061             disjoint_vertex
0062         };
0063         disjoint_info(type t) : m_(t){}
0064         operator type () const {return m_;}
0065         type m_;
0066     private :
0067         //prevent automatic conversion for any other built-in types
0068         template <typename T>
0069         operator T () const;
0070     };
0071 
0072     template
0073     <
0074         typename Segment, typename Box,
0075         typename AzimuthStrategy,
0076         typename NormalizeStrategy,
0077         typename DisjointPointBoxStrategy,
0078         typename DisjointBoxBoxStrategy
0079     >
0080     static inline bool apply(Segment const& segment,
0081                              Box const& box,
0082                              AzimuthStrategy const& azimuth_strategy,
0083                              NormalizeStrategy const& normalize_strategy,
0084                              DisjointPointBoxStrategy const& disjoint_point_box_strategy,
0085                              DisjointBoxBoxStrategy const& disjoint_box_box_strategy)
0086     {
0087         typedef typename point_type<Segment>::type segment_point;
0088         segment_point vertex;
0089         return apply(segment, box, vertex,
0090                      azimuth_strategy,
0091                      normalize_strategy,
0092                      disjoint_point_box_strategy,
0093                      disjoint_box_box_strategy) != disjoint_info::intersect;
0094     }
0095 
0096     template
0097     <
0098         typename Segment, typename Box,
0099         typename P,
0100         typename AzimuthStrategy,
0101         typename NormalizeStrategy,
0102         typename DisjointPointBoxStrategy,
0103         typename DisjointBoxBoxStrategy
0104     >
0105     static inline disjoint_info apply(Segment const& segment,
0106                                       Box const& box,
0107                                       P& vertex,
0108                                       AzimuthStrategy const& azimuth_strategy,
0109                                       NormalizeStrategy const& ,
0110                                       DisjointPointBoxStrategy const& disjoint_point_box_strategy,
0111                                       DisjointBoxBoxStrategy const& disjoint_box_box_strategy)
0112     {
0113         assert_dimension_equal<Segment, Box>();
0114 
0115         typedef typename point_type<Segment>::type segment_point_type;
0116 
0117         segment_point_type p0, p1;
0118         geometry::detail::assign_point_from_index<0>(segment, p0);
0119         geometry::detail::assign_point_from_index<1>(segment, p1);
0120 
0121         //vertex not computed here
0122         disjoint_info disjoint_return_value = disjoint_info::disjoint_no_vertex;
0123 
0124         // Simplest cases first
0125 
0126         // Case 1: if box contains one of segment's endpoints then they are not disjoint
0127         if ( ! disjoint_point_box(p0, box, disjoint_point_box_strategy)
0128           || ! disjoint_point_box(p1, box, disjoint_point_box_strategy) )
0129         {
0130             return disjoint_info::intersect;
0131         }
0132 
0133         // Case 2: disjoint if bounding boxes are disjoint
0134 
0135         typedef typename coordinate_type<segment_point_type>::type CT;
0136 
0137         segment_point_type p0_normalized;
0138         NormalizeStrategy::apply(p0, p0_normalized);
0139         segment_point_type p1_normalized;
0140         NormalizeStrategy::apply(p1, p1_normalized);
0141 
0142         CT lon1 = geometry::get_as_radian<0>(p0_normalized);
0143         CT lat1 = geometry::get_as_radian<1>(p0_normalized);
0144         CT lon2 = geometry::get_as_radian<0>(p1_normalized);
0145         CT lat2 = geometry::get_as_radian<1>(p1_normalized);
0146 
0147         if (lon1 > lon2)
0148         {
0149             std::swap(lon1, lon2);
0150             std::swap(lat1, lat2);
0151         }
0152 
0153         geometry::model::box<segment_point_type> box_seg;
0154 
0155         strategy::envelope::detail::envelope_segment_impl
0156             <
0157                 CS_Tag
0158             >::template apply<geometry::radian>(lon1, lat1,
0159                                                 lon2, lat2,
0160                                                 box_seg,
0161                                                 azimuth_strategy);
0162 
0163         if (disjoint_box_box(box, box_seg, disjoint_box_box_strategy))
0164         {
0165             return disjoint_return_value;
0166         }
0167 
0168         // Case 3: test intersection by comparing angles
0169 
0170         CT alp1, a_b0, a_b1, a_b2, a_b3;
0171 
0172         CT b_lon_min = geometry::get_as_radian<geometry::min_corner, 0>(box);
0173         CT b_lat_min = geometry::get_as_radian<geometry::min_corner, 1>(box);
0174         CT b_lon_max = geometry::get_as_radian<geometry::max_corner, 0>(box);
0175         CT b_lat_max = geometry::get_as_radian<geometry::max_corner, 1>(box);
0176 
0177         azimuth_strategy.apply(lon1, lat1, lon2, lat2, alp1);
0178         azimuth_strategy.apply(lon1, lat1, b_lon_min, b_lat_min, a_b0);
0179         azimuth_strategy.apply(lon1, lat1, b_lon_max, b_lat_min, a_b1);
0180         azimuth_strategy.apply(lon1, lat1, b_lon_min, b_lat_max, a_b2);
0181         azimuth_strategy.apply(lon1, lat1, b_lon_max, b_lat_max, a_b3);
0182 
0183         int s0 = formula::azimuth_side_value(alp1, a_b0);
0184         int s1 = formula::azimuth_side_value(alp1, a_b1);
0185         int s2 = formula::azimuth_side_value(alp1, a_b2);
0186         int s3 = formula::azimuth_side_value(alp1, a_b3);
0187 
0188         if (s0 == 0 || s1 == 0 || s2 == 0 || s3 == 0)
0189         {
0190             return disjoint_info::intersect;
0191         }
0192 
0193         bool s0_positive = s0 > 0;
0194         bool s1_positive = s1 > 0;
0195         bool s2_positive = s2 > 0;
0196         bool s3_positive = s3 > 0;
0197 
0198         bool all_positive = s0_positive && s1_positive && s2_positive && s3_positive;
0199         bool all_non_positive = !(s0_positive || s1_positive || s2_positive || s3_positive);
0200         bool vertex_north = lat1 + lat2 > 0;
0201 
0202         if ((all_positive && vertex_north) || (all_non_positive && !vertex_north))
0203         {
0204             return disjoint_info::disjoint_no_vertex;
0205         }
0206 
0207         if (!all_positive && !all_non_positive)
0208         {
0209             return disjoint_info::intersect;
0210         }
0211 
0212         // Case 4: The only intersection case not covered above is when all four
0213         // points of the box are above (below) the segment in northern (southern)
0214         // hemisphere. Then we have to compute the vertex of the segment
0215 
0216         CT vertex_lat;
0217 
0218         if ((lat1 < b_lat_min && vertex_north)
0219                 || (lat1 > b_lat_max && !vertex_north))
0220         {
0221             CT b_lat_below; //latitude of box closest to equator
0222 
0223             if (vertex_north)
0224             {
0225                 vertex_lat = geometry::get_as_radian<geometry::max_corner, 1>(box_seg);
0226                 b_lat_below = b_lat_min;
0227             } else {
0228                 vertex_lat = geometry::get_as_radian<geometry::min_corner, 1>(box_seg);
0229                 b_lat_below = b_lat_max;
0230             }
0231 
0232             //optimization TODO: computing the spherical longitude should suffice for
0233             // the majority of cases
0234             CT vertex_lon = geometry::formula::vertex_longitude<CT, CS_Tag>
0235                                     ::apply(lon1, lat1,
0236                                             lon2, lat2,
0237                                             vertex_lat,
0238                                             alp1,
0239                                             azimuth_strategy);
0240 
0241             geometry::set_from_radian<0>(vertex, vertex_lon);
0242             geometry::set_from_radian<1>(vertex, vertex_lat);
0243             disjoint_return_value = disjoint_info::disjoint_vertex; //vertex_computed
0244 
0245             // Check if the vertex point is within the band defined by the
0246             // minimum and maximum longitude of the box; if yes, then return
0247             // false if the point is above the min latitude of the box; return
0248             // true in all other cases
0249             if (vertex_lon >= b_lon_min && vertex_lon <= b_lon_max
0250                     && std::abs(vertex_lat) > std::abs(b_lat_below))
0251             {
0252                 return disjoint_info::intersect;
0253             }
0254         }
0255 
0256         return disjoint_return_value;
0257     }
0258 };
0259 
0260 struct disjoint_segment_box
0261 {
0262     template <typename Segment, typename Box, typename Strategy>
0263     static inline bool apply(Segment const& segment,
0264                              Box const& box,
0265                              Strategy const& strategy)
0266     {
0267         return strategy.disjoint(segment, box).apply(segment, box);
0268     }
0269 };
0270 
0271 }} // namespace detail::disjoint
0272 #endif // DOXYGEN_NO_DETAIL
0273 
0274 
0275 #ifndef DOXYGEN_NO_DISPATCH
0276 namespace dispatch
0277 {
0278 
0279 
0280 template <typename Segment, typename Box, std::size_t DimensionCount>
0281 struct disjoint<Segment, Box, DimensionCount, segment_tag, box_tag, false>
0282         : detail::disjoint::disjoint_segment_box
0283 {};
0284 
0285 
0286 } // namespace dispatch
0287 #endif // DOXYGEN_NO_DISPATCH
0288 
0289 
0290 }} // namespace boost::geometry
0291 
0292 
0293 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_SEGMENT_BOX_HPP