// Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2018-2019 Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fisikopoulos, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // 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_STRATEGIES_SPHERICAL_DISTANCE_SEGMENT_BOX_HPP #define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_SEGMENT_BOX_HPP #include #include #include #include #include #include #include // spherical #include namespace boost { namespace geometry { namespace strategy { namespace distance { struct generic_segment_box { template < typename LessEqual, typename ReturnType, typename SegmentPoint, typename BoxPoint, typename SegmentBoxStrategy, typename AzimuthStrategy, typename EnvelopeSegmentStrategy, typename NormalizePointStrategy, typename DisjointPointBoxStrategy, typename DisjointBoxBoxStrategy > static inline ReturnType segment_below_of_box( SegmentPoint const& p0, SegmentPoint const& p1, BoxPoint const&, BoxPoint const& top_right, BoxPoint const& bottom_left, BoxPoint const& bottom_right, SegmentBoxStrategy const& sb_strategy, AzimuthStrategy const& az_strategy, EnvelopeSegmentStrategy const& es_strategy, NormalizePointStrategy const& np_strategy, DisjointPointBoxStrategy const& dpb_strategy, DisjointBoxBoxStrategy const& dbb_strategy) { ReturnType result; typename LessEqual::other less_equal; typedef geometry::model::segment segment_type; // if cs_tag is spherical_tag check segment's cs_tag with spherical_equatorial_tag as default typedef typename boost::mpl::if_c < boost::is_same::value, typename boost::mpl::if_c < boost::is_same < typename geometry::cs_tag::type, spherical_polar_tag >::value, spherical_polar_tag, spherical_equatorial_tag >::type, typename SegmentBoxStrategy::cs_tag >::type cs_tag; typedef geometry::detail::disjoint:: disjoint_segment_box_sphere_or_spheroid disjoint_sb; typedef typename disjoint_sb::disjoint_info disjoint_info_type; segment_type seg(p0, p1); geometry::model::box input_box; geometry::set_from_radian (input_box, geometry::get_as_radian<0>(bottom_left)); geometry::set_from_radian (input_box, geometry::get_as_radian<1>(bottom_left)); geometry::set_from_radian (input_box, geometry::get_as_radian<0>(top_right)); geometry::set_from_radian (input_box, geometry::get_as_radian<1>(top_right)); SegmentPoint p_max; disjoint_info_type disjoint_result = disjoint_sb:: apply(seg, input_box, p_max, az_strategy, np_strategy, dpb_strategy, dbb_strategy); if (disjoint_result == disjoint_info_type::intersect) //intersect { return 0; } // disjoint but vertex not computed if (disjoint_result == disjoint_info_type::disjoint_no_vertex) { typedef typename coordinate_type::type CT; geometry::model::box mbr; geometry::envelope(seg, mbr, es_strategy); CT lon1 = geometry::get_as_radian<0>(p0); CT lat1 = geometry::get_as_radian<1>(p0); CT lon2 = geometry::get_as_radian<0>(p1); CT lat2 = geometry::get_as_radian<1>(p1); if (lon1 > lon2) { std::swap(lon1, lon2); std::swap(lat1, lat2); } CT vertex_lat; CT lat_sum = lat1 + lat2; if (lat_sum > CT(0)) { vertex_lat = geometry::get_as_radian(mbr); } else { vertex_lat = geometry::get_as_radian(mbr); } CT alp1; az_strategy.apply(lon1, lat1, lon2, lat2, alp1); CT vertex_lon = geometry::formula::vertex_longitude < CT, cs_tag >::apply(lon1, lat1, lon2, lat2, vertex_lat, alp1, az_strategy); geometry::set_from_radian<0>(p_max, vertex_lon); geometry::set_from_radian<1>(p_max, vertex_lat); } //otherwise disjoint and vertex computed inside disjoint if (less_equal(geometry::get_as_radian<0>(bottom_left), geometry::get_as_radian<0>(p_max))) { result = boost::numeric_cast(typename SegmentBoxStrategy::distance_ps_strategy::type().apply(bottom_left, p0, p1)); } else { result = geometry::detail::distance::segment_to_box_2D < ReturnType, SegmentPoint, BoxPoint, SegmentBoxStrategy >::template call_above_of_box < typename LessEqual::other >(p1, p0, p_max, bottom_right, sb_strategy); } return result; } template static void mirror(SPoint& p0, SPoint& p1, BPoint& bottom_left, BPoint& bottom_right, BPoint& top_left, BPoint& top_right) { //if segment's vertex is the southest point then mirror geometries if (geometry::get<1>(p0) + geometry::get<1>(p1) < 0) { BPoint bl = bottom_left; BPoint br = bottom_right; geometry::set<1>(p0, geometry::get<1>(p0) * -1); geometry::set<1>(p1, geometry::get<1>(p1) * -1); geometry::set<1>(bottom_left, geometry::get<1>(top_left) * -1); geometry::set<1>(top_left, geometry::get<1>(bl) * -1); geometry::set<1>(bottom_right, geometry::get<1>(top_right) * -1); geometry::set<1>(top_right, geometry::get<1>(br) * -1); } } }; //=========================================================================== template < typename CalculationType = void, typename Strategy = haversine > struct spherical_segment_box { template struct calculation_type : promote_floating_point < typename strategy::distance::services::return_type < Strategy, PointOfSegment, PointOfBox >::type > {}; typedef spherical_tag cs_tag; // strategy getters // point-point strategy getters struct distance_pp_strategy { typedef Strategy type; }; inline typename distance_pp_strategy::type get_distance_pp_strategy() const { return typename distance_pp_strategy::type(); } // point-segment strategy getters struct distance_ps_strategy { typedef cross_track type; }; inline typename distance_ps_strategy::type get_distance_ps_strategy() const { return typename distance_ps_strategy::type(); } struct distance_pb_strategy { typedef cross_track_point_box type; }; inline typename distance_pb_strategy::type get_distance_pb_strategy() const { return typename distance_pb_strategy::type(); } // TODO: why is the Radius not propagated above? typedef side::spherical_side_formula side_strategy_type; static inline side_strategy_type get_side_strategy() { return side_strategy_type(); } typedef within::spherical_point_point equals_point_point_strategy_type; static inline equals_point_point_strategy_type get_equals_point_point_strategy() { return equals_point_point_strategy_type(); } // methods template inline ReturnType segment_below_of_box(SegmentPoint const& p0, SegmentPoint const& p1, BoxPoint const& top_left, BoxPoint const& top_right, BoxPoint const& bottom_left, BoxPoint const& bottom_right) const { typedef typename azimuth::spherical azimuth_strategy_type; azimuth_strategy_type az_strategy; typedef typename envelope::spherical_segment envelope_segment_strategy_type; envelope_segment_strategy_type es_strategy; return generic_segment_box::segment_below_of_box < LessEqual, ReturnType >(p0,p1,top_left,top_right,bottom_left,bottom_right, spherical_segment_box(), az_strategy, es_strategy, normalize::spherical_point(), covered_by::spherical_point_box(), disjoint::spherical_box_box()); } template static void mirror(SPoint& p0, SPoint& p1, BPoint& bottom_left, BPoint& bottom_right, BPoint& top_left, BPoint& top_right) { generic_segment_box::mirror(p0, p1, bottom_left, bottom_right, top_left, top_right); } }; #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS namespace services { template struct tag > { typedef strategy_tag_distance_segment_box type; }; template struct return_type, PS, PB> : spherical_segment_box::template calculation_type {}; template struct comparable_type > { // Define a cartesian_segment_box strategy with its underlying point-segment // strategy being comparable typedef spherical_segment_box < CalculationType, typename comparable_type::type > type; }; template struct get_comparable > { typedef typename comparable_type < spherical_segment_box >::type comparable_type; public : static inline comparable_type apply(spherical_segment_box const& ) { return comparable_type(); } }; template struct result_from_distance, PS, PB> { private : typedef typename return_type< spherical_segment_box < CalculationType, Strategy >, PS, PB >::type return_type; public : template static inline return_type apply(spherical_segment_box const& , T const& value) { Strategy s; return result_from_distance::apply(s, value); } }; template struct default_strategy < segment_tag, box_tag, Segment, Box, spherical_equatorial_tag, spherical_equatorial_tag > { typedef spherical_segment_box<> type; }; template struct default_strategy < box_tag, segment_tag, Box, Segment, spherical_equatorial_tag, spherical_equatorial_tag > { typedef typename default_strategy < segment_tag, box_tag, Segment, Box, spherical_equatorial_tag, spherical_equatorial_tag >::type type; }; } #endif }} // namespace strategy::distance }} // namespace boost::geometry #endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_SEGMENT_BOX_HPP