From 3a2ecb68c106b7bc5f6b1bc39e543800ac234811 Mon Sep 17 00:00:00 2001 From: Vissarion Fysikopoulos Date: Fri, 8 Jul 2016 11:34:55 +0300 Subject: [PATCH 01/89] [area] trapezoidal strategy and some fixes for huiller --- .../strategies/spherical/area_huiller.hpp | 130 +++++++++--- .../strategies/spherical/area_trapezoidal.hpp | 192 ++++++++++++++++++ .../boost/geometry/strategies/strategies.hpp | 1 + 3 files changed, 294 insertions(+), 29 deletions(-) create mode 100644 include/boost/geometry/strategies/spherical/area_trapezoidal.hpp diff --git a/include/boost/geometry/strategies/spherical/area_huiller.hpp b/include/boost/geometry/strategies/spherical/area_huiller.hpp index 37d8d2012..447ef8ece 100644 --- a/include/boost/geometry/strategies/spherical/area_huiller.hpp +++ b/include/boost/geometry/strategies/spherical/area_huiller.hpp @@ -2,9 +2,10 @@ // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2015. -// Modifications copyright (c) 2015, Oracle and/or its affiliates. +// This file was modified by Oracle on 2015, 2016. +// Modifications copyright (c) 2015, 2016 Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -91,17 +92,69 @@ protected : { calculation_type sum; + calculation_type max_lon, min_lon; + // Distances are calculated on unit sphere here strategy::distance::haversine distance_over_unit_sphere; + // Keep track if encircles some pole + size_t crosses_prime_meridian; + + bool south; // true if has no point on North hemisphere + bool south_vertex; // true if South pole is a vertex inline excess_sum() : sum(0) , distance_over_unit_sphere(1) + , crosses_prime_meridian(0) + , south(true) + , south_vertex(false) + , max_lon(0) + , min_lon(360) {} inline calculation_type area(calculation_type radius) const { - return - sum * radius * radius; + calculation_type result; + + std::cout << "(sum=" << sum << ")"; + + // Encircles pole + if((crosses_prime_meridian % 2 == 1 && south) || south_vertex) + { + + calculation_type constant; + + //if(south_vertex) + //{ + constant = 2.0 * (max_lon - min_lon) / geometry::math::pi(); + //} else { + // constant = 4.0; + //} + + if(crosses_prime_meridian % 2 == 0 && crosses_prime_meridian > 1) + { + constant = 4.0 - constant; + } + + std::cout << "(const=" << constant << ")"; + + + result = constant + * geometry::math::pi() + - std::abs(sum); + + if(geometry::math::sign(sum) == -1) + { + result = - result; + } + + } else { + result = - sum; + } + + result *= radius * radius; + + return result; } }; @@ -133,7 +186,7 @@ public : // Distance p1 p2 calculation_type a = state.distance_over_unit_sphere.apply(p1, p2); - // Sides on unit sphere to south pole + // Sides on unit sphere to north pole calculation_type b = half_pi - geometry::get_as_radian<1>(p2); calculation_type c = half_pi - geometry::get_as_radian<1>(p1); @@ -150,6 +203,7 @@ public : excess = geometry::math::abs(excess); + // In right direction: positive, add area. In left direction: negative, subtract area. // Longitude comparisons are not so obvious. If one is negative and other is positive, // we have to take the dateline into account. @@ -166,12 +220,55 @@ public : excess = -excess; } + // Keep track whenever a segment crosses the prime meridian + // First normalize to [0,360) + //TODO: compress with trapezoidal strategy + + calculation_type p1_lon = geometry::get_as_radian<0>(p1) + - ( floor( geometry::get_as_radian<0>(p1) / two_pi ) * two_pi ); + calculation_type p2_lon = geometry::get_as_radian<0>(p2) + - ( floor( geometry::get_as_radian<0>(p2) / two_pi ) * two_pi ); + + calculation_type max_lon = std::max(p1_lon, p2_lon); + calculation_type min_lon = std::min(p1_lon, p2_lon); + + if(max_lon > pi && min_lon < pi && max_lon - min_lon > pi) + { + state.crosses_prime_meridian++; + } + + //Test if the segment has a vertex that is the South pole + if (geometry::get_as_radian<1>(p1) == - half_pi + || geometry::get_as_radian<1>(p2) == - half_pi) + { + state.south_vertex = true; + } else { + // Global max, min + state.max_lon = std::max(state.max_lon, max_lon); + state.min_lon = std::min(state.min_lon, min_lon); + } + + // Test if the segment has a point on northern hemisphere + if(state.south) + { + if(get<1>(p1) > 0 || get<1>(p2) > 0) + { + state.south = false; + } + } + state.sum += excess; + + std::cout << "(width=" << max_lon-min_lon << ")"; + } } inline return_type result(excess_sum const& state) const { + std::cout << "(pole=" << state.crosses_prime_meridian << ")"; + std::cout<<"(W="< -struct default_strategy -{ - typedef strategy::area::huiller type; -}; - -// Note: spherical polar coordinate system requires "get_as_radian_equatorial" -/***template -struct default_strategy -{ - typedef strategy::area::huiller type; -};***/ - -} // namespace services - -#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS - }} // namespace strategy::area - - }} // namespace boost::geometry #endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_AREA_HUILLER_HPP diff --git a/include/boost/geometry/strategies/spherical/area_trapezoidal.hpp b/include/boost/geometry/strategies/spherical/area_trapezoidal.hpp new file mode 100644 index 000000000..aacc7c8db --- /dev/null +++ b/include/boost/geometry/strategies/spherical/area_trapezoidal.hpp @@ -0,0 +1,192 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2016 Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fisikopoulos, 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_AREA_TRAPEZOIDAL_HPP +#define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_AREA_TRAPEZOIDAL_HPP + + +#include +#include + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace area +{ + + + +/*! +\brief Area calculation by trapezoidal rule + +} + +*/ +template +< + typename PointOfSegment, + typename CalculationType = void +> +class trapezoidal +{ +typedef typename boost::mpl::if_c + < + boost::is_void::type::value, + typename select_most_precise + < + typename coordinate_type::type, + double + >::type, + CalculationType + >::type calculation_type; + +protected : + struct excess_sum + { + calculation_type sum; + + // Keep track if encircles some pole + size_t crosses_prime_meridian; + + inline excess_sum() + : sum(0) + , crosses_prime_meridian(0) + {} + inline calculation_type area(calculation_type radius) const + { + calculation_type result; + + std::cout << "(sum=" << sum << ")"; + + // Encircles pole + if(crosses_prime_meridian % 2 == 1) + { + size_t times_crosses_prime_meridian + = 1 + (crosses_prime_meridian / 2); + + result = 2.0 + * geometry::math::pi() + * times_crosses_prime_meridian + - std::abs(sum); + + if(geometry::math::sign(sum) == 1) + { + result = - result; + } + + } else { + result = sum; + } + + result *= radius * radius; + + return result; + } + }; + +public : + typedef calculation_type return_type; + typedef PointOfSegment segment_point_type; + typedef excess_sum state_type; + + inline trapezoidal(calculation_type radius = 1.0) + : m_radius(radius) + {} + + inline void apply(PointOfSegment const& p1, + PointOfSegment const& p2, + excess_sum& state) const + { + if (! geometry::math::equals(get<0>(p1), get<0>(p2))) + { + calculation_type const two = 2.0; + calculation_type const pi + = geometry::math::pi(); + calculation_type const two_pi + = geometry::math::two_pi(); + calculation_type const half_pi + = geometry::math::half_pi(); + + // Trapezoidal formula + // + + calculation_type tan_lat1 = + tan(geometry::get_as_radian<1>(p1) / two); + calculation_type tan_lat2 = + tan(geometry::get_as_radian<1>(p2) / two); + + calculation_type excess = two + * atan(((tan_lat1 + tan_lat2) / (1 + tan_lat1 * tan_lat2)) + * tan((geometry::get_as_radian<0>(p2) + - geometry::get_as_radian<0>(p1)) / 2)); + + // Keep track whenever a segment crosses the prime meridian + // First normalize to [0,360) + + calculation_type p1_lon = get_as_radian<0>(p1) + - ( floor( get_as_radian<0>(p1) / two_pi ) * two_pi ); + calculation_type p2_lon = get_as_radian<0>(p2) + - ( floor( get_as_radian<0>(p2) / two_pi ) * two_pi ); + + calculation_type max_lon = std::max(p1_lon, p2_lon); + calculation_type min_lon = std::min(p1_lon, p2_lon); + + if(max_lon > pi && min_lon < pi && max_lon - min_lon > pi) + { + state.crosses_prime_meridian++; + } + + state.sum += excess; + } + } + + inline return_type result(excess_sum const& state) const + { + std::cout << "(tpole=" << state.crosses_prime_meridian << ")"; + return state.area(m_radius); + } + +private : + /// Radius of the sphere + calculation_type m_radius; +}; + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +namespace services +{ + + +template +struct default_strategy +{ + typedef strategy::area::trapezoidal type; +}; + +// Note: spherical polar coordinate system requires "get_as_radian_equatorial" +/***template +struct default_strategy +{ + typedef strategy::area::trapezoidal type; +};***/ + +} // namespace services + +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + + +}} // namespace strategy::area + + + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_AREA_TRAPEZOIDAL_HPP diff --git a/include/boost/geometry/strategies/strategies.hpp b/include/boost/geometry/strategies/strategies.hpp index 28850020a..c9fad5782 100644 --- a/include/boost/geometry/strategies/strategies.hpp +++ b/include/boost/geometry/strategies/strategies.hpp @@ -57,6 +57,7 @@ #include #include +#include #include #include #include From 271f427bdef05f9fdc9211a389fc29c32354b759 Mon Sep 17 00:00:00 2001 From: Vissarion Fysikopoulos Date: Mon, 18 Jul 2016 12:03:26 +0300 Subject: [PATCH 02/89] [area] formulas for spherical and geographic areas --- .../algorithms/detail/andoyer_inverse.hpp | 128 ++++--- .../algorithms/detail/result_inverse.hpp | 15 +- .../algorithms/detail/thomas_inverse.hpp | 66 +++- .../geometry/strategies/geographic/area.hpp | 324 ++++++++++++++++++ .../strategies/spherical/area_huiller.hpp | 9 +- .../boost/geometry/strategies/strategies.hpp | 1 + 6 files changed, 470 insertions(+), 73 deletions(-) create mode 100644 include/boost/geometry/strategies/geographic/area.hpp diff --git a/include/boost/geometry/algorithms/detail/andoyer_inverse.hpp b/include/boost/geometry/algorithms/detail/andoyer_inverse.hpp index 66ad6446e..057e2f02b 100644 --- a/include/boost/geometry/algorithms/detail/andoyer_inverse.hpp +++ b/include/boost/geometry/algorithms/detail/andoyer_inverse.hpp @@ -21,6 +21,7 @@ #include #include +//#include #include @@ -36,10 +37,22 @@ namespace boost { namespace geometry { namespace detail - Technical Report: PAUL D. THOMAS, SPHEROIDAL GEODESICS, REFERENCE SYSTEMS, AND LOCAL GEOMETRY, 1970 http://www.dtic.mil/docs/citations/AD703541 */ - -template -struct andoyer_inverse +template < + typename CT, + bool EnableDistance, + bool EnableAzimuth, + bool EnableReverseAzimuth = false, + bool EnableReducedLength = false, + bool EnableGeodesicScale = false +> +class andoyer_inverse { + static const bool CalcQuantities = EnableReducedLength || EnableGeodesicScale; + static const bool CalcAzimuths = EnableAzimuth || EnableReverseAzimuth || CalcQuantities; + static const bool CalcFwdAzimuth = EnableAzimuth || CalcQuantities; + static const bool CalcRevAzimuth = EnableReverseAzimuth || CalcQuantities; + +public: typedef result_inverse result_type; template @@ -49,20 +62,20 @@ struct andoyer_inverse T2 const& lat2, Spheroid const& spheroid) { - CT const c0 = CT(0); - CT const c1 = CT(1); - CT const pi = math::pi(); - result_type result; // coordinates in radians if ( math::equals(lon1, lon2) && math::equals(lat1, lat2) ) { - result.set(c0, c0); return result; } + CT const c0 = CT(0); + CT const c1 = CT(1); + CT const pi = math::pi(); + CT const f = detail::flattening(spheroid); + CT const dlon = lon2 - lon1; CT const sin_dlon = sin(dlon); CT const cos_dlon = cos(dlon); @@ -83,8 +96,6 @@ struct andoyer_inverse CT const d = acos(cos_d); // [0, pi] CT const sin_d = sin(d); // [-1, 1] - - CT const f = detail::flattening(spheroid); if ( BOOST_GEOMETRY_CONDITION(EnableDistance) ) { @@ -109,12 +120,8 @@ struct andoyer_inverse result.distance = a * (d + dd); } - else - { - result.distance = c0; - } - if ( BOOST_GEOMETRY_CONDITION(EnableAzimuth) ) + if ( BOOST_GEOMETRY_CONDITION(CalcAzimuths) ) { // sin_d = 0 <=> antipodal points if (math::equals(sin_d, c0)) @@ -142,60 +149,91 @@ struct andoyer_inverse U = (f/ c2)*math::sqr(cos_lat1)*sin_2A; } + CT B = c0; CT V = c0; if ( ! math::equals(cos_lat1, c0) ) { CT const tan_lat1 = sin_lat1/cos_lat1; CT const N = cos_lat2*tan_lat1-sin_lat2*cos_dlon; - CT const B = atan2(sin_dlon, N); + B = atan2(sin_dlon, N); CT const sin_2B = sin(c2*B); V = (f/ c2)*math::sqr(cos_lat2)*sin_2B; } CT const T = d / sin_d; - CT const dA = V*T-U; - - result.azimuth = A - dA; // even with sin_d == 0 checked above if the second point // is somewhere in the antipodal area T may still be great - // therefore dA may be great and the resulting azimuth - // may be some more or less arbitrary angle - if (A >= c0) // A indicates Eastern hemisphere + // therefore dA and dB may be great and the resulting azimuths + // may be some more or less arbitrary angles + + if (BOOST_GEOMETRY_CONDITION(CalcFwdAzimuth)) { - if (dA >= c0) // A altered towards 0 - { - if ((result.azimuth) < c0) - result.azimuth = c0; - } - else // dA < 0, A altered towards pi - { - if (result.azimuth > pi) - result.azimuth = pi; - } + CT const dA = V*T - U; + result.azimuth = A - dA; + normalize_azimuth(result.azimuth, A, dA); } - else // A indicates Western hemisphere + + if (BOOST_GEOMETRY_CONDITION(CalcRevAzimuth)) { - if (dA <= c0) // A altered towards 0 + CT const dB = -U*T + V; + result.reverse_azimuth = pi - B - dB; + if (result.reverse_azimuth > pi) { - if (result.azimuth > c0) - result.azimuth = c0; - } - else // dA > 0, A altered towards -pi - { - CT const minus_pi = -pi; - if ((result.azimuth) < minus_pi) - result.azimuth = minus_pi; + result.reverse_azimuth -= 2 * pi; } + normalize_azimuth(result.reverse_azimuth, B, dB); } } } - else +/* + if (BOOST_GEOMETRY_CONDITION(CalcQuantities)) { - result.azimuth = c0; + typedef inverse_differential_quantities quantities; + quantities::apply(dlon, sin_lat1, cos_lat1, sin_lat2, cos_lat2, + result.azimuth, result.reverse_azimuth, + get_radius<2>(spheroid), f, + result.reduced_length, result.geodesic_scale, + quantities::J12_calc_f1); } - +*/ return result; + + } + +private: + static inline void normalize_azimuth(CT & azimuth, CT const& A, CT const& dA) + { + CT const c0 = 0; + + if (A >= c0) // A indicates Eastern hemisphere + { + if (dA >= c0) // A altered towards 0 + { + if (azimuth < c0) + azimuth = c0; + } + else // dA < 0, A altered towards pi + { + CT const pi = math::pi(); + if (azimuth > pi) + azimuth = pi; + } + } + else // A indicates Western hemisphere + { + if (dA <= c0) // A altered towards 0 + { + if (azimuth > c0) + azimuth = c0; + } + else // dA > 0, A altered towards -pi + { + CT const minus_pi = -math::pi(); + if (azimuth < minus_pi) + azimuth = minus_pi; + } + } } }; diff --git a/include/boost/geometry/algorithms/detail/result_inverse.hpp b/include/boost/geometry/algorithms/detail/result_inverse.hpp index 01a1997e4..13960bd70 100644 --- a/include/boost/geometry/algorithms/detail/result_inverse.hpp +++ b/include/boost/geometry/algorithms/detail/result_inverse.hpp @@ -28,14 +28,19 @@ namespace boost { namespace geometry { namespace detail template struct result_inverse { - void set(T const& d, T const& a) - { - distance = d; - azimuth = a; - } + result_inverse() + : distance(0) + , azimuth(0) + , reverse_azimuth(0) + , reduced_length(0) + , geodesic_scale(1) + {} T distance; T azimuth; + T reverse_azimuth; + T reduced_length; + T geodesic_scale; }; }}} // namespace boost::geometry::detail diff --git a/include/boost/geometry/algorithms/detail/thomas_inverse.hpp b/include/boost/geometry/algorithms/detail/thomas_inverse.hpp index 96b237e05..35de56a81 100644 --- a/include/boost/geometry/algorithms/detail/thomas_inverse.hpp +++ b/include/boost/geometry/algorithms/detail/thomas_inverse.hpp @@ -21,8 +21,10 @@ #include #include +//#include #include + namespace boost { namespace geometry { namespace detail { @@ -35,9 +37,22 @@ namespace boost { namespace geometry { namespace detail - Technical Report: PAUL D. THOMAS, SPHEROIDAL GEODESICS, REFERENCE SYSTEMS, AND LOCAL GEOMETRY, 1970 http://www.dtic.mil/docs/citations/AD703541 */ -template -struct thomas_inverse +template < + typename CT, + bool EnableDistance, + bool EnableAzimuth, + bool EnableReverseAzimuth = false, + bool EnableReducedLength = false, + bool EnableGeodesicScale = false +> +class thomas_inverse { + static const bool CalcQuantities = EnableReducedLength || EnableGeodesicScale; + static const bool CalcAzimuths = EnableAzimuth || EnableReverseAzimuth || CalcQuantities; + static const bool CalcFwdAzimuth = EnableAzimuth || CalcQuantities; + static const bool CalcRevAzimuth = EnableReverseAzimuth || CalcQuantities; + +public: typedef result_inverse result_type; template @@ -51,13 +66,12 @@ struct thomas_inverse // coordinates in radians - if ( math::equals(lon1, lon2) - && math::equals(lat1, lat2) ) + if ( math::equals(lon1, lon2) && math::equals(lat1, lat2) ) { - result.set(CT(0), CT(0)); return result; } + CT const pi_half = math::pi() / CT(2); CT const f = detail::flattening(spheroid); CT const one_minus_f = CT(1) - f; @@ -66,7 +80,6 @@ struct thomas_inverse // CT const theta1 = atan(tan_theta1); // CT const theta2 = atan(tan_theta2); - CT const pi_half = math::pi() / CT(2); CT const theta1 = math::equals(lat1, pi_half) ? lat1 : math::equals(lat1, -pi_half) ? lat1 : atan(one_minus_f * tan(lat1)); @@ -102,7 +115,6 @@ struct thomas_inverse || math::equals(L, CT(0)) || math::equals(one_minus_L, CT(0)) ) { - result.set(CT(0), CT(0)); return result; } @@ -116,7 +128,7 @@ struct thomas_inverse //CT const A = D * E; //CT const B = CT(2) * D; //CT const C = T - (A - E) / CT(2); - + if ( BOOST_GEOMETRY_CONDITION(EnableDistance) ) { //CT const n1 = X * (A + C*X); @@ -134,12 +146,8 @@ struct thomas_inverse result.distance = a * sin_d * (T - delta1d); //double S2 = a * sin_d * (T - delta1d + delta2d); } - else - { - result.distance = CT(0); - } - - if ( BOOST_GEOMETRY_CONDITION(EnableAzimuth) ) + + if ( BOOST_GEOMETRY_CONDITION(CalcAzimuths) ) { // NOTE: if both cos_latX == 0 then below we'd have 0 * INF // it's a situation when the endpoints are on the poles +-90 deg @@ -175,12 +183,32 @@ struct thomas_inverse } result.azimuth = alpha1; - } - else - { - result.azimuth = CT(0); - } + CT alpha2 = pi - (v - u); + if (alpha2 > pi) + { + alpha2 -= CT(2) * pi; + } + + result.reverse_azimuth = alpha2; + } +/* + if (BOOST_GEOMETRY_CONDITION(CalcQuantities)) + { + CT const dlon = lon2 - lon1; + CT const sin_lat1 = sin(lat1); + CT const cos_lat1 = cos(lat1); + CT const sin_lat2 = sin(lat2); + CT const cos_lat2 = cos(lat2); + + typedef inverse_differential_quantities quantities; + quantities::apply(dlon, sin_lat1, cos_lat1, sin_lat2, cos_lat2, + result.azimuth, result.reverse_azimuth, + get_radius<2>(spheroid), f, + result.reduced_length, result.geodesic_scale, + quantities::J12_calc_f2); + } +*/ return result; } }; diff --git a/include/boost/geometry/strategies/geographic/area.hpp b/include/boost/geometry/strategies/geographic/area.hpp new file mode 100644 index 000000000..b28ab4c96 --- /dev/null +++ b/include/boost/geometry/strategies/geographic/area.hpp @@ -0,0 +1,324 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2016 Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fisikopoulos, 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_GEOGRAPHIC_AREA_HPP +#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_AREA_HPP + +#include +#include +#include +#include + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace area +{ + + + +/*! +\brief Area calculation by trapezoidal rule plus ellipsoidal correction + +} + +*/ +template +< + typename PointOfSegment, + typename CalculationType = void +> +class geographic_area +{ +typedef typename boost::mpl::if_c + < + boost::is_void::type::value, + typename select_most_precise + < + typename coordinate_type::type, + double + >::type, + CalculationType + >::type CT; + +protected : + struct excess_sum + { + CT sum; + + // Keep track if encircles some pole + size_t crosses_prime_meridian; + + inline excess_sum() + : sum(0) + , crosses_prime_meridian(0) + {} + inline CT area() const + { + CT result; + + std::cout << "(sum=" << sum << ")"; + + // Encircles pole + if(crosses_prime_meridian % 2 == 1) + { + size_t times_crosses_prime_meridian + = 1 + (crosses_prime_meridian / 2); + + result = 2.0 + * geometry::math::pi() + * times_crosses_prime_meridian + - std::abs(sum); + + if(geometry::math::sign(sum) == 1) + { + result = - result; + } + + } else { + result = sum; + } + + //result *= radius * radius; + + return result; + } + }; + +public : + typedef CT return_type; + typedef PointOfSegment segment_point_type; + typedef excess_sum state_type; + + inline geographic_area() + {} + + inline void apply(PointOfSegment const& p1, + PointOfSegment const& p2, + excess_sum& state) const + { + + if (! geometry::math::equals(get<0>(p1), get<0>(p2))) + { + // + //TODO: from shperical + // + CT const two = 2.0; + CT const pi + = geometry::math::pi(); + CT const two_pi + = geometry::math::two_pi(); + CT const half_pi + = geometry::math::half_pi(); + + // Trapezoidal formula + // + + CT tan_lat1 = + tan(geometry::get_as_radian<1>(p1) / two); + CT tan_lat2 = + tan(geometry::get_as_radian<1>(p2) / two); + + CT excess = two + * atan(((tan_lat1 + tan_lat2) / (1 + tan_lat1 * tan_lat2)) + * tan((geometry::get_as_radian<0>(p2) + - geometry::get_as_radian<0>(p1)) / 2)); + + + //GEO + + //TODO put it as member + geometry::srs::spheroid spheroid; + + //TODO compute only once for the whole polygon + CT const f = detail::flattening(spheroid); + CT const one_minus_f = 1.0 - f; + + CT const a = get_radius<0>(spheroid); //equitorial radius + CT const a2 = math::sqr(a); + CT const b = a * one_minus_f; //polar semi-minor axis + CT const b2 = math::sqr(b); + CT const e2 = f * (2.0 - f); + CT const e = math::sqrt(e2); + CT const ep2 = e2 / math::sqr(one_minus_f); + CT const ep = math::sqrt(ep2); + + CT const c2 = (a2 / 2.0) + ((b2 * std::atanh(e)) / (2.0 * e)); // authalic radius + //----upto here only once + + + int order = 2; + CT alp1, alp2; + + //FIRST ORDER Approximation + if(order == 1) + { + alp1 = geometry::detail::andoyer_inverse + < + CT, false, true + >::apply(get_as_radian<0>(p1), get_as_radian<1>(p1), + get_as_radian<0>(p2), get_as_radian<1>(p2), + spheroid).azimuth; + + alp2 = geometry::detail::andoyer_inverse + < + CT, false, true + >::apply(get_as_radian<0>(p1), get_as_radian<1>(p1), + get_as_radian<0>(p2), get_as_radian<1>(p2), + spheroid).reverse_azimuth; + } + //SECOND ORDER Approximation + if(order == 2) + { + alp1 = geometry::detail::thomas_inverse + < + CT, false, true + >::apply(get_as_radian<0>(p1), get_as_radian<1>(p1), + get_as_radian<0>(p2), get_as_radian<1>(p2), + spheroid).azimuth; + + alp2 = geometry::detail::thomas_inverse + < + CT, false, true + >::apply(get_as_radian<0>(p1), get_as_radian<1>(p1), + get_as_radian<0>(p2), get_as_radian<1>(p2), + spheroid).reverse_azimuth; + } + + //CT cos_a1 = geometry::math:cos(a1); + //CT sin_a1 = geometry::math:sin(a1); + //CT sin_ph1 = geometry::math:sin(get_as_radian<1>(p1)); + + //CT cos_a0 = std::hypot(cos_a1, sin_a1 * sin_ph1); + //CT sin_a0 = math::sqrt(1 - cos_a0 * cos_a0); + + CT cos_bet1 = cos(get_as_radian<1>(p1)); + CT cos_bet2 = cos(get_as_radian<1>(p2)); + + CT sin_alp1 = sin(alp1); + CT cos_alp1 = cos(alp1); + CT sin_alp2 = sin(alp2); + CT cos_alp2 = cos(alp2); + + CT sin_alp0 = sin_alp1 * cos_bet1; + CT cos_alp0 = math::sqrt(1 - math::sqr(sin_alp0)); //TODO: do it more accurate! + + //CT sin_sig1 = sin_bet1; + CT cos_sig1 = cos_alp1 * cos_bet1; + //CT sin_sig2 = sin_bet2; + CT cos_sig2 = cos_alp2 * cos_bet2; + + CT cos3_sig1 = 4.0 * std::pow(cos_sig1,3) - 3.0 * cos_sig1; + CT cos3_sig2 = 4.0 * std::pow(cos_sig2,3) - 3.0 * cos_sig2; + + CT k2 = math::sqr(ep * cos_alp0); + + CT I12; + + if(order == 1) + { + CT c_40 = ((2.0 / 3.0) - (1.0 / 15.0) * ep2) + - ((1.0 / 20.0) - (1.0 / 35.0) * ep2) * k2; + CT c_41 = ((1.0 / 180.0) - (1.0 / 315.0) * ep2) * k2; + + I12 = c_40 * (cos_sig2 - cos_sig1) + + c_41 * (cos3_sig2 - cos3_sig1); + } + if(order == 2) + { + CT ep4 = math::sqr(ep2); + CT k4 = math::sqr(k2); + + CT c_40 = ((2.0 / 3.0) - (1.0 / 15.0) * ep2 + + (4.0 / 105.0) * ep4) + - ((1.0 / 20.0) - (1.0 / 35.0) * ep2 + + (2.0 /105.0) * ep4) * k2 + + ((1.0 / 42.0) - (1.0 / 63.0) * ep2 + + (8.0 / 693.0) * ep4) * k4; + + CT c_41 = ((1.0 / 180.0) - (1.0 / 315.0) * ep2 + + (2.0 / 945.0) * ep4) * k2 + - ((1.0 / 252.0) - (1.0 / 378.0) * ep2 + + (4.0 / 2079.0) * ep4) * k4; + + CT c_42 = ((1.0 / 2100.0) - (1.0 / 3150.0) * ep2 + + (4.0 / 17325.0) * ep4) * k4; + + CT cos5_sig1 = 16.0 * std::pow(cos_sig1,5) + - 20.0 * std::pow(cos_sig1,3) + + 5.0 * cos_sig1; + CT cos5_sig2 = 16.0 * std::pow(cos_sig2,5) + - 20.0 * std::pow(cos_sig2,3) + + 5.0 * cos_sig2; + + I12 = c_40 * (cos_sig2 - cos_sig1) + + c_41 * (cos3_sig2 - cos3_sig1) + + c_42 * (cos5_sig2 - cos5_sig1); + } + + state.sum += excess * c2 + e2 * a2 * cos_alp0 * sin_alp0 * I12; + + // + //TODO: from shperical + // + // Keep track whenever a segment crosses the prime meridian + // First normalize to [0,360) + + CT p1_lon = get_as_radian<0>(p1) + - ( floor( get_as_radian<0>(p1) / two_pi ) * two_pi ); + CT p2_lon = get_as_radian<0>(p2) + - ( floor( get_as_radian<0>(p2) / two_pi ) * two_pi ); + + CT max_lon = std::max(p1_lon, p2_lon); + CT min_lon = std::min(p1_lon, p2_lon); + + if(max_lon > pi && min_lon < pi && max_lon - min_lon > pi) + { + state.crosses_prime_meridian++; + } + + + } + } + + inline return_type result(excess_sum const& state) const + { + return state.area(); + } + +//private : +// /// Radius of the sphere +// CT m_radius; +}; + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +namespace services +{ + + +template +struct default_strategy +{ + typedef strategy::area::geographic_area type; +}; + +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +} + +}} // namespace strategy::area + + + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_AREA_HPP diff --git a/include/boost/geometry/strategies/spherical/area_huiller.hpp b/include/boost/geometry/strategies/spherical/area_huiller.hpp index 447ef8ece..5b10eedea 100644 --- a/include/boost/geometry/strategies/spherical/area_huiller.hpp +++ b/include/boost/geometry/strategies/spherical/area_huiller.hpp @@ -242,12 +242,13 @@ public : || geometry::get_as_radian<1>(p2) == - half_pi) { state.south_vertex = true; - } else { - // Global max, min - state.max_lon = std::max(state.max_lon, max_lon); - state.min_lon = std::min(state.min_lon, min_lon); } + // Global max, min + state.max_lon = std::max(state.max_lon, max_lon); + state.min_lon = std::min(state.min_lon, min_lon); + + // Test if the segment has a point on northern hemisphere if(state.south) { diff --git a/include/boost/geometry/strategies/strategies.hpp b/include/boost/geometry/strategies/strategies.hpp index c9fad5782..b923e771f 100644 --- a/include/boost/geometry/strategies/strategies.hpp +++ b/include/boost/geometry/strategies/strategies.hpp @@ -64,6 +64,7 @@ #include #include +#include #include #include #include From 597efb93e533f86337e9dfa29b1f583e73897ad9 Mon Sep 17 00:00:00 2001 From: Vissarion Fysikopoulos Date: Tue, 2 Aug 2016 18:15:51 +0300 Subject: [PATCH 03/89] [area] functional functions for spherical and geographic area --- include/boost/geometry/algorithms/area.hpp | 1 - .../geometry/formulas/andoyer_inverse.hpp | 54 +--- .../geometry/formulas/geographic_area.hpp | 220 ++++++++++++++ .../geometry/strategies/geographic/area.hpp | 276 +++++------------- .../strategies/spherical/area_trapezoidal.hpp | 60 +--- 5 files changed, 318 insertions(+), 293 deletions(-) create mode 100644 include/boost/geometry/formulas/geographic_area.hpp diff --git a/include/boost/geometry/algorithms/area.hpp b/include/boost/geometry/algorithms/area.hpp index cb1501d8c..1d68b2c37 100644 --- a/include/boost/geometry/algorithms/area.hpp +++ b/include/boost/geometry/algorithms/area.hpp @@ -320,5 +320,4 @@ inline typename Strategy::return_type area( }} // namespace boost::geometry - #endif // BOOST_GEOMETRY_ALGORITHMS_AREA_HPP diff --git a/include/boost/geometry/formulas/andoyer_inverse.hpp b/include/boost/geometry/formulas/andoyer_inverse.hpp index 0a8079a09..a419d0489 100644 --- a/include/boost/geometry/formulas/andoyer_inverse.hpp +++ b/include/boost/geometry/formulas/andoyer_inverse.hpp @@ -21,11 +21,6 @@ #include #include -<<<<<<< HEAD:include/boost/geometry/algorithms/detail/andoyer_inverse.hpp -//#include -#include -======= ->>>>>>> 50d9fe37d893aaa3844afcf8a5d0e69142dcd642:include/boost/geometry/formulas/andoyer_inverse.hpp #include #include @@ -102,11 +97,7 @@ public: CT const d = acos(cos_d); // [0, pi] CT const sin_d = sin(d); // [-1, 1] -<<<<<<< HEAD:include/boost/geometry/algorithms/detail/andoyer_inverse.hpp -======= - ->>>>>>> 50d9fe37d893aaa3844afcf8a5d0e69142dcd642:include/boost/geometry/formulas/andoyer_inverse.hpp if ( BOOST_GEOMETRY_CONDITION(EnableDistance) ) { CT const K = math::sqr(sin_lat1-sin_lat2); @@ -196,63 +187,22 @@ public: } } } -<<<<<<< HEAD:include/boost/geometry/algorithms/detail/andoyer_inverse.hpp -/* - if (BOOST_GEOMETRY_CONDITION(CalcQuantities)) - { - typedef inverse_differential_quantities quantities; -======= + if (BOOST_GEOMETRY_CONDITION(CalcQuantities)) { typedef differential_quantities quantities; ->>>>>>> 50d9fe37d893aaa3844afcf8a5d0e69142dcd642:include/boost/geometry/formulas/andoyer_inverse.hpp quantities::apply(dlon, sin_lat1, cos_lat1, sin_lat2, cos_lat2, result.azimuth, result.reverse_azimuth, get_radius<2>(spheroid), f, result.reduced_length, result.geodesic_scale, quantities::J12_calc_f1); } -*/ + return result; } -private: - static inline void normalize_azimuth(CT & azimuth, CT const& A, CT const& dA) - { - CT const c0 = 0; - - if (A >= c0) // A indicates Eastern hemisphere - { - if (dA >= c0) // A altered towards 0 - { - if (azimuth < c0) - azimuth = c0; - } - else // dA < 0, A altered towards pi - { - CT const pi = math::pi(); - if (azimuth > pi) - azimuth = pi; - } - } - else // A indicates Western hemisphere - { - if (dA <= c0) // A altered towards 0 - { - if (azimuth > c0) - azimuth = c0; - } - else // dA > 0, A altered towards -pi - { - CT const minus_pi = -math::pi(); - if (azimuth < minus_pi) - azimuth = minus_pi; - } - } - } - private: static inline void normalize_azimuth(CT & azimuth, CT const& A, CT const& dA) { diff --git a/include/boost/geometry/formulas/geographic_area.hpp b/include/boost/geometry/formulas/geographic_area.hpp new file mode 100644 index 000000000..ac13e3881 --- /dev/null +++ b/include/boost/geometry/formulas/geographic_area.hpp @@ -0,0 +1,220 @@ +// Boost.Geometry + +// Copyright (c) 2015-2016 Oracle and/or its affiliates. + +// Contributed and/or modified by Vissarion Fysikopoulos, 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_FORMULAS_GEOGRAPHIC_AREA_HPP +#define BOOST_GEOMETRY_FORMULAS_GEOGRAPHIC_AREA_HPP + +#include +#include +#include + +namespace boost { namespace geometry { namespace formula +{ + +/*! +\brief Formulas for computing spherical and ellipsoidal polygon area. + The current class computes the area of the trapezoid defined by a segment + the two meridians passing by the endpoints and the equator. +\author See +- Charles F.F Karney, Algorithms for geodesics, 2011 +https://arxiv.org/pdf/1109.4448.pdf +*/ + +template < + typename CT +> +class geographic_area +{ + +public: + + template < + typename PointOfSegment, + bool LongSegment = false + > + static inline CT spherical_excess(PointOfSegment const& p1, + PointOfSegment const& p2) + { + //Spherical excess computation + + CT excess; + + if(LongSegment) + { + //TODO: TO BE IMPLEMENTED + excess = 0; + + } else { // Trapezoidal formula + CT tan_lat1 = + tan(geometry::get_as_radian<1>(p1) / 2.0); + CT tan_lat2 = + tan(geometry::get_as_radian<1>(p2) / 2.0); + + excess = 2.0 + * atan(((tan_lat1 + tan_lat2) / (1 + tan_lat1 * tan_lat2)) + * tan((geometry::get_as_radian<0>(p2) + - geometry::get_as_radian<0>(p1)) / 2)); + } + + return excess; + } + + template < + typename AzimuthStrategy, + size_t SeriesOrder = 2, + typename PointOfSegment, + typename SpheroidConst + > + static inline CT ellipsoidal_correction(PointOfSegment const& p1, + PointOfSegment const& p2, + SpheroidConst spheroid_const) + { + + //Azimuth Approximation + + CT alp1, alp2; + + + alp1 = AzimuthStrategy::apply(get_as_radian<0>(p1), + get_as_radian<1>(p1), + get_as_radian<0>(p2), + get_as_radian<1>(p2), + spheroid_const.spheroid).azimuth; + + alp2 = AzimuthStrategy::apply(get_as_radian<0>(p1), + get_as_radian<1>(p1), + get_as_radian<0>(p2), + get_as_radian<1>(p2), + spheroid_const.spheroid).reverse_azimuth; + //Integral approximation + + CT result; + + + // Epsoidal constants + CT const a2 = spheroid_const.a2; + CT const e2 = spheroid_const.e2; + CT const ep2 = spheroid_const.ep2; + CT const ep = spheroid_const.ep; + CT const c2 = spheroid_const.c2; // authalic radius + + + //CT cos_a1 = geometry::math:cos(a1); + //CT sin_a1 = geometry::math:sin(a1); + //CT sin_ph1 = geometry::math:sin(get_as_radian<1>(p1)); + + //CT cos_a0 = std::hypot(cos_a1, sin_a1 * sin_ph1); + //CT sin_a0 = math::sqrt(1 - cos_a0 * cos_a0); + + CT cos_bet1 = cos(get_as_radian<1>(p1)); + CT cos_bet2 = cos(get_as_radian<1>(p2)); + + CT sin_alp1 = sin(alp1); + CT cos_alp1 = cos(alp1); + //CT sin_alp2 = sin(alp2); + CT cos_alp2 = cos(alp2); + + CT sin_alp0 = sin_alp1 * cos_bet1; + //TODO: do it more accurate! + CT cos_alp0 = math::sqrt(1 - math::sqr(sin_alp0)); + + //CT sin_sig1 = sin_bet1; + CT cos_sig1 = cos_alp1 * cos_bet1; + //CT sin_sig2 = sin_bet2; + CT cos_sig2 = cos_alp2 * cos_bet2; + + CT cos3_sig1 = 4.0 * std::pow(cos_sig1,3) - 3.0 * cos_sig1; + CT cos3_sig2 = 4.0 * std::pow(cos_sig2,3) - 3.0 * cos_sig2; + + CT k2 = math::sqr(ep * cos_alp0); + + CT I12; + + if(SeriesOrder == 1) + { + CT c_40 = ((2.0 / 3.0) - (1.0 / 15.0) * ep2) + - ((1.0 / 20.0) - (1.0 / 35.0) * ep2) * k2; + CT c_41 = ((1.0 / 180.0) - (1.0 / 315.0) * ep2) * k2; + + I12 = c_40 * (cos_sig2 - cos_sig1) + + c_41 * (cos3_sig2 - cos3_sig1); + } + if(SeriesOrder == 2) + { + CT ep4 = math::sqr(ep2); + CT k4 = math::sqr(k2); + + CT c_40 = ((2.0 / 3.0) - (1.0 / 15.0) * ep2 + + (4.0 / 105.0) * ep4) + - ((1.0 / 20.0) - (1.0 / 35.0) * ep2 + + (2.0 /105.0) * ep4) * k2 + + ((1.0 / 42.0) - (1.0 / 63.0) * ep2 + + (8.0 / 693.0) * ep4) * k4; + + CT c_41 = ((1.0 / 180.0) - (1.0 / 315.0) * ep2 + + (2.0 / 945.0) * ep4) * k2 + - ((1.0 / 252.0) - (1.0 / 378.0) * ep2 + + (4.0 / 2079.0) * ep4) * k4; + + CT c_42 = ((1.0 / 2100.0) - (1.0 / 3150.0) * ep2 + + (4.0 / 17325.0) * ep4) * k4; + + CT cos5_sig1 = 16.0 * std::pow(cos_sig1,5) + - 20.0 * std::pow(cos_sig1,3) + + 5.0 * cos_sig1; + CT cos5_sig2 = 16.0 * std::pow(cos_sig2,5) + - 20.0 * std::pow(cos_sig2,3) + + 5.0 * cos_sig2; + + I12 = c_40 * (cos_sig2 - cos_sig1) + + c_41 * (cos3_sig2 - cos3_sig1) + + c_42 * (cos5_sig2 - cos5_sig1); + } + + return cos_alp0 * sin_alp0 * I12; + + } + + // Keep track whenever a segment crosses the prime meridian + // First normalize to [0,360) + template + static inline int crosses_prime_meridian(PointOfSegment const& p1, + PointOfSegment const& p2, + StateType& state) + { + CT const pi + = geometry::math::pi(); + CT const two_pi + = geometry::math::two_pi(); + + CT p1_lon = get_as_radian<0>(p1) + - ( floor( get_as_radian<0>(p1) / two_pi ) + * two_pi ); + CT p2_lon = get_as_radian<0>(p2) + - ( floor( get_as_radian<0>(p2) / two_pi ) + * two_pi ); + + CT max_lon = std::max(p1_lon, p2_lon); + CT min_lon = std::min(p1_lon, p2_lon); + + if(max_lon > pi && min_lon < pi && max_lon - min_lon > pi) + { + state.crosses_prime_meridian++; + } + + return state.crosses_prime_meridian; + } + +}; + +}}} // namespace boost::geometry::formula + + +#endif // BOOST_GEOMETRY_FORMULAS_GEOGRAPHIC_AREA_HPP diff --git a/include/boost/geometry/strategies/geographic/area.hpp b/include/boost/geometry/strategies/geographic/area.hpp index b28ab4c96..3f346f73f 100644 --- a/include/boost/geometry/strategies/geographic/area.hpp +++ b/include/boost/geometry/strategies/geographic/area.hpp @@ -10,11 +10,9 @@ #ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_AREA_HPP #define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_AREA_HPP -#include -#include #include #include - +#include namespace boost { namespace geometry { @@ -22,17 +20,18 @@ namespace boost { namespace geometry namespace strategy { namespace area { - - /*! \brief Area calculation by trapezoidal rule plus ellipsoidal correction } */ + template < typename PointOfSegment, + typename Strategy = void, + typename Spheroid = void, typename CalculationType = void > class geographic_area @@ -48,25 +47,73 @@ typedef typename boost::mpl::if_c CalculationType >::type CT; +//If strategy not set select default strategy for azimuth computation +typedef typename boost::mpl::if_c + < + boost::is_void::type::value, + typename geometry::formula::thomas_inverse + < + CT, + false, + true, + true + >, + Strategy + >::type AzimuthStrategy; + +typedef typename boost::mpl::if_c + < + boost::is_void::type::value, + geometry::srs::spheroid, + Spheroid + >::type SpheroidType; + protected : - struct excess_sum + struct spheroid_constants { - CT sum; + SpheroidType spheroid; + CT const a2; // squared equatorial radius + CT const e2; // squared eccentricity + CT const ep2; // squared second eccentricity + CT const ep; // second eccentricity + CT const c2; // authalic radius + + inline spheroid_constants(SpheroidType spheroid) + : spheroid(spheroid) + , a2(math::sqr(get_radius<0>(spheroid))) + , e2(detail::flattening(spheroid) + * (2.0 - detail::flattening(spheroid))) + , ep2(e2 / (1 - e2)) + , ep(math::sqrt(ep2)) + , c2((a2 / 2.0) + + ((math::sqr(get_radius<2>(spheroid)) * std::atanh(math::sqrt(e2))) + / (2.0 * math::sqrt(e2)))) + {} + }; + + struct spheroid_param + { + CT excess_sum; + CT correction_sum; // Keep track if encircles some pole size_t crosses_prime_meridian; - inline excess_sum() - : sum(0) + inline spheroid_param() + : excess_sum(0) + , correction_sum(0) , crosses_prime_meridian(0) {} - inline CT area() const + inline CT area(spheroid_constants spheroid_const) const { CT result; - std::cout << "(sum=" << sum << ")"; + CT sum = spheroid_const.c2 * excess_sum + + spheroid_const.e2 * spheroid_const.a2 * correction_sum; - // Encircles pole + std::cout << "(result=" << result << ")"; + + // If encircles some pole if(crosses_prime_meridian % 2 == 1) { size_t times_crosses_prime_meridian @@ -74,6 +121,7 @@ protected : result = 2.0 * geometry::math::pi() + * spheroid_const.c2 * times_crosses_prime_meridian - std::abs(sum); @@ -83,11 +131,9 @@ protected : } } else { - result = sum; + result = sum; } - //result *= radius * radius; - return result; } }; @@ -95,207 +141,45 @@ protected : public : typedef CT return_type; typedef PointOfSegment segment_point_type; - typedef excess_sum state_type; + typedef spheroid_param state_type; - inline geographic_area() + inline geographic_area(SpheroidType spheroid) + : spheroid_const(spheroid) {} inline void apply(PointOfSegment const& p1, PointOfSegment const& p2, - excess_sum& state) const + spheroid_param& state) const { if (! geometry::math::equals(get<0>(p1), get<0>(p2))) { - // - //TODO: from shperical - // - CT const two = 2.0; - CT const pi - = geometry::math::pi(); - CT const two_pi - = geometry::math::two_pi(); - CT const half_pi - = geometry::math::half_pi(); - // Trapezoidal formula - // - - CT tan_lat1 = - tan(geometry::get_as_radian<1>(p1) / two); - CT tan_lat2 = - tan(geometry::get_as_radian<1>(p2) / two); - - CT excess = two - * atan(((tan_lat1 + tan_lat2) / (1 + tan_lat1 * tan_lat2)) - * tan((geometry::get_as_radian<0>(p2) - - geometry::get_as_radian<0>(p1)) / 2)); + //Compute the trapezoidal area + state.excess_sum += geometry::formula::geographic_area + + ::spherical_excess(p1, p2); - //GEO + state.correction_sum += geometry::formula::geographic_area + ::template ellipsoidal_correction + (p1, p2, spheroid_const); - //TODO put it as member - geometry::srs::spheroid spheroid; - - //TODO compute only once for the whole polygon - CT const f = detail::flattening(spheroid); - CT const one_minus_f = 1.0 - f; - - CT const a = get_radius<0>(spheroid); //equitorial radius - CT const a2 = math::sqr(a); - CT const b = a * one_minus_f; //polar semi-minor axis - CT const b2 = math::sqr(b); - CT const e2 = f * (2.0 - f); - CT const e = math::sqrt(e2); - CT const ep2 = e2 / math::sqr(one_minus_f); - CT const ep = math::sqrt(ep2); - - CT const c2 = (a2 / 2.0) + ((b2 * std::atanh(e)) / (2.0 * e)); // authalic radius - //----upto here only once - - - int order = 2; - CT alp1, alp2; - - //FIRST ORDER Approximation - if(order == 1) - { - alp1 = geometry::detail::andoyer_inverse - < - CT, false, true - >::apply(get_as_radian<0>(p1), get_as_radian<1>(p1), - get_as_radian<0>(p2), get_as_radian<1>(p2), - spheroid).azimuth; - - alp2 = geometry::detail::andoyer_inverse - < - CT, false, true - >::apply(get_as_radian<0>(p1), get_as_radian<1>(p1), - get_as_radian<0>(p2), get_as_radian<1>(p2), - spheroid).reverse_azimuth; - } - //SECOND ORDER Approximation - if(order == 2) - { - alp1 = geometry::detail::thomas_inverse - < - CT, false, true - >::apply(get_as_radian<0>(p1), get_as_radian<1>(p1), - get_as_radian<0>(p2), get_as_radian<1>(p2), - spheroid).azimuth; - - alp2 = geometry::detail::thomas_inverse - < - CT, false, true - >::apply(get_as_radian<0>(p1), get_as_radian<1>(p1), - get_as_radian<0>(p2), get_as_radian<1>(p2), - spheroid).reverse_azimuth; - } - - //CT cos_a1 = geometry::math:cos(a1); - //CT sin_a1 = geometry::math:sin(a1); - //CT sin_ph1 = geometry::math:sin(get_as_radian<1>(p1)); - - //CT cos_a0 = std::hypot(cos_a1, sin_a1 * sin_ph1); - //CT sin_a0 = math::sqrt(1 - cos_a0 * cos_a0); - - CT cos_bet1 = cos(get_as_radian<1>(p1)); - CT cos_bet2 = cos(get_as_radian<1>(p2)); - - CT sin_alp1 = sin(alp1); - CT cos_alp1 = cos(alp1); - CT sin_alp2 = sin(alp2); - CT cos_alp2 = cos(alp2); - - CT sin_alp0 = sin_alp1 * cos_bet1; - CT cos_alp0 = math::sqrt(1 - math::sqr(sin_alp0)); //TODO: do it more accurate! - - //CT sin_sig1 = sin_bet1; - CT cos_sig1 = cos_alp1 * cos_bet1; - //CT sin_sig2 = sin_bet2; - CT cos_sig2 = cos_alp2 * cos_bet2; - - CT cos3_sig1 = 4.0 * std::pow(cos_sig1,3) - 3.0 * cos_sig1; - CT cos3_sig2 = 4.0 * std::pow(cos_sig2,3) - 3.0 * cos_sig2; - - CT k2 = math::sqr(ep * cos_alp0); - - CT I12; - - if(order == 1) - { - CT c_40 = ((2.0 / 3.0) - (1.0 / 15.0) * ep2) - - ((1.0 / 20.0) - (1.0 / 35.0) * ep2) * k2; - CT c_41 = ((1.0 / 180.0) - (1.0 / 315.0) * ep2) * k2; - - I12 = c_40 * (cos_sig2 - cos_sig1) - + c_41 * (cos3_sig2 - cos3_sig1); - } - if(order == 2) - { - CT ep4 = math::sqr(ep2); - CT k4 = math::sqr(k2); - - CT c_40 = ((2.0 / 3.0) - (1.0 / 15.0) * ep2 - + (4.0 / 105.0) * ep4) - - ((1.0 / 20.0) - (1.0 / 35.0) * ep2 - + (2.0 /105.0) * ep4) * k2 - + ((1.0 / 42.0) - (1.0 / 63.0) * ep2 - + (8.0 / 693.0) * ep4) * k4; - - CT c_41 = ((1.0 / 180.0) - (1.0 / 315.0) * ep2 - + (2.0 / 945.0) * ep4) * k2 - - ((1.0 / 252.0) - (1.0 / 378.0) * ep2 - + (4.0 / 2079.0) * ep4) * k4; - - CT c_42 = ((1.0 / 2100.0) - (1.0 / 3150.0) * ep2 - + (4.0 / 17325.0) * ep4) * k4; - - CT cos5_sig1 = 16.0 * std::pow(cos_sig1,5) - - 20.0 * std::pow(cos_sig1,3) - + 5.0 * cos_sig1; - CT cos5_sig2 = 16.0 * std::pow(cos_sig2,5) - - 20.0 * std::pow(cos_sig2,3) - + 5.0 * cos_sig2; - - I12 = c_40 * (cos_sig2 - cos_sig1) - + c_41 * (cos3_sig2 - cos3_sig1) - + c_42 * (cos5_sig2 - cos5_sig1); - } - - state.sum += excess * c2 + e2 * a2 * cos_alp0 * sin_alp0 * I12; - - // - //TODO: from shperical - // // Keep track whenever a segment crosses the prime meridian - // First normalize to [0,360) - - CT p1_lon = get_as_radian<0>(p1) - - ( floor( get_as_radian<0>(p1) / two_pi ) * two_pi ); - CT p2_lon = get_as_radian<0>(p2) - - ( floor( get_as_radian<0>(p2) / two_pi ) * two_pi ); - - CT max_lon = std::max(p1_lon, p2_lon); - CT min_lon = std::min(p1_lon, p2_lon); - - if(max_lon > pi && min_lon < pi && max_lon - min_lon > pi) - { - state.crosses_prime_meridian++; - } - - + geometry::formula::geographic_area + + ::crosses_prime_meridian(p1, p2, state); } } - inline return_type result(excess_sum const& state) const + inline return_type result(spheroid_param const& state) const { - return state.area(); + return state.area(spheroid_const); } -//private : -// /// Radius of the sphere -// CT m_radius; +private: + spheroid_constants spheroid_const; + }; #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS diff --git a/include/boost/geometry/strategies/spherical/area_trapezoidal.hpp b/include/boost/geometry/strategies/spherical/area_trapezoidal.hpp index aacc7c8db..a6a417efb 100644 --- a/include/boost/geometry/strategies/spherical/area_trapezoidal.hpp +++ b/include/boost/geometry/strategies/spherical/area_trapezoidal.hpp @@ -13,7 +13,7 @@ #include #include - +#include namespace boost { namespace geometry { @@ -45,12 +45,12 @@ typedef typename boost::mpl::if_c double >::type, CalculationType - >::type calculation_type; + >::type CT; protected : struct excess_sum { - calculation_type sum; + CT sum; // Keep track if encircles some pole size_t crosses_prime_meridian; @@ -59,9 +59,9 @@ protected : : sum(0) , crosses_prime_meridian(0) {} - inline calculation_type area(calculation_type radius) const + inline CT area(CT radius) const { - calculation_type result; + CT result; std::cout << "(sum=" << sum << ")"; @@ -72,11 +72,11 @@ protected : = 1 + (crosses_prime_meridian / 2); result = 2.0 - * geometry::math::pi() + * geometry::math::pi() * times_crosses_prime_meridian - std::abs(sum); - if(geometry::math::sign(sum) == 1) + if(geometry::math::sign(sum) == 1) { result = - result; } @@ -92,11 +92,11 @@ protected : }; public : - typedef calculation_type return_type; + typedef CT return_type; typedef PointOfSegment segment_point_type; typedef excess_sum state_type; - inline trapezoidal(calculation_type radius = 1.0) + inline trapezoidal(CT radius = 1.0) : m_radius(radius) {} @@ -106,44 +106,16 @@ public : { if (! geometry::math::equals(get<0>(p1), get<0>(p2))) { - calculation_type const two = 2.0; - calculation_type const pi - = geometry::math::pi(); - calculation_type const two_pi - = geometry::math::two_pi(); - calculation_type const half_pi - = geometry::math::half_pi(); - // Trapezoidal formula - // - - calculation_type tan_lat1 = - tan(geometry::get_as_radian<1>(p1) / two); - calculation_type tan_lat2 = - tan(geometry::get_as_radian<1>(p2) / two); - - calculation_type excess = two - * atan(((tan_lat1 + tan_lat2) / (1 + tan_lat1 * tan_lat2)) - * tan((geometry::get_as_radian<0>(p2) - - geometry::get_as_radian<0>(p1)) / 2)); + state.sum += geometry::formula::geographic_area + + ::spherical_excess(p1, p2); // Keep track whenever a segment crosses the prime meridian - // First normalize to [0,360) + geometry::formula::geographic_area + + ::crosses_prime_meridian(p1, p2, state); - calculation_type p1_lon = get_as_radian<0>(p1) - - ( floor( get_as_radian<0>(p1) / two_pi ) * two_pi ); - calculation_type p2_lon = get_as_radian<0>(p2) - - ( floor( get_as_radian<0>(p2) / two_pi ) * two_pi ); - - calculation_type max_lon = std::max(p1_lon, p2_lon); - calculation_type min_lon = std::min(p1_lon, p2_lon); - - if(max_lon > pi && min_lon < pi && max_lon - min_lon > pi) - { - state.crosses_prime_meridian++; - } - - state.sum += excess; } } @@ -155,7 +127,7 @@ public : private : /// Radius of the sphere - calculation_type m_radius; + CT m_radius; }; #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS From 31235117f432d124f80e13003b81ed60e5d3c876 Mon Sep 17 00:00:00 2001 From: Vissarion Fysikopoulos Date: Wed, 10 Aug 2016 12:29:14 +0300 Subject: [PATCH 04/89] [area] series evaluation for spherical and geographic area --- .../extensions/contrib/ttmath_stub.hpp | 7 + .../formulas/differential_quantities.hpp | 24 +- .../geometry/formulas/geographic_area.hpp | 296 ++++++++++++++---- .../geometry/strategies/geographic/area.hpp | 69 ++-- 4 files changed, 299 insertions(+), 97 deletions(-) diff --git a/include/boost/geometry/extensions/contrib/ttmath_stub.hpp b/include/boost/geometry/extensions/contrib/ttmath_stub.hpp index 91ef63eb1..b095fc7e5 100644 --- a/include/boost/geometry/extensions/contrib/ttmath_stub.hpp +++ b/include/boost/geometry/extensions/contrib/ttmath_stub.hpp @@ -7,6 +7,7 @@ // This file was modified by Oracle on 2014, 2015. // Modifications copyright (c) 2014-2015, Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fisikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library @@ -82,6 +83,12 @@ namespace ttmath return ATan(v); } + template + inline Big atanh(Big const& v) + { + return ATanh(v); + } + template inline Big acos(Big const& v) { diff --git a/include/boost/geometry/formulas/differential_quantities.hpp b/include/boost/geometry/formulas/differential_quantities.hpp index 0b5e14d92..5fb69fd3a 100644 --- a/include/boost/geometry/formulas/differential_quantities.hpp +++ b/include/boost/geometry/formulas/differential_quantities.hpp @@ -63,7 +63,7 @@ public: CT & reduced_length, CT & geodesic_scale, J12Calc J12_calc) { - CT one_minus_f = 1 - f; + CT one_minus_f = CT(1) - f; CT sin_bet1 = one_minus_f * sin_lat1; CT sin_bet2 = one_minus_f * sin_lat2; @@ -102,13 +102,13 @@ public: normalize(sin_sig2, cos_sig2); CT sin_alp0 = sin_alp1 * cos_bet1; - CT cos_alp0_sqr = 1 - math::sqr(sin_alp0); + CT cos_alp0_sqr = CT(1) - math::sqr(sin_alp0); CT const J12 = J12_calc(sin_sig1, cos_sig1, sin_sig2, cos_sig2, cos_alp0_sqr, f); - CT const e2 = f * (2 - f); - CT const dn1 = math::sqrt(1 + e2 * math::sqr(sin_lat1)); - CT const dn2 = math::sqrt(1 + e2 * math::sqr(sin_lat2)); + CT const e2 = f * (CT(2) - f); + CT const dn1 = math::sqrt(CT(1) + e2 * math::sqr(sin_lat1)); + CT const dn2 = math::sqrt(CT(1) + e2 * math::sqr(sin_lat2)); if (BOOST_GEOMETRY_CONDITION(EnableReducedLength)) { @@ -153,17 +153,17 @@ public: { CT const sig12 = atan2(cos_sig1 * sin_sig2 - sin_sig1 * cos_sig2, cos_sig1 * cos_sig2 + sin_sig1 * sin_sig2); - CT const sin_2sig1 = 2 * cos_sig1 * sin_sig1; // sin(2sig1) - CT const sin_2sig2 = 2 * cos_sig2 * sin_sig2; // sin(2sig2) + CT const sin_2sig1 = CT(2) * cos_sig1 * sin_sig1; // sin(2sig1) + CT const sin_2sig2 = CT(2) * cos_sig2 * sin_sig2; // sin(2sig2) CT const sin_2sig12 = sin_2sig2 - sin_2sig1; - CT const sin_4sig1 = 2 * sin_2sig1 * (math::sqr(cos_sig1) - math::sqr(sin_sig1)); // sin(4sig1) - CT const sin_4sig2 = 2 * sin_2sig2 * (math::sqr(cos_sig2) - math::sqr(sin_sig2)); // sin(4sig2) + CT const sin_4sig1 = CT(2) * sin_2sig1 * (math::sqr(cos_sig1) - math::sqr(sin_sig1)); // sin(4sig1) + CT const sin_4sig2 = CT(2) * sin_2sig2 * (math::sqr(cos_sig2) - math::sqr(sin_sig2)); // sin(4sig2) CT const sin_4sig12 = sin_4sig2 - sin_4sig1; - CT const t1 = 2 * sig12 - sin_2sig12; + CT const t1 = CT(2) * sig12 - sin_2sig12; CT const t2 = cos_alp0_sqr * sin_4sig12 - + (-8 * cos_alp0_sqr + 12) * sin_2sig12 - + (12 * cos_alp0_sqr - 24) * sig12; + + (-CT(8) * cos_alp0_sqr + CT(12)) * sin_2sig12 + + (CT(12) * cos_alp0_sqr - CT(24)) * sig12; CT const J12 = cos_alp0_sqr * f * (t1 / 2 - f * t2 / 16); return J12; diff --git a/include/boost/geometry/formulas/geographic_area.hpp b/include/boost/geometry/formulas/geographic_area.hpp index ac13e3881..61ddd7eb0 100644 --- a/include/boost/geometry/formulas/geographic_area.hpp +++ b/include/boost/geometry/formulas/geographic_area.hpp @@ -28,16 +28,82 @@ https://arxiv.org/pdf/1109.4448.pdf */ template < - typename CT + typename CT, + const std::size_t SeriesOrder = 2, + bool LongSegment = false > class geographic_area { public: + /* + Evaluate the polynomial in x, of coefficients + CoefficientsOfPolynomial, using Horner's method. + */ + template + static inline CT HornerEvaluate(CT x, + IteratorType begin, + IteratorType end) + { + CT result(0); + IteratorType it = end; + do{ + result = result * x + *--it; + }while(it != begin); + return result; + } + + + /* + Evaluate the series given the set of coefficients A[] + */ + static inline void EvaluateSeries(CT eps, + CT A[], + CT c_4[]){ + std::size_t begin(0), end(0); + for(std::size_t i = 0; i <= SeriesOrder; i++){ + end = begin + SeriesOrder + 1 - i; + //replace pow() + c_4[i] = pow(eps,i) * + HornerEvaluate(eps, + A + begin, + A + end); + begin = end; + } + //E.g. for SeriesOrder = 2 + //c_4[0] = HornerEvaluate(eps, A, A + 3); + //c_4[1] = eps * HornerEvaluate(eps, A + 3, A + 5); + //c_4[2] = eps * eps * HornerEvaluate(eps, A + 5, A + 6); + // + //CT c_40 = _C4x[0] + eps * (_C4x[1] + eps * _C4x[2]); + //CT c_41 = eps * (_C4x[3] + eps * (_C4x[4])); + //CT c_42 = eps * (eps * _C4x[5]); + } + + /* + Clenshaw algorithm for summing trigonometric series + */ + static inline CT ClenshawSum(CT cosx, + const CT c[]) + { + int n = 2 * SeriesOrder + 1; + CT b_k, b_k1(0), b_k2(0); + do{ + CT c_k = n % 2 ? c[n / 2] : CT(0); + b_k = c_k + CT(2) * cosx * b_k1 - b_k2; + b_k2 = b_k1; + b_k1 = b_k; + }while(--n); + + return c[0] + b_k1 * cosx - b_k2; + } + + /* + Compute the spherical excess of a geodesic (or shperical) segment + */ template < - typename PointOfSegment, - bool LongSegment = false + typename PointOfSegment > static inline CT spherical_excess(PointOfSegment const& p1, PointOfSegment const& p2) @@ -48,8 +114,24 @@ public: if(LongSegment) { - //TODO: TO BE IMPLEMENTED - excess = 0; + CT cbet1 = cos(geometry::get_as_radian<1>(p1)); + CT sbet1 = sin(geometry::get_as_radian<1>(p1)); + CT cbet2 = cos(geometry::get_as_radian<1>(p2)); + CT sbet2 = sin(geometry::get_as_radian<1>(p2)); + CT omg12 = geometry::get_as_radian<0>(p1) + - geometry::get_as_radian<0>(p2); + CT comg12 = cos(omg12); + CT somg12 = sin(omg12); + + CT alp1 = atan2(cbet1 * sbet2 + - sbet1 * cbet2 * comg12, + cbet2 * somg12); + + CT alp2 = atan2(cbet1 * sbet2 * comg12 + - sbet1 * cbet2, + cbet1 * somg12); + + excess = alp2 - alp1; } else { // Trapezoidal formula CT tan_lat1 = @@ -57,8 +139,8 @@ public: CT tan_lat2 = tan(geometry::get_as_radian<1>(p2) / 2.0); - excess = 2.0 - * atan(((tan_lat1 + tan_lat2) / (1 + tan_lat1 * tan_lat2)) + excess = CT(2.0) + * atan(((tan_lat1 + tan_lat2) / (CT(1) + tan_lat1 * tan_lat2)) * tan((geometry::get_as_radian<0>(p2) - geometry::get_as_radian<0>(p1)) / 2)); } @@ -66,9 +148,11 @@ public: return excess; } + /* + Compute the ellipsoidal correction of a geodesic (or shperical) segment + */ template < typename AzimuthStrategy, - size_t SeriesOrder = 2, typename PointOfSegment, typename SpheroidConst > @@ -77,7 +161,8 @@ public: SpheroidConst spheroid_const) { - //Azimuth Approximation + + // 1. Azimuth Approximation CT alp1, alp2; @@ -93,18 +178,12 @@ public: get_as_radian<0>(p2), get_as_radian<1>(p2), spheroid_const.spheroid).reverse_azimuth; - //Integral approximation - - CT result; - + // 2. Integral approximation // Epsoidal constants - CT const a2 = spheroid_const.a2; - CT const e2 = spheroid_const.e2; - CT const ep2 = spheroid_const.ep2; + //CT const ep2 = spheroid_const.ep2; CT const ep = spheroid_const.ep; - CT const c2 = spheroid_const.c2; // authalic radius - + CT const f = detail::flattening(spheroid_const.spheroid); //CT cos_a1 = geometry::math:cos(a1); //CT sin_a1 = geometry::math:sin(a1); @@ -115,6 +194,8 @@ public: CT cos_bet1 = cos(get_as_radian<1>(p1)); CT cos_bet2 = cos(get_as_radian<1>(p2)); + //CT sin_bet1 = sin(get_as_radian<1>(p1)); + //CT sin_bet2 = sin(get_as_radian<1>(p2)); CT sin_alp1 = sin(alp1); CT cos_alp1 = cos(alp1); @@ -123,60 +204,163 @@ public: CT sin_alp0 = sin_alp1 * cos_bet1; //TODO: do it more accurate! - CT cos_alp0 = math::sqrt(1 - math::sqr(sin_alp0)); + CT cos_alp0 = math::sqrt(CT(1) - math::sqr(sin_alp0)); //CT sin_sig1 = sin_bet1; CT cos_sig1 = cos_alp1 * cos_bet1; //CT sin_sig2 = sin_bet2; CT cos_sig2 = cos_alp2 * cos_bet2; - CT cos3_sig1 = 4.0 * std::pow(cos_sig1,3) - 3.0 * cos_sig1; - CT cos3_sig2 = 4.0 * std::pow(cos_sig2,3) - 3.0 * cos_sig2; - CT k2 = math::sqr(ep * cos_alp0); - CT I12; + CT sqrt_k2_plus_one = math::sqrt(CT(1) + k2); + CT eps = (sqrt_k2_plus_one - 1) / (sqrt_k2_plus_one + 1); + CT n = f / (CT(2) - f); - if(SeriesOrder == 1) - { - CT c_40 = ((2.0 / 3.0) - (1.0 / 15.0) * ep2) - - ((1.0 / 20.0) - (1.0 / 35.0) * ep2) * k2; - CT c_41 = ((1.0 / 180.0) - (1.0 / 315.0) * ep2) * k2; + const std::size_t C4_size = ((SeriesOrder + 2) * (SeriesOrder + 1)) / 2; + CT _C4x[C4_size]; - I12 = c_40 * (cos_sig2 - cos_sig1) - + c_41 * (cos3_sig2 - cos3_sig1); + switch(SeriesOrder + 1){ + case 0: + break; + case 1: + _C4x[0] = 2.0/3.0; + break; + case 2: + _C4x[0] = (10.0-4.0*n)/15.0; + _C4x[1] = -1.0/5.0; + _C4x[2] = 1.0/45.0; + //Alternatively... + //{CT A[][C4_size] = { {10, -4, 15}, + // {-1, 5}, + // {1, 45} }; + //_C4x[0] = HornerEvaluate(n, A[0], A[0] + 2) / A[0][2]; + //_C4x[1] = HornerEvaluate(n, A[1], A[1] + 1) / A[1][1]; + //_C4x[2] = HornerEvaluate(n, A[2], A[2] + 1) / A[2][1];} + break; + case 3: + _C4x[0] = (n*(8.0*n-28.0)+70.0)/105.0; + _C4x[1] = (16.0*n-7.0)/35.0; + _C4x[2] = -2.0/105.0; + _C4x[3] = (7.0-16.0*n)/315.0; + _C4x[4] = -2.0/105.0; + _C4x[5] = 4.0/525.0; + break; + case 4: + _C4x[0] = (n*(n*(4.*n+24.)-84.)+210.)/315.; + _C4x[1] = ((48.-32.*n)*n-21.)/105.; + _C4x[2] = (-32.*n-6.)/315; + _C4x[3] = 11./315; + _C4x[4] = (n*(32.*n-48.)+21.)/945; + _C4x[5] = (64.*n-18.)/945; + _C4x[6] = -1./105; + _C4x[7] = (12.-32*n)/1575; + _C4x[8] = -8./1575; + _C4x[9] = 8./2205; + break; + case 5: + _C4x[0] = (n*(n*(n*(16.*n+44)+264)-924)+2310)/3465; + _C4x[1] = (n*(n*(48.*n-352)+528)-231)/1155; + _C4x[2] = (n*(1088.*n-352)-66)/3465; + _C4x[3] = (121.-368*n)/3465; + _C4x[4] = 4./1155; + _C4x[5] = (n*((352.-48*n)*n-528)+231)/10395; + _C4x[6] = ((704.-896*n)*n-198)/10395; + _C4x[7] = (80*n-99)/10395; + _C4x[8] = 4./1155; + _C4x[9] = (n*(320.*n-352)+132)/17325; + _C4x[10] = (384.*n-88)/17325; + _C4x[11] = -8./1925; + _C4x[12] = (88.-256*n)/24255; + _C4x[13] = -16./8085; + _C4x[14] = 64./31185; + break; + case 6: + _C4x[0] = (n*(n*(n*(n*(100.*n+208)+572)+3432)-12012)+30030)/45045; + _C4x[1] = (n*(n*(n*(64.*n+624)-4576)+6864)-3003)/15015; + _C4x[2] = (n*((14144.-10656*n)*n-4576)-858)/45045; + _C4x[3] = ((-224.*n-4784)*n+1573)/45045; + _C4x[4] = (1088.*n+156)/45045; + _C4x[5] = 97./15015; + _C4x[6] = (n*(n*((-64.*n-624)*n+4576)-6864)+3003)/135135; + _C4x[7] = (n*(n*(5952*n-11648)+9152)-2574)/135135; + _C4x[8] = (n*(5792.*n+1040)-1287)/135135; + _C4x[9] = (468.-2944*n)/135135; + _C4x[10] = 1./9009; + _C4x[11] = (n*((4160.-1440*n)*n-4576)+1716)/225225; + _C4x[12] = ((4992.-8448*n)*n-1144)/225225; + _C4x[13] = (1856.*n-936)/225225; + _C4x[14] = 8./10725; + _C4x[15] = (n*(3584.*n-3328)+1144)/315315; + _C4x[16] = (1024.*n-208)/105105; + _C4x[17] = -136./63063; + _C4x[18] = (832.-2560*n)/405405; + _C4x[19] = -128./135135; + _C4x[20] = 128./99099; + break; } - if(SeriesOrder == 2) - { - CT ep4 = math::sqr(ep2); - CT k4 = math::sqr(k2); - CT c_40 = ((2.0 / 3.0) - (1.0 / 15.0) * ep2 - + (4.0 / 105.0) * ep4) - - ((1.0 / 20.0) - (1.0 / 35.0) * ep2 - + (2.0 /105.0) * ep4) * k2 - + ((1.0 / 42.0) - (1.0 / 63.0) * ep2 - + (8.0 / 693.0) * ep4) * k4; + CT c_4[SeriesOrder + 1]; + EvaluateSeries(eps,_C4x,c_4); - CT c_41 = ((1.0 / 180.0) - (1.0 / 315.0) * ep2 - + (2.0 / 945.0) * ep4) * k2 - - ((1.0 / 252.0) - (1.0 / 378.0) * ep2 - + (4.0 / 2079.0) * ep4) * k4; + CT I12 = ClenshawSum(cos_sig2, c_4) + - ClenshawSum(cos_sig1, c_4); - CT c_42 = ((1.0 / 2100.0) - (1.0 / 3150.0) * ep2 - + (4.0 / 17325.0) * ep4) * k4; + //CT cos3_sig1 = CT(4.0) * cos_sig1 * cos_sig1 * cos_sig1 - CT(3.0) * cos_sig1; + //CT cos3_sig2 = CT(4.0) * cos_sig2 * cos_sig2 * cos_sig2 - CT(3.0) * cos_sig2; - CT cos5_sig1 = 16.0 * std::pow(cos_sig1,5) - - 20.0 * std::pow(cos_sig1,3) - + 5.0 * cos_sig1; - CT cos5_sig2 = 16.0 * std::pow(cos_sig2,5) - - 20.0 * std::pow(cos_sig2,3) - + 5.0 * cos_sig2; + /* + if(SeriesOrder == 1) + { + //CT c_40 = (CT(2) / CT(3) - CT(4) / CT(15) * n) + // - CT(1) / CT(5) * eps; + //CT c_41 = CT(1) / CT(45) * eps; - I12 = c_40 * (cos_sig2 - cos_sig1) - + c_41 * (cos3_sig2 - cos3_sig1) - + c_42 * (cos5_sig2 - cos5_sig1); - } + //CT c_40 = _C4x[0] + _C4x[1] * eps; + //CT c_41 = _C4x[2] * eps; + + //I12 = c_4[0] * (cos_sig2 - cos_sig1) + // + c_4[1] * (cos3_sig2 - cos3_sig1); + } + if(SeriesOrder == 2) + { + // CT n2 = math::sqr(n); + // CT eps2 = math::sqr(eps); + + //CT c_40 = (CT(2) / CT(3) - CT(4) / CT(15) * n + CT(8) / CT(105) * n2) + // - (CT(1) / CT(5) - CT(16) / CT(35) * n) * eps + // - (CT(2) / CT(105)) * eps2; + + //CT c_41 = (CT(1) / CT(45) - CT(16) / CT(315) * n) * eps + // - (CT(2) / CT(105)) * eps2; + + //CT c_42 = (CT(4) / CT(525)) * eps2; + + //c_4[0] = HornerEvaluate(eps, _C4x, _C4x + 3); + //c_4[1] = eps * HornerEvaluate(eps, _C4x + 3, _C4x + 5); + //c_4[2] = eps * eps * HornerEvaluate(eps, _C4x + 5, _C4x + 6); + //CT c_40 = _C4x[0] + eps * (_C4x[1] + eps * _C4x[2]); + //CT c_41 = eps * (_C4x[3] + eps * (_C4x[4])); + //CT c_42 = eps * (eps * _C4x[5]); + + + + CT cos5_sig1 = CT(16) + * cos_sig1 * cos_sig1 * cos_sig1 * cos_sig1 * cos_sig1 + - CT(20) + * cos_sig1 * cos_sig1 * cos_sig1 + + CT(5) * cos_sig1; + CT cos5_sig2 = CT(16) + * cos_sig2 * cos_sig2 * cos_sig2 * cos_sig2 * cos_sig2 + - CT(20) + * cos_sig2 * cos_sig2 * cos_sig2 + + CT(5) * cos_sig2; + + I12 = c_4[0] * (cos_sig2 - cos_sig1) + + c_4[1] * (cos3_sig2 - cos3_sig1) + + c_4[2] * (cos5_sig2 - cos5_sig1); + +*/ return cos_alp0 * sin_alp0 * I12; diff --git a/include/boost/geometry/strategies/geographic/area.hpp b/include/boost/geometry/strategies/geographic/area.hpp index 3f346f73f..ede2860cf 100644 --- a/include/boost/geometry/strategies/geographic/area.hpp +++ b/include/boost/geometry/strategies/geographic/area.hpp @@ -13,6 +13,7 @@ #include #include #include +#include namespace boost { namespace geometry { @@ -31,12 +32,17 @@ template < typename PointOfSegment, typename Strategy = void, + const std::size_t SeriesOrder = 2, typename Spheroid = void, typename CalculationType = void > class geographic_area { -typedef typename boost::mpl::if_c + + //Select default types for Strategy, Spheroid and CalculationType + //in case they are not set + + typedef typename boost::mpl::if_c < boost::is_void::type::value, typename select_most_precise @@ -47,8 +53,7 @@ typedef typename boost::mpl::if_c CalculationType >::type CT; -//If strategy not set select default strategy for azimuth computation -typedef typename boost::mpl::if_c + typedef typename boost::mpl::if_c < boost::is_void::type::value, typename geometry::formula::thomas_inverse @@ -61,7 +66,7 @@ typedef typename boost::mpl::if_c Strategy >::type AzimuthStrategy; -typedef typename boost::mpl::if_c + typedef typename boost::mpl::if_c < boost::is_void::type::value, geometry::srs::spheroid, @@ -82,24 +87,27 @@ protected : : spheroid(spheroid) , a2(math::sqr(get_radius<0>(spheroid))) , e2(detail::flattening(spheroid) - * (2.0 - detail::flattening(spheroid))) - , ep2(e2 / (1 - e2)) + * (CT(2.0) - CT(detail::flattening(spheroid)))) + , ep2(e2 / (CT(1.0) - e2)) , ep(math::sqrt(ep2)) - , c2((a2 / 2.0) + - ((math::sqr(get_radius<2>(spheroid)) * std::atanh(math::sqrt(e2))) - / (2.0 * math::sqrt(e2)))) + , c2((a2 / CT(2.0)) + + ((math::sqr(get_radius<2>(spheroid)) +// * 1) + * atanh(math::sqrt(e2))) +// * std::atanh(math::sqrt(e2))) + / (CT(2.0) * math::sqrt(e2)))) {} }; - struct spheroid_param + struct area_sums { CT excess_sum; CT correction_sum; // Keep track if encircles some pole - size_t crosses_prime_meridian; + std::size_t crosses_prime_meridian; - inline spheroid_param() + inline area_sums() : excess_sum(0) , correction_sum(0) , crosses_prime_meridian(0) @@ -111,19 +119,17 @@ protected : CT sum = spheroid_const.c2 * excess_sum + spheroid_const.e2 * spheroid_const.a2 * correction_sum; - std::cout << "(result=" << result << ")"; - // If encircles some pole if(crosses_prime_meridian % 2 == 1) { - size_t times_crosses_prime_meridian + std::size_t times_crosses_prime_meridian = 1 + (crosses_prime_meridian / 2); - result = 2.0 + result = CT(2.0) * geometry::math::pi() * spheroid_const.c2 - * times_crosses_prime_meridian - - std::abs(sum); + * CT(times_crosses_prime_meridian) + - geometry::math::abs(sum); if(geometry::math::sign(sum) == 1) { @@ -141,15 +147,15 @@ protected : public : typedef CT return_type; typedef PointOfSegment segment_point_type; - typedef spheroid_param state_type; + typedef area_sums state_type; - inline geographic_area(SpheroidType spheroid) + inline geographic_area(SpheroidType spheroid = SpheroidType()) : spheroid_const(spheroid) {} inline void apply(PointOfSegment const& p1, PointOfSegment const& p2, - spheroid_param& state) const + area_sums& state) const { if (! geometry::math::equals(get<0>(p1), get<0>(p2))) @@ -157,22 +163,27 @@ public : //Compute the trapezoidal area state.excess_sum += geometry::formula::geographic_area - - ::spherical_excess(p1, p2); - + + ::template spherical_excess(p1, p2); state.correction_sum += geometry::formula::geographic_area - ::template ellipsoidal_correction - (p1, p2, spheroid_const); + + ::template ellipsoidal_correction + + (p1, p2, spheroid_const); + + //std::cout << "current excess=" << state.excess_sum + // << " correction=" << state.correction_sum + // << std::endl; // Keep track whenever a segment crosses the prime meridian geometry::formula::geographic_area - - ::crosses_prime_meridian(p1, p2, state); + + ::crosses_prime_meridian(p1, p2, state); } } - inline return_type result(spheroid_param const& state) const + inline return_type result(area_sums const& state) const { return state.area(spheroid_const); } From fb092ca86db6bd14e7f7bc0d6b0db08355f28d2d Mon Sep 17 00:00:00 2001 From: Vissarion Fysikopoulos Date: Fri, 12 Aug 2016 21:58:24 +0300 Subject: [PATCH 05/89] [area] maxima code; Clenshaw and Horner algorithms; fix an error (reduced length) --- .../algorithms/detail/calculate_sum.hpp | 6 +- .../extensions/contrib/ttmath_stub.hpp | 9 + .../boost/geometry/formulas/area_formulas.hpp | 500 ++++++++++++++++++ .../geometry/formulas/geographic_area.hpp | 404 -------------- .../{area.hpp => area_geographic.hpp} | 100 ++-- .../strategies/spherical/area_huiller.hpp | 12 +- ...rea_trapezoidal.hpp => area_spherical.hpp} | 57 +- .../boost/geometry/strategies/strategies.hpp | 7 +- test/algorithms/area.cpp | 12 +- 9 files changed, 598 insertions(+), 509 deletions(-) create mode 100644 include/boost/geometry/formulas/area_formulas.hpp delete mode 100644 include/boost/geometry/formulas/geographic_area.hpp rename include/boost/geometry/strategies/geographic/{area.hpp => area_geographic.hpp} (57%) rename include/boost/geometry/strategies/spherical/{area_trapezoidal.hpp => area_spherical.hpp} (65%) diff --git a/include/boost/geometry/algorithms/detail/calculate_sum.hpp b/include/boost/geometry/algorithms/detail/calculate_sum.hpp index b23e70171..732a2f575 100644 --- a/include/boost/geometry/algorithms/detail/calculate_sum.hpp +++ b/include/boost/geometry/algorithms/detail/calculate_sum.hpp @@ -8,6 +8,10 @@ // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. +// This file was modified by Oracle on 2016. +// Modifications copyright (c) 2016 Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fysikopoulos, 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) @@ -30,7 +34,7 @@ class calculate_polygon_sum template static inline ReturnType sum_interior_rings(Rings const& rings, Strategy const& strategy) { - ReturnType sum = ReturnType(); + ReturnType sum = ReturnType(0); for (typename boost::range_iterator::type it = boost::begin(rings); it != boost::end(rings); ++it) { diff --git a/include/boost/geometry/extensions/contrib/ttmath_stub.hpp b/include/boost/geometry/extensions/contrib/ttmath_stub.hpp index b095fc7e5..0469fd2a7 100644 --- a/include/boost/geometry/extensions/contrib/ttmath_stub.hpp +++ b/include/boost/geometry/extensions/contrib/ttmath_stub.hpp @@ -35,6 +35,15 @@ namespace ttmath return Sqrt(v); } + template + inline Big pow(Big const& v, + int n) + { + Big tmp(v); + tmp.Pow(n); + return tmp; + } + template inline Big abs(Big const& v) { diff --git a/include/boost/geometry/formulas/area_formulas.hpp b/include/boost/geometry/formulas/area_formulas.hpp new file mode 100644 index 000000000..8f6558fb4 --- /dev/null +++ b/include/boost/geometry/formulas/area_formulas.hpp @@ -0,0 +1,500 @@ +// Boost.Geometry + +// Copyright (c) 2015-2016 Oracle and/or its affiliates. + +// Contributed and/or modified by Vissarion Fysikopoulos, 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_FORMULAS_AREA_FORMULAS_HPP +#define BOOST_GEOMETRY_FORMULAS_AREA_FORMULAS_HPP + +#include + +namespace boost { namespace geometry { namespace formula +{ + +/*! +\brief Formulas for computing spherical and ellipsoidal polygon area. + The current class computes the area of the trapezoid defined by a segment + the two meridians passing by the endpoints and the equator. +\author See +- Charles F.F Karney, Algorithms for geodesics, 2011 +https://arxiv.org/pdf/1109.4448.pdf +*/ + +template < + typename CT, + const std::size_t SeriesOrder = 2, + bool ExpandEpsN = true, + bool LongSegment = false +> +class area_formulas +{ + +public: + + //TODO: move Horner and Clenshaw to a more general space + /* + Evaluate the polynomial in x using Horner's method. + */ + template + static inline NT HornerEvaluate(NT x, + IteratorType begin, + IteratorType end) + { + NT result(0); + IteratorType it = end; + do{ + result = result * x + *--it; + }while(it != begin); + return result; + } + + /* + Clenshaw algorithm for summing trigonometric series + https://en.wikipedia.org/wiki/Clenshaw_algorithm + */ + template + static inline NT ClenshawSum(NT cosx, + IteratorType begin, + IteratorType end) + { + IteratorType it = end; + bool odd(true); + CT b_k, b_k1(0), b_k2(0); + do{ + CT c_k = odd ? *--it : NT(0); + b_k = c_k + NT(2) * cosx * b_k1 - b_k2; + b_k2 = b_k1; + b_k1 = b_k; + odd = !odd; + }while(it != begin); + + return *begin + b_k1 * cosx - b_k2; + } + + /* + Evaluate the series expansion of the following integral + + I4 = -integrate( (t(ep2) - t(k2*sin(sigma1)^2)) / (ep2 - k2*sin(sigma1)^2) + * sin(sigma1)/2, sigma1, pi/2, sigma ) + where + + t(x) = sqrt(1+1/x)*asinh(sqrt(x)) + x + + valid for ep2 and k2 small. We substitute k2 = 4 * eps / (1 - eps)^2 + and ep2 = 4 * n / (1 - n)^2 and expand in eps and n. + + The resulting sum of the series is of the form + + sum(C4[l] * cos((2*l+1)*sigma), l, 0, maxpow-1) ) + + The above expansion is performed in Computer Algebra System Maxima. + The C++ code (that yields the function GenerateCoeffs1 below) is generated + by the following Maxima script and is based on script: + http://geographiclib.sourceforge.net/html/geod.mac + + // Maxima script begin + taylordepth:5$ + ataylor(expr,var,ord):=expand(ratdisrep(taylor(expr,var,0,ord)))$ + jtaylor(expr,var1,var2,ord):=block([zz],expand(subst([zz=1], + ratdisrep(taylor(subst([var1=zz*var1,var2=zz*var2],expr),zz,0,ord)))))$ + + compute(maxpow):=block([int,t,intexp,area, x,ep2,k2], + maxpow:maxpow-1, + t : sqrt(1+1/x) * asinh(sqrt(x)) + x, + int:-(tf(ep2) - tf(k2*sin(sigma)^2)) / (ep2 - k2*sin(sigma)^2) + * sin(sigma)/2, + int:subst([tf(ep2)=subst([x=ep2],t), + tf(k2*sin(sigma)^2)=subst([x=k2*sin(sigma)^2],t)], + int), + int:subst([abs(sin(sigma))=sin(sigma)],int), + int:subst([k2=4*eps/(1-eps)^2,ep2=4*n/(1-n)^2],int), + intexp:jtaylor(int,n,eps,maxpow), + area:trigreduce(integrate(intexp,sigma)), + area:expand(area-subst(sigma=%pi/2,area)), + for i:0 thru maxpow do C4[i]:coeff(area,cos((2*i+1)*sigma)), + if expand(area-sum(C4[i]*cos((2*i+1)*sigma),i,0,maxpow)) # 0 + then error("left over terms in I4"), + 'done)$ + + printcode(maxpow):= + block([tab2:" ",tab3:" "], + print(" switch (SeriesOrder) {"), + for nn:1 thru maxpow do block([c], + print(concat(tab2,"case ",string(nn-1),":")), + c:0, + for m:0 thru nn-1 do block( + [q:jtaylor(subst([n=n],C4[m]),n,eps,nn-1), + linel:1200], + for j:m thru nn-1 do ( + print(concat(tab3,"coeffs_n[",c,"] = ", + string(horner(coeff(q,eps,j))),";")), + c:c+1) + ), + print(concat(tab3,"break;"))), + print(" }"), + 'done)$ + + maxpow:6$ + compute(maxpow)$ + printcode(maxpow)$ + // Maxima script end + + In the resulting code we should replace each number x by CT(x) + e.g. using the following scirpt: + sed -e 's/[0-9]\+/CT(&)/g; s/\[CT(/\[/g; s/)\]/\]/g; + s/case\sCT(/case /g; s/):/:/g' + */ + + static inline void GenerateCoeffs1(CT n, CT coeffs_n[]) + { + + switch (SeriesOrder) { + case 0: + coeffs_n[0] = CT(2)/CT(3); + break; + case 1: + coeffs_n[0] = (CT(10)-CT(4)*n)/CT(15); + coeffs_n[1] = -CT(1)/CT(5); + coeffs_n[2] = CT(1)/CT(45); + break; + case 2: + coeffs_n[0] = (n*(CT(8)*n-CT(28))+CT(70))/CT(105); + coeffs_n[1] = (CT(16)*n-CT(7))/CT(35); + coeffs_n[2] = -CT(2)/CT(105); + coeffs_n[3] = (CT(7)-CT(16)*n)/CT(315); + coeffs_n[4] = -CT(2)/CT(105); + coeffs_n[5] = CT(4)/CT(525); + break; + case 3: + coeffs_n[0] = (n*(n*(CT(4)*n+CT(24))-CT(84))+CT(210))/CT(315); + coeffs_n[1] = ((CT(48)-CT(32)*n)*n-CT(21))/CT(105); + coeffs_n[2] = (-CT(32)*n-CT(6))/CT(315); + coeffs_n[3] = CT(11)/CT(315); + coeffs_n[4] = (n*(CT(32)*n-CT(48))+CT(21))/CT(945); + coeffs_n[5] = (CT(64)*n-CT(18))/CT(945); + coeffs_n[6] = -CT(1)/CT(105); + coeffs_n[7] = (CT(12)-CT(32)*n)/CT(1575); + coeffs_n[8] = -CT(8)/CT(1575); + coeffs_n[9] = CT(8)/CT(2205); + break; + case 4: + coeffs_n[0] = (n*(n*(n*(CT(16)*n+CT(44))+CT(264))-CT(924))+CT(2310))/CT(3465); + coeffs_n[1] = (n*(n*(CT(48)*n-CT(352))+CT(528))-CT(231))/CT(1155); + coeffs_n[2] = (n*(CT(1088)*n-CT(352))-CT(66))/CT(3465); + coeffs_n[3] = (CT(121)-CT(368)*n)/CT(3465); + coeffs_n[4] = CT(4)/CT(1155); + coeffs_n[5] = (n*((CT(352)-CT(48)*n)*n-CT(528))+CT(231))/CT(10395); + coeffs_n[6] = ((CT(704)-CT(896)*n)*n-CT(198))/CT(10395); + coeffs_n[7] = (CT(80)*n-CT(99))/CT(10395); + coeffs_n[8] = CT(4)/CT(1155); + coeffs_n[9] = (n*(CT(320)*n-CT(352))+CT(132))/CT(17325); + coeffs_n[10] = (CT(384)*n-CT(88))/CT(17325); + coeffs_n[11] = -CT(8)/CT(1925); + coeffs_n[12] = (CT(88)-CT(256)*n)/CT(24255); + coeffs_n[13] = -CT(16)/CT(8085); + coeffs_n[14] = CT(64)/CT(31185); + break; + case 5: + coeffs_n[0] = (n*(n*(n*(n*(CT(100)*n+CT(208))+CT(572))+CT(3432))-CT(12012))+CT(30030)) + /CT(45045); + coeffs_n[1] = (n*(n*(n*(CT(64)*n+CT(624))-CT(4576))+CT(6864))-CT(3003))/CT(15015); + coeffs_n[2] = (n*((CT(14144)-CT(10656)*n)*n-CT(4576))-CT(858))/CT(45045); + coeffs_n[3] = ((-CT(224)*n-CT(4784))*n+CT(1573))/CT(45045); + coeffs_n[4] = (CT(1088)*n+CT(156))/CT(45045); + coeffs_n[5] = CT(97)/CT(15015); + coeffs_n[6] = (n*(n*((-CT(64)*n-CT(624))*n+CT(4576))-CT(6864))+CT(3003))/CT(135135); + coeffs_n[7] = (n*(n*(CT(5952)*n-CT(11648))+CT(9152))-CT(2574))/CT(135135); + coeffs_n[8] = (n*(CT(5792)*n+CT(1040))-CT(1287))/CT(135135); + coeffs_n[9] = (CT(468)-CT(2944)*n)/CT(135135); + coeffs_n[10] = CT(1)/CT(9009); + coeffs_n[11] = (n*((CT(4160)-CT(1440)*n)*n-CT(4576))+CT(1716))/CT(225225); + coeffs_n[12] = ((CT(4992)-CT(8448)*n)*n-CT(1144))/CT(225225); + coeffs_n[13] = (CT(1856)*n-CT(936))/CT(225225); + coeffs_n[14] = CT(8)/CT(10725); + coeffs_n[15] = (n*(CT(3584)*n-CT(3328))+CT(1144))/CT(315315); + coeffs_n[16] = (CT(1024)*n-CT(208))/CT(105105); + coeffs_n[17] = -CT(136)/CT(63063); + coeffs_n[18] = (CT(832)-CT(2560)*n)/CT(405405); + coeffs_n[19] = -CT(128)/CT(135135); + coeffs_n[20] = CT(128)/CT(99099); + break; + } + } + + /* + Expand in k2 and ep2. + */ + static inline void GenerateCoeffs1b(CT ep, CT coeffs_n[]) + { + switch (SeriesOrder) { + case 0: + coeffs_n[0] = CT(2)/CT(3); + break; + case 1: + coeffs_n[0] = (CT(10)-ep)/CT(15); + coeffs_n[1] = -CT(1)/CT(20); + coeffs_n[2] = CT(1)/CT(180); + break; + case 2: + coeffs_n[0] = (ep*(CT(4)*ep-CT(7))+CT(70))/CT(105); + coeffs_n[1] = (CT(4)*ep-CT(7))/CT(140); + coeffs_n[2] = CT(1)/CT(42); + coeffs_n[3] = (CT(7)-CT(4)*ep)/CT(1260); + coeffs_n[4] = -CT(1)/CT(252); + coeffs_n[5] = CT(1)/CT(2100); + break; + case 3: + coeffs_n[0] = (ep*((CT(12)-CT(8)*ep)*ep-CT(21))+CT(210))/CT(315); + coeffs_n[1] = ((CT(12)-CT(8)*ep)*ep-CT(21))/CT(420); + coeffs_n[2] = (CT(3)-CT(2)*ep)/CT(126); + coeffs_n[3] = -CT(1)/CT(72); + coeffs_n[4] = (ep*(CT(8)*ep-CT(12))+CT(21))/CT(3780); + coeffs_n[5] = (CT(2)*ep-CT(3))/CT(756); + coeffs_n[6] = CT(1)/CT(360); + coeffs_n[7] = (CT(3)-CT(2)*ep)/CT(6300); + coeffs_n[8] = -CT(1)/CT(1800); + coeffs_n[9] = CT(1)/CT(17640); + break; + case 4: + coeffs_n[0] = (ep*(ep*(ep*(CT(64)*ep-CT(88))+CT(132))-CT(231))+CT(2310))/CT(3465); + coeffs_n[1] = (ep*(ep*(CT(64)*ep-CT(88))+CT(132))-CT(231))/CT(4620); + coeffs_n[2] = (ep*(CT(16)*ep-CT(22))+CT(33))/CT(1386); + coeffs_n[3] = (CT(8)*ep-CT(11))/CT(792); + coeffs_n[4] = CT(1)/CT(110); + coeffs_n[5] = (ep*((CT(88)-CT(64)*ep)*ep-CT(132))+CT(231))/CT(41580); + coeffs_n[6] = ((CT(22)-CT(16)*ep)*ep-CT(33))/CT(8316); + coeffs_n[7] = (CT(11)-CT(8)*ep)/CT(3960); + coeffs_n[8] = -CT(1)/CT(495); + coeffs_n[9] = (ep*(CT(16)*ep-CT(22))+CT(33))/CT(69300); + coeffs_n[10] = (CT(8)*ep-CT(11))/CT(19800); + coeffs_n[11] = CT(1)/CT(1925); + coeffs_n[12] = (CT(11)-CT(8)*ep)/CT(194040); + coeffs_n[13] = -CT(1)/CT(10780); + coeffs_n[14] = CT(1)/CT(124740); + break; + case 5: + coeffs_n[0] = (ep*(ep*(ep*((CT(832)-CT(640)*ep)*ep-CT(1144))+CT(1716))-CT(3003))+CT(30030))/CT(45045); + coeffs_n[1] = (ep*(ep*((CT(832)-CT(640)*ep)*ep-CT(1144))+CT(1716))-CT(3003))/CT(60060); + coeffs_n[2] = (ep*((CT(208)-CT(160)*ep)*ep-CT(286))+CT(429))/CT(18018); + coeffs_n[3] = ((CT(104)-CT(80)*ep)*ep-CT(143))/CT(10296); + coeffs_n[4] = (CT(13)-CT(10)*ep)/CT(1430); + coeffs_n[5] = -CT(1)/CT(156); + coeffs_n[6] = (ep*(ep*(ep*(CT(640)*ep-CT(832))+CT(1144))-CT(1716))+CT(3003))/CT(540540); + coeffs_n[7] = (ep*(ep*(CT(160)*ep-CT(208))+CT(286))-CT(429))/CT(108108); + coeffs_n[8] = (ep*(CT(80)*ep-CT(104))+CT(143))/CT(51480); + coeffs_n[9] = (CT(10)*ep-CT(13))/CT(6435); + coeffs_n[10] = CT(5)/CT(3276); + coeffs_n[11] = (ep*((CT(208)-CT(160)*ep)*ep-CT(286))+CT(429))/CT(900900); + coeffs_n[12] = ((CT(104)-CT(80)*ep)*ep-CT(143))/CT(257400); + coeffs_n[13] = (CT(13)-CT(10)*ep)/CT(25025); + coeffs_n[14] = -CT(1)/CT(2184); + coeffs_n[15] = (ep*(CT(80)*ep-CT(104))+CT(143))/CT(2522520); + coeffs_n[16] = (CT(10)*ep-CT(13))/CT(140140); + coeffs_n[17] = CT(5)/CT(45864); + coeffs_n[18] = (CT(13)-CT(10)*ep)/CT(1621620); + coeffs_n[19] = -CT(1)/CT(58968); + coeffs_n[20] = CT(1)/CT(792792); + break; + } + } + + /* + Given the set of coefficients coeffs1[] generate the set of + coefficients coeffs2[] + */ + static inline void GenerateCoeffs2(CT eps, + CT coeffs1[], + CT coeffs2[]){ + std::size_t begin(0), end(0); + for(std::size_t i = 0; i <= SeriesOrder; i++){ + end = begin + SeriesOrder + 1 - i; + coeffs2[i] = ((i==0) ? CT(1) : pow(eps,int(i))) + * HornerEvaluate(eps, + coeffs1 + begin, + coeffs1 + end); + begin = end; + } + } + + /* + Compute the spherical excess of a geodesic (or shperical) segment + */ + template < + typename PointOfSegment + > + static inline CT spherical_excess(PointOfSegment const& p1, + PointOfSegment const& p2) + { + CT excess; + + if(LongSegment) + { + CT cbet1 = cos(geometry::get_as_radian<1>(p1)); + CT sbet1 = sin(geometry::get_as_radian<1>(p1)); + CT cbet2 = cos(geometry::get_as_radian<1>(p2)); + CT sbet2 = sin(geometry::get_as_radian<1>(p2)); + CT omg12 = geometry::get_as_radian<0>(p1) + - geometry::get_as_radian<0>(p2); + CT comg12 = cos(omg12); + CT somg12 = sin(omg12); + + CT alp1 = atan2(cbet1 * sbet2 + - sbet1 * cbet2 * comg12, + cbet2 * somg12); + + CT alp2 = atan2(cbet1 * sbet2 * comg12 + - sbet1 * cbet2, + cbet1 * somg12); + + excess = alp2 - alp1; + + } else { + + // Trapezoidal formula + + CT tan_lat1 = + tan(geometry::get_as_radian<1>(p1) / 2.0); + CT tan_lat2 = + tan(geometry::get_as_radian<1>(p2) / 2.0); + + excess = CT(2.0) + * atan(((tan_lat1 + tan_lat2) / (CT(1) + tan_lat1 * tan_lat2)) + * tan((geometry::get_as_radian<0>(p2) + - geometry::get_as_radian<0>(p1)) / 2)); + + } + + return excess; + } + + /* + Compute the ellipsoidal correction of a geodesic (or shperical) segment + */ + template < + typename AzimuthStrategy, + typename PointOfSegment, + typename SpheroidConst + > + static inline CT ellipsoidal_correction(PointOfSegment const& p1, + PointOfSegment const& p2, + SpheroidConst spheroid_const) + { + + + // Azimuth Approximation + + CT alp1, alp2; + + alp1 = AzimuthStrategy::apply(get_as_radian<0>(p1), + get_as_radian<1>(p1), + get_as_radian<0>(p2), + get_as_radian<1>(p2), + spheroid_const.m_spheroid).azimuth; + + alp2 = AzimuthStrategy::apply(get_as_radian<0>(p1), + get_as_radian<1>(p1), + get_as_radian<0>(p2), + get_as_radian<1>(p2), + spheroid_const.m_spheroid).reverse_azimuth; + + // Integral approximation + + CT const ep = spheroid_const.m_ep; + CT const f = geometry::detail::flattening(spheroid_const.m_spheroid); + + //TODO: do it faster + CT cos_bet1 = cos(atan(tan(get_as_radian<1>(p1)) * (1 - f))); + CT cos_bet2 = cos(atan(tan(get_as_radian<1>(p2)) * (1 - f))); + CT sin_alp1 = sin(alp1); + CT cos_alp1 = cos(alp1); + CT cos_alp2 = cos(alp2); + CT sin_alp0 = sin_alp1 * cos_bet1; + CT cos_alp0 = math::sqrt(CT(1) - math::sqr(sin_alp0)); + //cos_alp0 = hypot(cos_alp2, sin(alp2) * sin_bet2); + CT cos_sig1 = cos_alp1 * cos_bet1; + CT cos_sig2 = cos_alp2 * cos_bet2; + + CT coeffs[SeriesOrder + 1];; + const std::size_t coeffs_var_size = ((SeriesOrder + 2) + * (SeriesOrder + 1)) / 2; + CT coeffs_var[coeffs_var_size]; + + if(ExpandEpsN){ // expand by eps and n + + CT k2 = math::sqr(ep * cos_alp0); + CT sqrt_k2_plus_one = math::sqrt(CT(1) + k2); + CT eps = (sqrt_k2_plus_one - 1) / (sqrt_k2_plus_one + 1); + CT n = f / (CT(2) - f); + + // Generate and evaluate the polynomials on n + // to get the series coefficients (that depend on eps) + GenerateCoeffs1(n, coeffs_var); + + // Generate and evaluate the polynomials on eps + // to get the final series coefficients + GenerateCoeffs2(eps, coeffs_var, coeffs); + + }else{ // expand by k2 and ep + + CT k2 = math::sqr(ep * cos_alp0); + CT ep2 = math::sqr(ep); + + // Generate and evaluate the polynomials on ep2 + GenerateCoeffs1b(ep2, coeffs_var); + + // Generate and evaluate the polynomials on k2 + GenerateCoeffs2(k2, coeffs_var, coeffs); + + } + + // Evaluate the trigonometric sum + CT I12 = ClenshawSum(cos_sig2, coeffs, coeffs + SeriesOrder + 1) + - ClenshawSum(cos_sig1, coeffs, coeffs + SeriesOrder + 1); + + // Return the part of the ellipsodal correction that depends on + // point coordinates + return cos_alp0 * sin_alp0 * I12; + + } + + // Keep track whenever a segment crosses the prime meridian + // First normalize to [0,360) + template + static inline int crosses_prime_meridian(PointOfSegment const& p1, + PointOfSegment const& p2, + StateType& state) + { + CT const pi + = geometry::math::pi(); + CT const two_pi + = geometry::math::two_pi(); + + CT p1_lon = get_as_radian<0>(p1) + - ( floor( get_as_radian<0>(p1) / two_pi ) + * two_pi ); + CT p2_lon = get_as_radian<0>(p2) + - ( floor( get_as_radian<0>(p2) / two_pi ) + * two_pi ); + + CT max_lon = std::max(p1_lon, p2_lon); + CT min_lon = std::min(p1_lon, p2_lon); + + if(max_lon > pi && min_lon < pi && max_lon - min_lon > pi) + { + state.m_crosses_prime_meridian++; + } + + return state.m_crosses_prime_meridian; + } + +}; + +}}} // namespace boost::geometry::formula + + +#endif // BOOST_GEOMETRY_FORMULAS_AREA_FORMULAS_HPP diff --git a/include/boost/geometry/formulas/geographic_area.hpp b/include/boost/geometry/formulas/geographic_area.hpp deleted file mode 100644 index 61ddd7eb0..000000000 --- a/include/boost/geometry/formulas/geographic_area.hpp +++ /dev/null @@ -1,404 +0,0 @@ -// Boost.Geometry - -// Copyright (c) 2015-2016 Oracle and/or its affiliates. - -// Contributed and/or modified by Vissarion Fysikopoulos, 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_FORMULAS_GEOGRAPHIC_AREA_HPP -#define BOOST_GEOMETRY_FORMULAS_GEOGRAPHIC_AREA_HPP - -#include -#include -#include - -namespace boost { namespace geometry { namespace formula -{ - -/*! -\brief Formulas for computing spherical and ellipsoidal polygon area. - The current class computes the area of the trapezoid defined by a segment - the two meridians passing by the endpoints and the equator. -\author See -- Charles F.F Karney, Algorithms for geodesics, 2011 -https://arxiv.org/pdf/1109.4448.pdf -*/ - -template < - typename CT, - const std::size_t SeriesOrder = 2, - bool LongSegment = false -> -class geographic_area -{ - -public: - - /* - Evaluate the polynomial in x, of coefficients - CoefficientsOfPolynomial, using Horner's method. - */ - template - static inline CT HornerEvaluate(CT x, - IteratorType begin, - IteratorType end) - { - CT result(0); - IteratorType it = end; - do{ - result = result * x + *--it; - }while(it != begin); - return result; - } - - - /* - Evaluate the series given the set of coefficients A[] - */ - static inline void EvaluateSeries(CT eps, - CT A[], - CT c_4[]){ - std::size_t begin(0), end(0); - for(std::size_t i = 0; i <= SeriesOrder; i++){ - end = begin + SeriesOrder + 1 - i; - //replace pow() - c_4[i] = pow(eps,i) * - HornerEvaluate(eps, - A + begin, - A + end); - begin = end; - } - //E.g. for SeriesOrder = 2 - //c_4[0] = HornerEvaluate(eps, A, A + 3); - //c_4[1] = eps * HornerEvaluate(eps, A + 3, A + 5); - //c_4[2] = eps * eps * HornerEvaluate(eps, A + 5, A + 6); - // - //CT c_40 = _C4x[0] + eps * (_C4x[1] + eps * _C4x[2]); - //CT c_41 = eps * (_C4x[3] + eps * (_C4x[4])); - //CT c_42 = eps * (eps * _C4x[5]); - } - - /* - Clenshaw algorithm for summing trigonometric series - */ - static inline CT ClenshawSum(CT cosx, - const CT c[]) - { - int n = 2 * SeriesOrder + 1; - CT b_k, b_k1(0), b_k2(0); - do{ - CT c_k = n % 2 ? c[n / 2] : CT(0); - b_k = c_k + CT(2) * cosx * b_k1 - b_k2; - b_k2 = b_k1; - b_k1 = b_k; - }while(--n); - - return c[0] + b_k1 * cosx - b_k2; - } - - /* - Compute the spherical excess of a geodesic (or shperical) segment - */ - template < - typename PointOfSegment - > - static inline CT spherical_excess(PointOfSegment const& p1, - PointOfSegment const& p2) - { - //Spherical excess computation - - CT excess; - - if(LongSegment) - { - CT cbet1 = cos(geometry::get_as_radian<1>(p1)); - CT sbet1 = sin(geometry::get_as_radian<1>(p1)); - CT cbet2 = cos(geometry::get_as_radian<1>(p2)); - CT sbet2 = sin(geometry::get_as_radian<1>(p2)); - CT omg12 = geometry::get_as_radian<0>(p1) - - geometry::get_as_radian<0>(p2); - CT comg12 = cos(omg12); - CT somg12 = sin(omg12); - - CT alp1 = atan2(cbet1 * sbet2 - - sbet1 * cbet2 * comg12, - cbet2 * somg12); - - CT alp2 = atan2(cbet1 * sbet2 * comg12 - - sbet1 * cbet2, - cbet1 * somg12); - - excess = alp2 - alp1; - - } else { // Trapezoidal formula - CT tan_lat1 = - tan(geometry::get_as_radian<1>(p1) / 2.0); - CT tan_lat2 = - tan(geometry::get_as_radian<1>(p2) / 2.0); - - excess = CT(2.0) - * atan(((tan_lat1 + tan_lat2) / (CT(1) + tan_lat1 * tan_lat2)) - * tan((geometry::get_as_radian<0>(p2) - - geometry::get_as_radian<0>(p1)) / 2)); - } - - return excess; - } - - /* - Compute the ellipsoidal correction of a geodesic (or shperical) segment - */ - template < - typename AzimuthStrategy, - typename PointOfSegment, - typename SpheroidConst - > - static inline CT ellipsoidal_correction(PointOfSegment const& p1, - PointOfSegment const& p2, - SpheroidConst spheroid_const) - { - - - // 1. Azimuth Approximation - - CT alp1, alp2; - - - alp1 = AzimuthStrategy::apply(get_as_radian<0>(p1), - get_as_radian<1>(p1), - get_as_radian<0>(p2), - get_as_radian<1>(p2), - spheroid_const.spheroid).azimuth; - - alp2 = AzimuthStrategy::apply(get_as_radian<0>(p1), - get_as_radian<1>(p1), - get_as_radian<0>(p2), - get_as_radian<1>(p2), - spheroid_const.spheroid).reverse_azimuth; - // 2. Integral approximation - - // Epsoidal constants - //CT const ep2 = spheroid_const.ep2; - CT const ep = spheroid_const.ep; - CT const f = detail::flattening(spheroid_const.spheroid); - - //CT cos_a1 = geometry::math:cos(a1); - //CT sin_a1 = geometry::math:sin(a1); - //CT sin_ph1 = geometry::math:sin(get_as_radian<1>(p1)); - - //CT cos_a0 = std::hypot(cos_a1, sin_a1 * sin_ph1); - //CT sin_a0 = math::sqrt(1 - cos_a0 * cos_a0); - - CT cos_bet1 = cos(get_as_radian<1>(p1)); - CT cos_bet2 = cos(get_as_radian<1>(p2)); - //CT sin_bet1 = sin(get_as_radian<1>(p1)); - //CT sin_bet2 = sin(get_as_radian<1>(p2)); - - CT sin_alp1 = sin(alp1); - CT cos_alp1 = cos(alp1); - //CT sin_alp2 = sin(alp2); - CT cos_alp2 = cos(alp2); - - CT sin_alp0 = sin_alp1 * cos_bet1; - //TODO: do it more accurate! - CT cos_alp0 = math::sqrt(CT(1) - math::sqr(sin_alp0)); - - //CT sin_sig1 = sin_bet1; - CT cos_sig1 = cos_alp1 * cos_bet1; - //CT sin_sig2 = sin_bet2; - CT cos_sig2 = cos_alp2 * cos_bet2; - - CT k2 = math::sqr(ep * cos_alp0); - - CT sqrt_k2_plus_one = math::sqrt(CT(1) + k2); - CT eps = (sqrt_k2_plus_one - 1) / (sqrt_k2_plus_one + 1); - CT n = f / (CT(2) - f); - - const std::size_t C4_size = ((SeriesOrder + 2) * (SeriesOrder + 1)) / 2; - CT _C4x[C4_size]; - - switch(SeriesOrder + 1){ - case 0: - break; - case 1: - _C4x[0] = 2.0/3.0; - break; - case 2: - _C4x[0] = (10.0-4.0*n)/15.0; - _C4x[1] = -1.0/5.0; - _C4x[2] = 1.0/45.0; - //Alternatively... - //{CT A[][C4_size] = { {10, -4, 15}, - // {-1, 5}, - // {1, 45} }; - //_C4x[0] = HornerEvaluate(n, A[0], A[0] + 2) / A[0][2]; - //_C4x[1] = HornerEvaluate(n, A[1], A[1] + 1) / A[1][1]; - //_C4x[2] = HornerEvaluate(n, A[2], A[2] + 1) / A[2][1];} - break; - case 3: - _C4x[0] = (n*(8.0*n-28.0)+70.0)/105.0; - _C4x[1] = (16.0*n-7.0)/35.0; - _C4x[2] = -2.0/105.0; - _C4x[3] = (7.0-16.0*n)/315.0; - _C4x[4] = -2.0/105.0; - _C4x[5] = 4.0/525.0; - break; - case 4: - _C4x[0] = (n*(n*(4.*n+24.)-84.)+210.)/315.; - _C4x[1] = ((48.-32.*n)*n-21.)/105.; - _C4x[2] = (-32.*n-6.)/315; - _C4x[3] = 11./315; - _C4x[4] = (n*(32.*n-48.)+21.)/945; - _C4x[5] = (64.*n-18.)/945; - _C4x[6] = -1./105; - _C4x[7] = (12.-32*n)/1575; - _C4x[8] = -8./1575; - _C4x[9] = 8./2205; - break; - case 5: - _C4x[0] = (n*(n*(n*(16.*n+44)+264)-924)+2310)/3465; - _C4x[1] = (n*(n*(48.*n-352)+528)-231)/1155; - _C4x[2] = (n*(1088.*n-352)-66)/3465; - _C4x[3] = (121.-368*n)/3465; - _C4x[4] = 4./1155; - _C4x[5] = (n*((352.-48*n)*n-528)+231)/10395; - _C4x[6] = ((704.-896*n)*n-198)/10395; - _C4x[7] = (80*n-99)/10395; - _C4x[8] = 4./1155; - _C4x[9] = (n*(320.*n-352)+132)/17325; - _C4x[10] = (384.*n-88)/17325; - _C4x[11] = -8./1925; - _C4x[12] = (88.-256*n)/24255; - _C4x[13] = -16./8085; - _C4x[14] = 64./31185; - break; - case 6: - _C4x[0] = (n*(n*(n*(n*(100.*n+208)+572)+3432)-12012)+30030)/45045; - _C4x[1] = (n*(n*(n*(64.*n+624)-4576)+6864)-3003)/15015; - _C4x[2] = (n*((14144.-10656*n)*n-4576)-858)/45045; - _C4x[3] = ((-224.*n-4784)*n+1573)/45045; - _C4x[4] = (1088.*n+156)/45045; - _C4x[5] = 97./15015; - _C4x[6] = (n*(n*((-64.*n-624)*n+4576)-6864)+3003)/135135; - _C4x[7] = (n*(n*(5952*n-11648)+9152)-2574)/135135; - _C4x[8] = (n*(5792.*n+1040)-1287)/135135; - _C4x[9] = (468.-2944*n)/135135; - _C4x[10] = 1./9009; - _C4x[11] = (n*((4160.-1440*n)*n-4576)+1716)/225225; - _C4x[12] = ((4992.-8448*n)*n-1144)/225225; - _C4x[13] = (1856.*n-936)/225225; - _C4x[14] = 8./10725; - _C4x[15] = (n*(3584.*n-3328)+1144)/315315; - _C4x[16] = (1024.*n-208)/105105; - _C4x[17] = -136./63063; - _C4x[18] = (832.-2560*n)/405405; - _C4x[19] = -128./135135; - _C4x[20] = 128./99099; - break; - } - - CT c_4[SeriesOrder + 1]; - EvaluateSeries(eps,_C4x,c_4); - - CT I12 = ClenshawSum(cos_sig2, c_4) - - ClenshawSum(cos_sig1, c_4); - - //CT cos3_sig1 = CT(4.0) * cos_sig1 * cos_sig1 * cos_sig1 - CT(3.0) * cos_sig1; - //CT cos3_sig2 = CT(4.0) * cos_sig2 * cos_sig2 * cos_sig2 - CT(3.0) * cos_sig2; - - /* - if(SeriesOrder == 1) - { - //CT c_40 = (CT(2) / CT(3) - CT(4) / CT(15) * n) - // - CT(1) / CT(5) * eps; - //CT c_41 = CT(1) / CT(45) * eps; - - //CT c_40 = _C4x[0] + _C4x[1] * eps; - //CT c_41 = _C4x[2] * eps; - - //I12 = c_4[0] * (cos_sig2 - cos_sig1) - // + c_4[1] * (cos3_sig2 - cos3_sig1); - } - if(SeriesOrder == 2) - { - // CT n2 = math::sqr(n); - // CT eps2 = math::sqr(eps); - - //CT c_40 = (CT(2) / CT(3) - CT(4) / CT(15) * n + CT(8) / CT(105) * n2) - // - (CT(1) / CT(5) - CT(16) / CT(35) * n) * eps - // - (CT(2) / CT(105)) * eps2; - - //CT c_41 = (CT(1) / CT(45) - CT(16) / CT(315) * n) * eps - // - (CT(2) / CT(105)) * eps2; - - //CT c_42 = (CT(4) / CT(525)) * eps2; - - //c_4[0] = HornerEvaluate(eps, _C4x, _C4x + 3); - //c_4[1] = eps * HornerEvaluate(eps, _C4x + 3, _C4x + 5); - //c_4[2] = eps * eps * HornerEvaluate(eps, _C4x + 5, _C4x + 6); - //CT c_40 = _C4x[0] + eps * (_C4x[1] + eps * _C4x[2]); - //CT c_41 = eps * (_C4x[3] + eps * (_C4x[4])); - //CT c_42 = eps * (eps * _C4x[5]); - - - - CT cos5_sig1 = CT(16) - * cos_sig1 * cos_sig1 * cos_sig1 * cos_sig1 * cos_sig1 - - CT(20) - * cos_sig1 * cos_sig1 * cos_sig1 - + CT(5) * cos_sig1; - CT cos5_sig2 = CT(16) - * cos_sig2 * cos_sig2 * cos_sig2 * cos_sig2 * cos_sig2 - - CT(20) - * cos_sig2 * cos_sig2 * cos_sig2 - + CT(5) * cos_sig2; - - I12 = c_4[0] * (cos_sig2 - cos_sig1) - + c_4[1] * (cos3_sig2 - cos3_sig1) - + c_4[2] * (cos5_sig2 - cos5_sig1); - -*/ - - return cos_alp0 * sin_alp0 * I12; - - } - - // Keep track whenever a segment crosses the prime meridian - // First normalize to [0,360) - template - static inline int crosses_prime_meridian(PointOfSegment const& p1, - PointOfSegment const& p2, - StateType& state) - { - CT const pi - = geometry::math::pi(); - CT const two_pi - = geometry::math::two_pi(); - - CT p1_lon = get_as_radian<0>(p1) - - ( floor( get_as_radian<0>(p1) / two_pi ) - * two_pi ); - CT p2_lon = get_as_radian<0>(p2) - - ( floor( get_as_radian<0>(p2) / two_pi ) - * two_pi ); - - CT max_lon = std::max(p1_lon, p2_lon); - CT min_lon = std::min(p1_lon, p2_lon); - - if(max_lon > pi && min_lon < pi && max_lon - min_lon > pi) - { - state.crosses_prime_meridian++; - } - - return state.crosses_prime_meridian; - } - -}; - -}}} // namespace boost::geometry::formula - - -#endif // BOOST_GEOMETRY_FORMULAS_GEOGRAPHIC_AREA_HPP diff --git a/include/boost/geometry/strategies/geographic/area.hpp b/include/boost/geometry/strategies/geographic/area_geographic.hpp similarity index 57% rename from include/boost/geometry/strategies/geographic/area.hpp rename to include/boost/geometry/strategies/geographic/area_geographic.hpp index ede2860cf..ddc715124 100644 --- a/include/boost/geometry/strategies/geographic/area.hpp +++ b/include/boost/geometry/strategies/geographic/area_geographic.hpp @@ -7,13 +7,12 @@ // 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_GEOGRAPHIC_AREA_HPP -#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_AREA_HPP +#ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_AREA_GEOGRAPHIC_HPP +#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_AREA_GEOGRAPHIC_HPP -#include -#include -#include -#include +#include +#include +//#include namespace boost { namespace geometry { @@ -22,7 +21,8 @@ namespace strategy { namespace area { /*! -\brief Area calculation by trapezoidal rule plus ellipsoidal correction +\brief Geographic area calculation by trapezoidal rule plus integral +approximation that gives the ellipsoidal correction } @@ -33,10 +33,11 @@ template typename PointOfSegment, typename Strategy = void, const std::size_t SeriesOrder = 2, + bool ExpandEpsN = true, typename Spheroid = void, typename CalculationType = void > -class geographic_area +class area_geographic { //Select default types for Strategy, Spheroid and CalculationType @@ -76,58 +77,55 @@ class geographic_area protected : struct spheroid_constants { - SpheroidType spheroid; - CT const a2; // squared equatorial radius - CT const e2; // squared eccentricity - CT const ep2; // squared second eccentricity - CT const ep; // second eccentricity - CT const c2; // authalic radius + SpheroidType m_spheroid; + CT const m_a2; // squared equatorial radius + CT const m_e2; // squared eccentricity + CT const m_ep2; // squared second eccentricity + CT const m_ep; // second eccentricity + CT const m_c2; // authalic radius inline spheroid_constants(SpheroidType spheroid) - : spheroid(spheroid) - , a2(math::sqr(get_radius<0>(spheroid))) - , e2(detail::flattening(spheroid) + : m_spheroid(spheroid) + , m_a2(math::sqr(get_radius<0>(spheroid))) + , m_e2(detail::flattening(spheroid) * (CT(2.0) - CT(detail::flattening(spheroid)))) - , ep2(e2 / (CT(1.0) - e2)) - , ep(math::sqrt(ep2)) - , c2((a2 / CT(2.0)) + - ((math::sqr(get_radius<2>(spheroid)) -// * 1) - * atanh(math::sqrt(e2))) -// * std::atanh(math::sqrt(e2))) - / (CT(2.0) * math::sqrt(e2)))) + , m_ep2(m_e2 / (CT(1.0) - m_e2)) + , m_ep(math::sqrt(m_ep2)) + , m_c2((m_a2 / CT(2.0)) + + ((math::sqr(get_radius<2>(spheroid)) * atanh(math::sqrt(m_e2))) + / (CT(2.0) * math::sqrt(m_e2)))) {} }; struct area_sums { - CT excess_sum; - CT correction_sum; + CT m_excess_sum; + CT m_correction_sum; // Keep track if encircles some pole - std::size_t crosses_prime_meridian; + std::size_t m_crosses_prime_meridian; inline area_sums() - : excess_sum(0) - , correction_sum(0) - , crosses_prime_meridian(0) + : m_excess_sum(0) + , m_correction_sum(0) + , m_crosses_prime_meridian(0) {} inline CT area(spheroid_constants spheroid_const) const { CT result; - CT sum = spheroid_const.c2 * excess_sum - + spheroid_const.e2 * spheroid_const.a2 * correction_sum; + CT sum = spheroid_const.m_c2 * m_excess_sum + + spheroid_const.m_e2 * spheroid_const.m_a2 * m_correction_sum; // If encircles some pole - if(crosses_prime_meridian % 2 == 1) + if(m_crosses_prime_meridian % 2 == 1) { std::size_t times_crosses_prime_meridian - = 1 + (crosses_prime_meridian / 2); + = 1 + (m_crosses_prime_meridian / 2); result = CT(2.0) * geometry::math::pi() - * spheroid_const.c2 + * spheroid_const.m_c2 * CT(times_crosses_prime_meridian) - geometry::math::abs(sum); @@ -149,7 +147,7 @@ public : typedef PointOfSegment segment_point_type; typedef area_sums state_type; - inline geographic_area(SpheroidType spheroid = SpheroidType()) + inline area_geographic(SpheroidType spheroid = SpheroidType()) : spheroid_const(spheroid) {} @@ -162,24 +160,18 @@ public : { //Compute the trapezoidal area - state.excess_sum += geometry::formula::geographic_area - - ::template spherical_excess(p1, p2); + state.m_excess_sum += geometry::formula::area_formulas + ::spherical_excess(p1, p2); - state.correction_sum += geometry::formula::geographic_area - - ::template ellipsoidal_correction - - (p1, p2, spheroid_const); - - //std::cout << "current excess=" << state.excess_sum - // << " correction=" << state.correction_sum - // << std::endl; + state.m_correction_sum += geometry::formula::area_formulas + + ::template ellipsoidal_correction + + (p1, p2, spheroid_const); // Keep track whenever a segment crosses the prime meridian - geometry::formula::geographic_area - - ::crosses_prime_meridian(p1, p2, state); + geometry::formula::area_formulas + ::crosses_prime_meridian(p1, p2, state); } } @@ -202,7 +194,7 @@ namespace services template struct default_strategy { - typedef strategy::area::geographic_area type; + typedef strategy::area::area_geographic type; }; #endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS @@ -216,4 +208,4 @@ struct default_strategy }} // namespace boost::geometry -#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_AREA_HPP +#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_AREA_GEOGRAPHIC_HPP diff --git a/include/boost/geometry/strategies/spherical/area_huiller.hpp b/include/boost/geometry/strategies/spherical/area_huiller.hpp index 5b10eedea..139bed489 100644 --- a/include/boost/geometry/strategies/spherical/area_huiller.hpp +++ b/include/boost/geometry/strategies/spherical/area_huiller.hpp @@ -116,8 +116,6 @@ protected : { calculation_type result; - std::cout << "(sum=" << sum << ")"; - // Encircles pole if((crosses_prime_meridian % 2 == 1 && south) || south_vertex) { @@ -219,7 +217,7 @@ public : { excess = -excess; } - +/* // Keep track whenever a segment crosses the prime meridian // First normalize to [0,360) //TODO: compress with trapezoidal strategy @@ -257,18 +255,18 @@ public : state.south = false; } } - +*/ state.sum += excess; - std::cout << "(width=" << max_lon-min_lon << ")"; + //std::cout << "(width=" << max_lon-min_lon << ")"; } } inline return_type result(excess_sum const& state) const { - std::cout << "(pole=" << state.crosses_prime_meridian << ")"; - std::cout<<"(W="< -#include -#include +#include namespace boost { namespace geometry { @@ -21,10 +18,8 @@ namespace boost { namespace geometry namespace strategy { namespace area { - - /*! -\brief Area calculation by trapezoidal rule +\brief Spherical area calculation by trapezoidal rule } @@ -34,7 +29,7 @@ template typename PointOfSegment, typename CalculationType = void > -class trapezoidal +class area_spherical { typedef typename boost::mpl::if_c < @@ -50,39 +45,37 @@ typedef typename boost::mpl::if_c protected : struct excess_sum { - CT sum; + CT m_sum; // Keep track if encircles some pole - size_t crosses_prime_meridian; + size_t m_crosses_prime_meridian; inline excess_sum() - : sum(0) - , crosses_prime_meridian(0) + : m_sum(0) + , m_crosses_prime_meridian(0) {} inline CT area(CT radius) const { CT result; - std::cout << "(sum=" << sum << ")"; - // Encircles pole - if(crosses_prime_meridian % 2 == 1) + if(m_crosses_prime_meridian % 2 == 1) { size_t times_crosses_prime_meridian - = 1 + (crosses_prime_meridian / 2); + = 1 + (m_crosses_prime_meridian / 2); - result = 2.0 + result = CT(2) * geometry::math::pi() * times_crosses_prime_meridian - - std::abs(sum); + - geometry::math::abs(m_sum); - if(geometry::math::sign(sum) == 1) + if(geometry::math::sign(m_sum) == 1) { result = - result; } } else { - result = sum; + result = m_sum; } result *= radius * radius; @@ -96,7 +89,7 @@ public : typedef PointOfSegment segment_point_type; typedef excess_sum state_type; - inline trapezoidal(CT radius = 1.0) + inline area_spherical(CT radius = 1.0) : m_radius(radius) {} @@ -107,21 +100,19 @@ public : if (! geometry::math::equals(get<0>(p1), get<0>(p2))) { - state.sum += geometry::formula::geographic_area - - ::spherical_excess(p1, p2); + state.m_sum += geometry::formula::area_formulas + ::spherical_excess(p1, p2); // Keep track whenever a segment crosses the prime meridian - geometry::formula::geographic_area - - ::crosses_prime_meridian(p1, p2, state); + geometry::formula::area_formulas + ::crosses_prime_meridian(p1, p2, state); } } inline return_type result(excess_sum const& state) const { - std::cout << "(tpole=" << state.crosses_prime_meridian << ")"; + //std::cout << "(tpole=" << state.crosses_prime_meridian << ")"; return state.area(m_radius); } @@ -139,14 +130,14 @@ namespace services template struct default_strategy { - typedef strategy::area::trapezoidal type; + typedef strategy::area::area_spherical type; }; // Note: spherical polar coordinate system requires "get_as_radian_equatorial" /***template struct default_strategy { - typedef strategy::area::trapezoidal type; + typedef strategy::area::area_spherical type; };***/ } // namespace services @@ -161,4 +152,4 @@ struct default_strategy }} // namespace boost::geometry -#endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_AREA_TRAPEZOIDAL_HPP +#endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_AREA_SPHERICAL_HPP diff --git a/include/boost/geometry/strategies/strategies.hpp b/include/boost/geometry/strategies/strategies.hpp index aaef441d8..52d356b84 100644 --- a/include/boost/geometry/strategies/strategies.hpp +++ b/include/boost/geometry/strategies/strategies.hpp @@ -7,6 +7,7 @@ // This file was modified by Oracle on 2014-2016. // Modifications copyright (c) 2014-2016 Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library @@ -57,8 +58,8 @@ #include #include -#include -#include +//#include +#include #include #include #include @@ -66,7 +67,7 @@ #include #include -#include +#include #include #include #include diff --git a/test/algorithms/area.cpp b/test/algorithms/area.cpp index 773f09941..4e5f28259 100644 --- a/test/algorithms/area.cpp +++ b/test/algorithms/area.cpp @@ -98,7 +98,7 @@ void test_spherical(bool polar = false) BOOST_CHECK_CLOSE(area, expected, 0.0001); // With strategy, radius 2 -> 4 pi r^2 - bg::strategy::area::huiller + bg::strategy::area::area_spherical < typename bg::point_type::type > strategy(2.0); @@ -109,7 +109,7 @@ void test_spherical(bool polar = false) // Wrangel Island (dateline crossing) // With (spherical) Earth strategy - bg::strategy::area::huiller + bg::strategy::area::area_spherical < typename bg::point_type::type > spherical_earth(6373); @@ -226,7 +226,6 @@ void test_spherical(bool polar = false) BOOST_CHECK_CLOSE(area1, 0.0305, 0.001); } // around poles -#ifdef BOOST_GEOMETRY_ENABLE_FAILING_TESTS { bg::read_wkt("POLYGON((0 80,-90 80,-180 80,90 80,0 80))", geometry); ct area1 = bg::area(geometry); @@ -240,7 +239,6 @@ void test_spherical(bool polar = false) BOOST_CHECK_CLOSE(area2, area3, 0.001); BOOST_CHECK_CLOSE(area3, area4, 0.001); } -#endif { bg::model::ring aurha; // a'dam-utr-rott.-den haag-a'dam @@ -254,11 +252,11 @@ void test_spherical(bool polar = false) } bg::correct(aurha); } - bg::strategy::area::huiller + bg::strategy::area::area_spherical < typename bg::point_type::type - > huiller(6372.795); - area = bg::area(aurha, huiller); + > area_spherical(6372.795); + area = bg::area(aurha, area_spherical); BOOST_CHECK_CLOSE(area, 1476.645675, 0.0001); // SQL Server gives: 1481.55595960659 From 62facdfe8628281dc4813a8a6fb1f74c13a0f356 Mon Sep 17 00:00:00 2001 From: Vissarion Fysikopoulos Date: Sat, 13 Aug 2016 15:31:28 +0300 Subject: [PATCH 06/89] [area] fix accuracy (normalize sin cos) --- .../boost/geometry/formulas/area_formulas.hpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/include/boost/geometry/formulas/area_formulas.hpp b/include/boost/geometry/formulas/area_formulas.hpp index 8f6558fb4..66aec0404 100644 --- a/include/boost/geometry/formulas/area_formulas.hpp +++ b/include/boost/geometry/formulas/area_formulas.hpp @@ -372,6 +372,14 @@ public: return excess; } + template + static inline void normalize(T& x, T& y) + { + T h = hypot(x, y); + x /= h; + y /= h; + } + /* Compute the ellipsoidal correction of a geodesic (or shperical) segment */ @@ -410,16 +418,23 @@ public: //TODO: do it faster CT cos_bet1 = cos(atan(tan(get_as_radian<1>(p1)) * (1 - f))); CT cos_bet2 = cos(atan(tan(get_as_radian<1>(p2)) * (1 - f))); + CT sin_bet1 = sin(atan(tan(get_as_radian<1>(p1)) * (1 - f))); + CT sin_bet2 = sin(atan(tan(get_as_radian<1>(p2)) * (1 - f))); CT sin_alp1 = sin(alp1); CT cos_alp1 = cos(alp1); CT cos_alp2 = cos(alp2); CT sin_alp0 = sin_alp1 * cos_bet1; CT cos_alp0 = math::sqrt(CT(1) - math::sqr(sin_alp0)); - //cos_alp0 = hypot(cos_alp2, sin(alp2) * sin_bet2); + //CT cos_alp0 = hypot(cos_alp2, sin(alp2) * sin_bet2); CT cos_sig1 = cos_alp1 * cos_bet1; CT cos_sig2 = cos_alp2 * cos_bet2; + CT sin_sig1 = sin_bet1; + CT sin_sig2 = sin_bet2; - CT coeffs[SeriesOrder + 1];; + normalize(sin_sig1, cos_sig1); + normalize(sin_sig2, cos_sig2); + + CT coeffs[SeriesOrder + 1]; const std::size_t coeffs_var_size = ((SeriesOrder + 2) * (SeriesOrder + 1)) / 2; CT coeffs_var[coeffs_var_size]; From 1a483d28c288b1b397d9a92f37491029157ab8d2 Mon Sep 17 00:00:00 2001 From: Vissarion Fysikopoulos Date: Mon, 15 Aug 2016 12:44:31 +0300 Subject: [PATCH 07/89] [area] [formulas] minor changes to improve performance --- .../boost/geometry/formulas/area_formulas.hpp | 91 ++++++++++--------- 1 file changed, 47 insertions(+), 44 deletions(-) diff --git a/include/boost/geometry/formulas/area_formulas.hpp b/include/boost/geometry/formulas/area_formulas.hpp index 66aec0404..6b742f693 100644 --- a/include/boost/geometry/formulas/area_formulas.hpp +++ b/include/boost/geometry/formulas/area_formulas.hpp @@ -36,14 +36,15 @@ class area_formulas public: - //TODO: move Horner and Clenshaw to a more general space + //TODO: move the following to a more general space to be used by other + // classes as well /* Evaluate the polynomial in x using Horner's method. */ template - static inline NT HornerEvaluate(NT x, - IteratorType begin, - IteratorType end) + static inline NT horner_evaluate(NT x, + IteratorType begin, + IteratorType end) { NT result(0); IteratorType it = end; @@ -58,9 +59,9 @@ public: https://en.wikipedia.org/wiki/Clenshaw_algorithm */ template - static inline NT ClenshawSum(NT cosx, - IteratorType begin, - IteratorType end) + static inline NT clenshaw_sum(NT cosx, + IteratorType begin, + IteratorType end) { IteratorType it = end; bool odd(true); @@ -76,8 +77,16 @@ public: return *begin + b_k1 * cosx - b_k2; } + template + static inline void normalize(T& x, T& y) + { + T h = hypot(x, y); + x /= h; + y /= h; + } + /* - Evaluate the series expansion of the following integral + Generate and evaluate the series expansion of the following integral I4 = -integrate( (t(ep2) - t(k2*sin(sigma1)^2)) / (ep2 - k2*sin(sigma1)^2) * sin(sigma1)/2, sigma1, pi/2, sigma ) @@ -93,7 +102,7 @@ public: sum(C4[l] * cos((2*l+1)*sigma), l, 0, maxpow-1) ) The above expansion is performed in Computer Algebra System Maxima. - The C++ code (that yields the function GenerateCoeffs1 below) is generated + The C++ code (that yields the function evaluate_coeffs_n below) is generated by the following Maxima script and is based on script: http://geographiclib.sourceforge.net/html/geod.mac @@ -150,7 +159,7 @@ public: s/case\sCT(/case /g; s/):/:/g' */ - static inline void GenerateCoeffs1(CT n, CT coeffs_n[]) + static inline void evaluate_coeffs_n(CT n, CT coeffs_n[]) { switch (SeriesOrder) { @@ -229,7 +238,7 @@ public: /* Expand in k2 and ep2. */ - static inline void GenerateCoeffs1b(CT ep, CT coeffs_n[]) + static inline void evaluate_coeffs_ep(CT ep, CT coeffs_n[]) { switch (SeriesOrder) { case 0: @@ -304,19 +313,17 @@ public: } /* - Given the set of coefficients coeffs1[] generate the set of - coefficients coeffs2[] + Given the set of coefficients coeffs1[] evaluate on var2 and return + the set of coefficients coeffs2[] */ - static inline void GenerateCoeffs2(CT eps, - CT coeffs1[], - CT coeffs2[]){ + static inline void evaluate_coeffs_var2(CT var2, + CT coeffs1[], + CT coeffs2[]){ std::size_t begin(0), end(0); for(std::size_t i = 0; i <= SeriesOrder; i++){ end = begin + SeriesOrder + 1 - i; - coeffs2[i] = ((i==0) ? CT(1) : pow(eps,int(i))) - * HornerEvaluate(eps, - coeffs1 + begin, - coeffs1 + end); + coeffs2[i] = ((i==0) ? CT(1) : pow(var2,int(i))) + * horner_evaluate(var2, coeffs1 + begin, coeffs1 + end); begin = end; } } @@ -372,14 +379,6 @@ public: return excess; } - template - static inline void normalize(T& x, T& y) - { - T h = hypot(x, y); - x /= h; - y /= h; - } - /* Compute the ellipsoidal correction of a geodesic (or shperical) segment */ @@ -414,12 +413,16 @@ public: CT const ep = spheroid_const.m_ep; CT const f = geometry::detail::flattening(spheroid_const.m_spheroid); + CT const one_minus_f = CT(1) - f; + std::size_t const series_order_plus_one = SeriesOrder + 1; + std::size_t const series_order_plus_two = SeriesOrder + 2; - //TODO: do it faster - CT cos_bet1 = cos(atan(tan(get_as_radian<1>(p1)) * (1 - f))); - CT cos_bet2 = cos(atan(tan(get_as_radian<1>(p2)) * (1 - f))); - CT sin_bet1 = sin(atan(tan(get_as_radian<1>(p1)) * (1 - f))); - CT sin_bet2 = sin(atan(tan(get_as_radian<1>(p2)) * (1 - f))); + CT tan_bet1 = tan(get_as_radian<1>(p1)) * one_minus_f; + CT tan_bet2 = tan(get_as_radian<1>(p2)) * one_minus_f; + CT cos_bet1 = cos(atan(tan_bet1)); + CT cos_bet2 = cos(atan(tan_bet2)); + CT sin_bet1 = tan_bet1 * cos_bet1; + CT sin_bet2 = tan_bet2 * cos_bet2; CT sin_alp1 = sin(alp1); CT cos_alp1 = cos(alp1); CT cos_alp2 = cos(alp2); @@ -435,24 +438,24 @@ public: normalize(sin_sig2, cos_sig2); CT coeffs[SeriesOrder + 1]; - const std::size_t coeffs_var_size = ((SeriesOrder + 2) - * (SeriesOrder + 1)) / 2; + const std::size_t coeffs_var_size = (series_order_plus_two + * series_order_plus_one) / 2; CT coeffs_var[coeffs_var_size]; if(ExpandEpsN){ // expand by eps and n CT k2 = math::sqr(ep * cos_alp0); CT sqrt_k2_plus_one = math::sqrt(CT(1) + k2); - CT eps = (sqrt_k2_plus_one - 1) / (sqrt_k2_plus_one + 1); + CT eps = (sqrt_k2_plus_one - CT(1)) / (sqrt_k2_plus_one + CT(1)); CT n = f / (CT(2) - f); // Generate and evaluate the polynomials on n // to get the series coefficients (that depend on eps) - GenerateCoeffs1(n, coeffs_var); + evaluate_coeffs_n(n, coeffs_var); - // Generate and evaluate the polynomials on eps + // Generate and evaluate the polynomials on eps (i.e. var2 = eps) // to get the final series coefficients - GenerateCoeffs2(eps, coeffs_var, coeffs); + evaluate_coeffs_var2(eps, coeffs_var, coeffs); }else{ // expand by k2 and ep @@ -460,16 +463,16 @@ public: CT ep2 = math::sqr(ep); // Generate and evaluate the polynomials on ep2 - GenerateCoeffs1b(ep2, coeffs_var); + evaluate_coeffs_ep(ep2, coeffs_var); - // Generate and evaluate the polynomials on k2 - GenerateCoeffs2(k2, coeffs_var, coeffs); + // Generate and evaluate the polynomials on k2 (i.e. var2 = k2) + evaluate_coeffs_var2(k2, coeffs_var, coeffs); } // Evaluate the trigonometric sum - CT I12 = ClenshawSum(cos_sig2, coeffs, coeffs + SeriesOrder + 1) - - ClenshawSum(cos_sig1, coeffs, coeffs + SeriesOrder + 1); + CT I12 = clenshaw_sum(cos_sig2, coeffs, coeffs + series_order_plus_one) + - clenshaw_sum(cos_sig1, coeffs, coeffs + series_order_plus_one); // Return the part of the ellipsodal correction that depends on // point coordinates From 982c58c07373a610507b897e92dc8b216f86e4d8 Mon Sep 17 00:00:00 2001 From: Vissarion Fysikopoulos Date: Mon, 15 Aug 2016 18:48:40 +0300 Subject: [PATCH 08/89] [area] [test] tests for spherical and geographic area --- .../extensions/contrib/ttmath_stub.hpp | 7 + .../strategies/spherical/area_spherical.hpp | 4 +- test/algorithms/Jamfile.v2 | 3 +- test/algorithms/area.cpp | 369 ----------- test/algorithms/area/Jamfile.v2 | 16 + test/algorithms/area/area.cpp | 574 ++++++++++++++++++ test/algorithms/area/area_multi.cpp | 52 ++ test/algorithms/{ => area}/test_area.hpp | 0 test/algorithms/area_multi.cpp | 36 -- 9 files changed, 652 insertions(+), 409 deletions(-) delete mode 100644 test/algorithms/area.cpp create mode 100644 test/algorithms/area/Jamfile.v2 create mode 100644 test/algorithms/area/area.cpp create mode 100644 test/algorithms/area/area_multi.cpp rename test/algorithms/{ => area}/test_area.hpp (100%) delete mode 100644 test/algorithms/area_multi.cpp diff --git a/include/boost/geometry/extensions/contrib/ttmath_stub.hpp b/include/boost/geometry/extensions/contrib/ttmath_stub.hpp index 0469fd2a7..353803bf4 100644 --- a/include/boost/geometry/extensions/contrib/ttmath_stub.hpp +++ b/include/boost/geometry/extensions/contrib/ttmath_stub.hpp @@ -35,6 +35,13 @@ namespace ttmath return Sqrt(v); } + template + inline Big hypot(Big const& v, + Big const& u) + { + return Sqrt(v * v + u * u); + } + template inline Big pow(Big const& v, int n) diff --git a/include/boost/geometry/strategies/spherical/area_spherical.hpp b/include/boost/geometry/strategies/spherical/area_spherical.hpp index fb881d8ea..218c78f7e 100644 --- a/include/boost/geometry/strategies/spherical/area_spherical.hpp +++ b/include/boost/geometry/strategies/spherical/area_spherical.hpp @@ -134,11 +134,11 @@ struct default_strategy }; // Note: spherical polar coordinate system requires "get_as_radian_equatorial" -/***template +template struct default_strategy { typedef strategy::area::area_spherical type; -};***/ +}; } // namespace services diff --git a/test/algorithms/Jamfile.v2 b/test/algorithms/Jamfile.v2 index 63f218504..0903aa845 100644 --- a/test/algorithms/Jamfile.v2 +++ b/test/algorithms/Jamfile.v2 @@ -18,8 +18,6 @@ test-suite boost-geometry-algorithms : [ run append.cpp : : : : algorithms_append ] - [ run area.cpp : : : : algorithms_area ] - [ run area_multi.cpp : : : : algorithms_area_multi ] [ run assign.cpp : : : : algorithms_assign ] [ run centroid.cpp : : : : algorithms_centroid ] [ run centroid_multi.cpp : : : : algorithms_centroid_multi ] @@ -60,6 +58,7 @@ test-suite boost-geometry-algorithms [ run unique_multi.cpp : : : : algorithms_unique_multi ] ; +build-project area ; build-project buffer ; build-project detail ; build-project distance ; diff --git a/test/algorithms/area.cpp b/test/algorithms/area.cpp deleted file mode 100644 index 4e5f28259..000000000 --- a/test/algorithms/area.cpp +++ /dev/null @@ -1,369 +0,0 @@ -// 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. - -// This file was modified by Oracle on 2015, 2016. -// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates. - -// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle - -// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library -// (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) - - -#include - -#include -#include -#include -#include -#include - -#include -#include -//#define BOOST_GEOMETRY_TEST_DEBUG - -#include - -template -void test_polygon() -{ - // Rotated square, length=sqrt(2) -> area=2 - test_geometry("POLYGON((1 1,2 2,3 1,2 0,1 1))", 2.0); - test_geometry("POLYGON((1 1,2 2,3 1,2 0,1 1))", 2.0); - test_geometry("POLYGON((0 0,0 7,4 2,2 0,0 0))", 16.0); - test_geometry("POLYGON((1 1,2 1,2 2,1 2,1 1))", -1.0); - test_geometry("POLYGON((0 0,0 7,4 2,2 0,0 0), (1 1,2 1,2 2,1 2,1 1))", 15.0); -} - - -template -void test_all() -{ - test_geometry >("POLYGON((0 0,2 2))", 4.0); - test_geometry >("POLYGON((2 2,0 0))", 4.0); - - test_polygon >(); - test_polygon >(); - - // clockwise rings (second is wrongly ordered) - test_geometry >("POLYGON((0 0,0 7,4 2,2 0,0 0))", 16.0); - test_geometry >("POLYGON((0 0,2 0,4 2,0 7,0 0))", -16.0); - - test_geometry >("POLYGON((0 0,0 7,4 2,2 0,0 0))", 16.0); - - // ccw - test_geometry > - ("POLYGON((0 0,0 7,4 2,2 0,0 0), (1 1,2 1,2 2,1 2,1 1))", -15.0); - - test_geometry > - ("POLYGON((1 0,0 1,-1 0,0 -1,1 0))", 2); - - typedef typename bg::coordinate_type

::type coord_type; - if (BOOST_GEOMETRY_CONDITION((boost::is_same::value))) - { - test_geometry > - ("POLYGON((100000001 100000000, 100000000 100000001, \ - 99999999 100000000, 100000000 99999999))", 2); - } - else if (BOOST_GEOMETRY_CONDITION((boost::is_same::value))) - { - test_geometry > - ("POLYGON((100001 100000, 100000 100001, \ - 99999 100000, 100000 99999))", 2); - } -} - -template -void test_spherical(bool polar = false) -{ - typedef typename bg::coordinate_type::type ct; - bg::model::polygon geometry; - - // unit-sphere has area of 4-PI. Polygon covering 1/8 of it: - // calculations splitted for ttmath - ct const four = 4.0; - ct const eight = 8.0; - ct expected = four * boost::geometry::math::pi() / eight; - bg::read_wkt("POLYGON((0 0,0 90,90 0,0 0))", geometry); - - ct area = bg::area(geometry); - BOOST_CHECK_CLOSE(area, expected, 0.0001); - - // With strategy, radius 2 -> 4 pi r^2 - bg::strategy::area::area_spherical - < - typename bg::point_type::type - > strategy(2.0); - - area = bg::area(geometry, strategy); - ct const two = 2.0; - BOOST_CHECK_CLOSE(area, two * two * expected, 0.0001); - - // Wrangel Island (dateline crossing) - // With (spherical) Earth strategy - bg::strategy::area::area_spherical - < - typename bg::point_type::type - > spherical_earth(6373); - bg::read_wkt("POLYGON((-178.7858 70.7852, 177.4758 71.2333, 179.7436 71.5733, -178.7858 70.7852))", geometry); - area = bg::area(geometry, spherical_earth); - // SQL Server gives: 4537.9654419375 - // PostGIS gives: 4537.9311668307 - // Note: those are Geographic, this test is Spherical - BOOST_CHECK_CLOSE(area, 4506.6389, 0.001); - - // Wrangel, more in detail - bg::read_wkt("POLYGON((-178.568604 71.564148,-178.017548 71.449692,-177.833313 71.3461,-177.502838 71.277466 ,-177.439453 71.226929,-177.620026 71.116638,-177.9389 71.037491,-178.8186 70.979965,-179.274445 70.907761,-180 70.9972,179.678314 70.895538,179.272766 70.888596,178.791016 70.7964,178.617737 71.035538,178.872192 71.217484,179.530273 71.4383 ,-180 71.535843 ,-179.628601 71.577194,-179.305298 71.551361,-179.03421 71.597748,-178.568604 71.564148))", geometry); - area = bg::area(geometry, spherical_earth); - // SQL Server gives: 7669.10402181435 - // PostGIS gives: 7669.55565459832 - BOOST_CHECK_CLOSE(area, 7616.523769, 0.001); - - // Check more at the equator - /* - select 1,geography::STGeomFromText('POLYGON((-178.7858 10.7852 , 179.7436 11.5733 , 177.4758 11.2333 , -178.7858 10.7852))',4326) .STArea()/1000000.0 - union select 2,geography::STGeomFromText('POLYGON((-178.7858 20.7852 , 179.7436 21.5733 , 177.4758 21.2333 , -178.7858 20.7852))',4326) .STArea()/1000000.0 - union select 3,geography::STGeomFromText('POLYGON((-178.7858 30.7852 , 179.7436 31.5733 , 177.4758 31.2333 , -178.7858 30.7852))',4326) .STArea()/1000000.0 - union select 0,geography::STGeomFromText('POLYGON((-178.7858 0.7852 , 179.7436 1.5733 , 177.4758 1.2333 , -178.7858 0.7852))',4326) .STArea()/1000000.0 - union select 4,geography::STGeomFromText('POLYGON((-178.7858 40.7852 , 179.7436 41.5733 , 177.4758 41.2333 , -178.7858 40.7852))',4326) .STArea()/1000000.0 - */ - - bg::read_wkt("POLYGON((-178.7858 0.7852, 177.4758 1.2333, 179.7436 1.5733, -178.7858 0.7852))", geometry); - area = bg::area(geometry, spherical_earth); - BOOST_CHECK_CLOSE(area, 14136.09946, 0.001); // SQL Server gives: 14064.1902284513 - - - bg::read_wkt("POLYGON((-178.7858 10.7852, 177.4758 11.2333, 179.7436 11.5733, -178.7858 10.7852))", geometry); - area = bg::area(geometry, spherical_earth); - BOOST_CHECK_CLOSE(area, 13760.2456, 0.001); // SQL Server gives: 13697.0941155193 - - bg::read_wkt("POLYGON((-178.7858 20.7852, 177.4758 21.2333, 179.7436 21.5733, -178.7858 20.7852))", geometry); - area = bg::area(geometry, spherical_earth); - BOOST_CHECK_CLOSE(area, 12987.8682, 0.001); // SQL Server gives: 12944.3970990317 -> -39m^2 - - bg::read_wkt("POLYGON((-178.7858 30.7852, 177.4758 31.2333, 179.7436 31.5733, -178.7858 30.7852))", geometry); - area = bg::area(geometry, spherical_earth); - BOOST_CHECK_CLOSE(area, 11856.3935, 0.001); // SQL Server gives: 11838.5338423574 -> -18m^2 - - bg::read_wkt("POLYGON((-178.7858 40.7852, 177.4758 41.2333, 179.7436 41.5733, -178.7858 40.7852))", geometry); - area = bg::area(geometry, spherical_earth); - BOOST_CHECK_CLOSE(area, 10404.627685523914, 0.001); // SQL Server gives: 10412.0607137119, -> +8m^2 - - // Concave - bg::read_wkt("POLYGON((0 40,1 42,0 44,2 43,4 44,3 42,4 40,2 41,0 40))", geometry); - area = bg::area(geometry, spherical_earth); - BOOST_CHECK_CLOSE(area, 73538.2958, 0.001); // SQL Server gives: 73604.2047689719 - - // With hole POLYGON((0 40,4 40,4 44,0 44,0 40),(1 41,2 43,3 42,1 41)) - bg::read_wkt("POLYGON((0 40,0 44,4 44,4 40,0 40),(1 41,3 42,2 43,1 41))", geometry); - area = bg::area(geometry, spherical_earth); - BOOST_CHECK_CLOSE(area, 133233.844876, 0.001); // SQL Server gives: 133353.335 - - // around 0 meridian - { - bg::read_wkt("POLYGON((-10 0,-10 10,0 10,0 0,-10 0))", geometry); - ct area1 = bg::area(geometry); - bg::read_wkt("POLYGON((0 0,0 10,10 10,10 0,0 0))", geometry); - ct area2 = bg::area(geometry); - bg::read_wkt("POLYGON((-5 0,-5 10,5 10,5 0,-5 0))", geometry); - ct area3 = bg::area(geometry); - BOOST_CHECK_CLOSE(area1, area2, 0.001); - BOOST_CHECK_CLOSE(area2, area3, 0.001); - BOOST_CHECK_CLOSE(area1, 0.0303822, 0.001); - } - { - bg::read_wkt("POLYGON((-10 -5,-10 5,0 5,0 -5,-10 -5))", geometry); - ct area1 = bg::area(geometry); - bg::read_wkt("POLYGON((0 -5,0 5,10 5,10 -5,0 -5))", geometry); - ct area2 = bg::area(geometry); - bg::read_wkt("POLYGON((-5 -5,-5 5,5 5,5 -5,-5 -5))", geometry); - ct area3 = bg::area(geometry); - BOOST_CHECK_CLOSE(area1, area2, 0.001); - BOOST_CHECK_CLOSE(area2, area3, 0.001); - BOOST_CHECK_CLOSE(area1, 0.0305, 0.001); - } - // around 180 meridian - { - bg::read_wkt("POLYGON((-180 0,-180 10,-170 10,-170 0,-180 0))", geometry); - ct area1 = bg::area(geometry); - bg::read_wkt("POLYGON((175 0,175 10,-175 10,-175 0,175 0))", geometry); - ct area2 = bg::area(geometry); - bg::read_wkt("POLYGON((170 0,170 10,180 10,180 0,170 0))", geometry); - ct area3 = bg::area(geometry); - bg::read_wkt("POLYGON((170 0,170 10,-180 10,-180 0,170 0))", geometry); - ct area4 = bg::area(geometry); - bg::read_wkt("POLYGON((180 0,180 10,-170 10,-170 0,180 0))", geometry); - ct area5 = bg::area(geometry); - BOOST_CHECK_CLOSE(area1, area2, 0.001); - BOOST_CHECK_CLOSE(area2, area3, 0.001); - BOOST_CHECK_CLOSE(area3, area4, 0.001); - BOOST_CHECK_CLOSE(area4, area5, 0.001); - BOOST_CHECK_CLOSE(area1, 0.0303822, 0.001); - } - { - bg::read_wkt("POLYGON((-180 -5,-180 5,-170 5,-170 -5,-180 -5))", geometry); - ct area1 = bg::area(geometry); - bg::read_wkt("POLYGON((175 -5,175 5,-175 5,-175 -5,175 -5))", geometry); - ct area2 = bg::area(geometry); - bg::read_wkt("POLYGON((170 -5,170 5,180 5,180 -5,170 -5))", geometry); - ct area3 = bg::area(geometry); - bg::read_wkt("POLYGON((170 -5,170 5,-180 5,-180 -5,170 -5))", geometry); - ct area4 = bg::area(geometry); - bg::read_wkt("POLYGON((180 -5,180 5,-170 5,-170 -5,180 -5))", geometry); - ct area5 = bg::area(geometry); - BOOST_CHECK_CLOSE(area1, area2, 0.001); - BOOST_CHECK_CLOSE(area2, area3, 0.001); - BOOST_CHECK_CLOSE(area3, area4, 0.001); - BOOST_CHECK_CLOSE(area4, area5, 0.001); - BOOST_CHECK_CLOSE(area1, 0.0305, 0.001); - } - // around poles - { - bg::read_wkt("POLYGON((0 80,-90 80,-180 80,90 80,0 80))", geometry); - ct area1 = bg::area(geometry); - bg::read_wkt("POLYGON((0 80,-90 80,180 80,90 80,0 80))", geometry); - ct area2 = bg::area(geometry); - bg::read_wkt("POLYGON((0 -80,90 -80,-180 -80,-90 -80,0 -80))", geometry); - ct area3 = bg::area(geometry); - bg::read_wkt("POLYGON((0 -80,90 -80,180 -80,-90 -80,0 -80))", geometry); - ct area4 = bg::area(geometry); - BOOST_CHECK_CLOSE(area1, area2, 0.001); - BOOST_CHECK_CLOSE(area2, area3, 0.001); - BOOST_CHECK_CLOSE(area3, area4, 0.001); - } - - { - bg::model::ring aurha; // a'dam-utr-rott.-den haag-a'dam - bg::read_wkt("POLYGON((4.892 52.373,5.119 52.093,4.479 51.930,4.23 52.08,4.892 52.373))", aurha); - if (polar) - { - // Create colatitudes (measured from pole) - BOOST_FOREACH(Point& p, aurha) - { - bg::set<1>(p, ct(90) - bg::get<1>(p)); - } - bg::correct(aurha); - } - bg::strategy::area::area_spherical - < - typename bg::point_type::type - > area_spherical(6372.795); - area = bg::area(aurha, area_spherical); - BOOST_CHECK_CLOSE(area, 1476.645675, 0.0001); - - // SQL Server gives: 1481.55595960659 - // for select geography::STGeomFromText('POLYGON((4.892 52.373,4.23 52.08,4.479 51.930,5.119 52.093,4.892 52.373))',4326).STArea()/1000000.0 - } -} - -template -void test_ccw() -{ - typedef bg::model::polygon ccw_polygon; - // counterclockwise rings (second is wrongly ordered) - test_geometry("POLYGON((1 1,2 2,3 1,2 0,1 1))", -2.0); - test_geometry("POLYGON((1 1,2 0,3 1,2 2,1 1))", +2.0); - test_geometry("POLYGON((0 0,0 7,4 2,2 0,0 0))", -16.0); - test_geometry("POLYGON((0 0,2 0,4 2,0 7,0 0))", +16.0); -} - -template -void test_open() -{ - typedef bg::model::polygon open_polygon; - test_geometry("POLYGON((1 1,2 2,3 1,2 0))", 2.0); - // Note the triangular testcase used in CCW is not sensible for open/close -} - -template -void test_open_ccw() -{ - typedef bg::model::polygon open_polygon; - test_geometry("POLYGON((1 1,2 0,3 1,2 2))", 2.0); - // Note the triangular testcase used in CCW is not sensible for open/close -} - -template -void test_empty_input() -{ - bg::model::polygon

poly_empty; - bg::model::ring

ring_empty; - - test_empty_input(poly_empty); - test_empty_input(ring_empty); -} - -void test_large_integers() -{ - typedef bg::model::point int_point_type; - typedef bg::model::point double_point_type; - - bg::model::polygon int_poly; - bg::model::polygon double_poly; - - std::string const polygon_li = "POLYGON((1872000 528000,1872000 192000,1536119 192000,1536000 528000,1200000 528000,1200000 863880,1536000 863880,1872000 863880,1872000 528000))"; - bg::read_wkt(polygon_li, int_poly); - bg::read_wkt(polygon_li, double_poly); - - double int_area = bg::area(int_poly); - double double_area = bg::area(double_poly); - - BOOST_CHECK_CLOSE(int_area, double_area, 0.0001); -} - -void test_variant() -{ - typedef bg::model::point double_point_type; - typedef bg::model::polygon polygon_type; - typedef bg::model::box box_type; - - polygon_type poly; - std::string const polygon_li = "POLYGON((18 5,18 1,15 1,15 5,12 5,12 8,15 8,18 8,18 5))"; - bg::read_wkt(polygon_li, poly); - - box_type box; - std::string const box_li = "BOX(0 0,2 2)"; - bg::read_wkt(box_li, box); - - boost::variant v; - - v = poly; - BOOST_CHECK_CLOSE(bg::area(v), bg::area(poly), 0.0001); - v = box; - BOOST_CHECK_CLOSE(bg::area(v), bg::area(box), 0.0001); -} - -int test_main(int, char* []) -{ - test_all >(); - test_all >(); - test_all >(); - - test_spherical > >(); - //test_spherical > >(true); - - test_ccw >(); - test_open >(); - test_open_ccw >(); - -#ifdef HAVE_TTMATH - test_all >(); - test_spherical > >(); -#endif - - test_large_integers(); - - test_variant(); - - // test_empty_input >(); - - return 0; -} diff --git a/test/algorithms/area/Jamfile.v2 b/test/algorithms/area/Jamfile.v2 new file mode 100644 index 000000000..0e2fa53e7 --- /dev/null +++ b/test/algorithms/area/Jamfile.v2 @@ -0,0 +1,16 @@ +# Boost.Geometry (aka GGL, Generic Geometry Library) +# +# Copyright (c) 2016 Oracle and/or its affiliates. +# +# Contributed and/or modified by Vissarion Fisikopoulos, 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) + +test-suite boost-geometry-algorithms-length + : + [ run area.cpp : : : : algorithms_area ] + [ run area_multi.cpp : : : : algorithms_area_multi ] + ; + diff --git a/test/algorithms/area/area.cpp b/test/algorithms/area/area.cpp new file mode 100644 index 000000000..d92d9e41c --- /dev/null +++ b/test/algorithms/area/area.cpp @@ -0,0 +1,574 @@ +// 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. + +// This file was modified by Oracle on 2015, 2016. +// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates. + +// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle +// Contributed and/or modified by Adam Wulkiewicz, 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) + + +#include + +#include +#include +#include +#include +#include + +#include +#include +//#define BOOST_GEOMETRY_TEST_DEBUG + +#include + +template +void test_polygon() +{ + // Rotated square, length=sqrt(2) -> area=2 + test_geometry("POLYGON((1 1,2 2,3 1,2 0,1 1))", 2.0); + test_geometry("POLYGON((1 1,2 2,3 1,2 0,1 1))", 2.0); + test_geometry("POLYGON((0 0,0 7,4 2,2 0,0 0))", 16.0); + test_geometry("POLYGON((1 1,2 1,2 2,1 2,1 1))", -1.0); + test_geometry("POLYGON((0 0,0 7,4 2,2 0,0 0), (1 1,2 1,2 2,1 2,1 1))", 15.0); +} + + +template +void test_all() +{ + test_geometry >("POLYGON((0 0,2 2))", 4.0); + test_geometry >("POLYGON((2 2,0 0))", 4.0); + + test_polygon >(); + test_polygon >(); + + // clockwise rings (second is wrongly ordered) + test_geometry >("POLYGON((0 0,0 7,4 2,2 0,0 0))", 16.0); + test_geometry >("POLYGON((0 0,2 0,4 2,0 7,0 0))", -16.0); + + test_geometry >("POLYGON((0 0,0 7,4 2,2 0,0 0))", 16.0); + + // ccw + test_geometry > + ("POLYGON((0 0,0 7,4 2,2 0,0 0), (1 1,2 1,2 2,1 2,1 1))", -15.0); + + test_geometry > + ("POLYGON((1 0,0 1,-1 0,0 -1,1 0))", 2); + + typedef typename bg::coordinate_type

::type coord_type; + if (BOOST_GEOMETRY_CONDITION((boost::is_same::value))) + { + test_geometry > + ("POLYGON((100000001 100000000, 100000000 100000001, \ + 99999999 100000000, 100000000 99999999))", 2); + } + else if (BOOST_GEOMETRY_CONDITION((boost::is_same::value))) + { + test_geometry > + ("POLYGON((100001 100000, 100000 100001, \ + 99999 100000, 100000 99999))", 2); + } +} + +template +void test_spherical_geo() +{ + typedef CT ct; + + //Geographic + + typedef typename bg::model::point< + ct, + 2, + bg::cs::geographic + > pt_geo; + + typedef typename bg::point_type::type pt_geo_type; + + typedef typename bg::formula::vincenty_inverse + < + ct, + false, + true, + true + > geo_strategy; + + bg::strategy::area::area_geographic + < + pt_geo_type, + geo_strategy, + 5, + true + > area_geographic; + + bg::model::polygon geometry_geo; + + //Spherical + + typedef typename bg::model::point< + ct, + 2, + bg::cs::spherical_equatorial + > pt; + bg::model::polygon geometry; + + // unit-sphere has area of 4-PI. Polygon covering 1/8 of it: + // calculations splitted for ttmath + std::string poly = "POLYGON((0 0,0 90,90 0,0 0))"; + + ct const four = 4.0; + ct const eight = 8.0; + ct expected = four * boost::geometry::math::pi() / eight; + bg::read_wkt(poly, geometry); + ct area = bg::area(geometry); + BOOST_CHECK_CLOSE(area, expected, 0.0001); + + // With strategy, radius 2 -> 4 pi r^2 + bg::strategy::area::area_spherical + < + typename bg::point_type::type + > strategy(2.0); + + area = bg::area(geometry, strategy); + ct const two = 2.0; + BOOST_CHECK_CLOSE(area, two * two * expected, 0.0001); + + // Geographic total area of earth is about 510072000 + // (https://en.wikipedia.org/wiki/Earth) + // So the 1/8 is 63759000 and here we get something close to it + bg::read_wkt(poly, geometry_geo); + area = bg::area(geometry_geo, area_geographic); + //GeoGraphicLib gives: 63758202715511.055 + BOOST_CHECK_CLOSE(area, 63758202715509.859, 0.0001); + + + // Wrangel Island (dateline crossing) + // With (spherical) Earth strategy + poly = "POLYGON((-178.7858 70.7852, 177.4758 71.2333, 179.7436 71.5733, -178.7858 70.7852))"; + + bg::strategy::area::area_spherical + < + typename bg::point_type::type + > spherical_earth(6373); + bg::read_wkt(poly, geometry); + area = bg::area(geometry, spherical_earth); + // SQL Server gives: 4537.9654419375 + // PostGIS gives: 4537.9311668307 + // Note: those are Geographic, this test is Spherical + BOOST_CHECK_CLOSE(area, 4506.6389, 0.001); + + bg::read_wkt(poly, geometry_geo); + area = bg::area(geometry_geo, area_geographic); + BOOST_CHECK_CLOSE(area, 4537974350.6843719, 0.0001); + + // Wrangel, more in detail + poly = "POLYGON((-178.568604 71.564148,-178.017548 71.449692,-177.833313 71.3461,\ + -177.502838 71.277466 ,-177.439453 71.226929,-177.620026 71.116638,\ + -177.9389 71.037491,-178.8186 70.979965,-179.274445 70.907761,\ + -180 70.9972,179.678314 70.895538,179.272766 70.888596,\ + 178.791016 70.7964,178.617737 71.035538,178.872192 71.217484,\ + 179.530273 71.4383 ,-180 71.535843 ,-179.628601 71.577194,\ + -179.305298 71.551361,-179.03421 71.597748,-178.568604 71.564148))"; + bg::read_wkt(poly, geometry); + area = bg::area(geometry, spherical_earth); + // SQL Server gives: 7669.10402181435 + // PostGIS gives: 7669.55565459832 + BOOST_CHECK_CLOSE(area, 7616.523769, 0.001); + + bg::read_wkt(poly, geometry_geo); + area = bg::area(geometry_geo, area_geographic); + BOOST_CHECK_CLOSE(area, 7669498457.4130802, 0.0001); + + // Check more at the equator + /* + select 1,geography::STGeomFromText('POLYGON((-178.7858 10.7852 , 179.7436 11.5733 , 177.4758 11.2333 , -178.7858 10.7852))',4326) .STArea()/1000000.0 + union select 2,geography::STGeomFromText('POLYGON((-178.7858 20.7852 , 179.7436 21.5733 , 177.4758 21.2333 , -178.7858 20.7852))',4326) .STArea()/1000000.0 + union select 3,geography::STGeomFromText('POLYGON((-178.7858 30.7852 , 179.7436 31.5733 , 177.4758 31.2333 , -178.7858 30.7852))',4326) .STArea()/1000000.0 + union select 0,geography::STGeomFromText('POLYGON((-178.7858 0.7852 , 179.7436 1.5733 , 177.4758 1.2333 , -178.7858 0.7852))',4326) .STArea()/1000000.0 + union select 4,geography::STGeomFromText('POLYGON((-178.7858 40.7852 , 179.7436 41.5733 , 177.4758 41.2333 , -178.7858 40.7852))',4326) .STArea()/1000000.0 + */ + + poly = "POLYGON((-178.7858 0.7852, 177.4758 1.2333, 179.7436 1.5733, -178.7858 0.7852))"; + bg::read_wkt(poly, geometry); + area = bg::area(geometry, spherical_earth); + BOOST_CHECK_CLOSE(area, 14136.09946, 0.001); // SQL Server gives: 14064.1902284513 + bg::read_wkt(poly, geometry_geo); + area = bg::area(geometry_geo, area_geographic); + BOOST_CHECK_CLOSE(area, 14064196647.560314, 0.0001); + + poly = "POLYGON((-178.7858 10.7852, 177.4758 11.2333, 179.7436 11.5733, -178.7858 10.7852))"; + bg::read_wkt(poly, geometry); + area = bg::area(geometry, spherical_earth); + BOOST_CHECK_CLOSE(area, 13760.2456, 0.001); // SQL Server gives: 13697.0941155193 + bg::read_wkt(poly, geometry_geo); + area = bg::area(geometry_geo, area_geographic); + BOOST_CHECK_CLOSE(area, 13697095227.008451, 0.0001); + + poly = "POLYGON((-178.7858 20.7852, 177.4758 21.2333, 179.7436 21.5733, -178.7858 20.7852))"; + bg::read_wkt(poly, geometry); + area = bg::area(geometry, spherical_earth); + BOOST_CHECK_CLOSE(area, 12987.8682, 0.001); // SQL Server gives: 12944.3970990317 -> -39m^2 + bg::read_wkt(poly, geometry_geo); + area = bg::area(geometry_geo, area_geographic); + BOOST_CHECK_CLOSE(area, 12944392155.546635, 0.0001); + + poly = "POLYGON((-178.7858 30.7852, 177.4758 31.2333, 179.7436 31.5733, -178.7858 30.7852))"; + bg::read_wkt(poly, geometry); + area = bg::area(geometry, spherical_earth); + BOOST_CHECK_CLOSE(area, 11856.3935, 0.001); // SQL Server gives: 11838.5338423574 -> -18m^2 + bg::read_wkt(poly, geometry_geo); + area = bg::area(geometry_geo, area_geographic); + BOOST_CHECK_CLOSE(area, 11838524075.970982, 0.0001); + + poly = "POLYGON((-178.7858 40.7852, 177.4758 41.2333, 179.7436 41.5733, -178.7858 40.7852))"; + bg::read_wkt(poly, geometry); + area = bg::area(geometry, spherical_earth); + BOOST_CHECK_CLOSE(area, 10404.627685523914, 0.001); // SQL Server gives: 10412.0607137119, -> +8m^2 + bg::read_wkt(poly, geometry_geo); + area = bg::area(geometry_geo, area_geographic); + BOOST_CHECK_CLOSE(area, 10412049661.81769, 0.0001); + + // Concave + poly = "POLYGON((0 40,1 42,0 44,2 43,4 44,3 42,4 40,2 41,0 40))"; + bg::read_wkt(poly, geometry); + area = bg::area(geometry, spherical_earth); + BOOST_CHECK_CLOSE(area, 73538.2958, 0.001); // SQL Server gives: 73604.2047689719 + bg::read_wkt(poly, geometry_geo); + area = bg::area(geometry_geo, area_geographic); + BOOST_CHECK_CLOSE(area, 73604208172.719223, 0.0001); + + // With hole POLYGON((0 40,4 40,4 44,0 44,0 40),(1 41,2 43,3 42,1 41)) + poly = "POLYGON((0 40,0 44,4 44,4 40,0 40),(1 41,3 42,2 43,1 41))"; + bg::read_wkt(poly, geometry); + area = bg::area(geometry, spherical_earth); + BOOST_CHECK_CLOSE(area, 133233.844876, 0.001); // SQL Server gives: 133353.335 + bg::read_wkt(poly, geometry_geo); + area = bg::area(geometry_geo, area_geographic); + BOOST_CHECK_CLOSE(area, 133353331647.58241, 0.0001); + + // around 0 meridian + { + std::string poly1 = "POLYGON((-10 0,-10 10,0 10,0 0,-10 0))"; + std::string poly2 = "POLYGON((0 0,0 10,10 10,10 0,0 0))"; + std::string poly3 = "POLYGON((-5 0,-5 10,5 10,5 0,-5 0))"; + bg::read_wkt(poly1, geometry); + ct area1 = bg::area(geometry); + bg::read_wkt(poly2, geometry); + ct area2 = bg::area(geometry); + bg::read_wkt(poly3, geometry); + ct area3 = bg::area(geometry); + BOOST_CHECK_CLOSE(area1, area2, 0.001); + BOOST_CHECK_CLOSE(area2, area3, 0.001); + BOOST_CHECK_CLOSE(area1, 0.0303822, 0.001); + //geographic + bg::read_wkt(poly1, geometry_geo); + area1 = bg::area(geometry_geo, area_geographic); + bg::read_wkt(poly2, geometry_geo); + area2 = bg::area(geometry_geo, area_geographic); + bg::read_wkt(poly3, geometry_geo); + area3 = bg::area(geometry_geo, area_geographic); + BOOST_CHECK_CLOSE(area1, area2, 0.001); + BOOST_CHECK_CLOSE(area2, area3, 0.001); + BOOST_CHECK_CLOSE(area1, 1227857282668.3145, 0.001); + } + { + std::string poly1 = "POLYGON((-10 -5,-10 5,0 5,0 -5,-10 -5))"; + std::string poly2 = "POLYGON((0 -5,0 5,10 5,10 -5,0 -5))"; + std::string poly3 = "POLYGON((-5 -5,-5 5,5 5,5 -5,-5 -5))"; + bg::read_wkt(poly1, geometry); + ct area1 = bg::area(geometry); + bg::read_wkt(poly2, geometry); + ct area2 = bg::area(geometry); + bg::read_wkt(poly3, geometry); + ct area3 = bg::area(geometry); + BOOST_CHECK_CLOSE(area1, area2, 0.001); + BOOST_CHECK_CLOSE(area2, area3, 0.001); + BOOST_CHECK_CLOSE(area1, 0.0305, 0.001); + //geographic + bg::read_wkt(poly1, geometry_geo); + area1 = bg::area(geometry_geo, area_geographic); + bg::read_wkt(poly2, geometry_geo); + area2 = bg::area(geometry_geo, area_geographic); + bg::read_wkt(poly3, geometry_geo); + area3 = bg::area(geometry_geo, area_geographic); + BOOST_CHECK_CLOSE(area1, area2, 0.001); + BOOST_CHECK_CLOSE(area2, area3, 0.001); + BOOST_CHECK_CLOSE(area1, 1232493707152.2292, 0.001); + } + // around 180 meridian + { + std::string poly1 = "POLYGON((-180 0,-180 10,-170 10,-170 0,-180 0))"; + std::string poly2 = "POLYGON((175 0,175 10,-175 10,-175 0,175 0))"; + std::string poly3 = "POLYGON((170 0,170 10,180 10,180 0,170 0))"; + std::string poly4 = "POLYGON((170 0,170 10,-180 10,-180 0,170 0))"; + std::string poly5 = "POLYGON((180 0,180 10,-170 10,-170 0,180 0))"; + bg::read_wkt(poly1, geometry); + ct area1 = bg::area(geometry); + bg::read_wkt(poly2, geometry); + ct area2 = bg::area(geometry); + bg::read_wkt(poly3, geometry); + ct area3 = bg::area(geometry); + bg::read_wkt(poly4, geometry); + ct area4 = bg::area(geometry); + bg::read_wkt(poly5, geometry); + ct area5 = bg::area(geometry); + BOOST_CHECK_CLOSE(area1, area2, 0.001); + BOOST_CHECK_CLOSE(area2, area3, 0.001); + BOOST_CHECK_CLOSE(area3, area4, 0.001); + BOOST_CHECK_CLOSE(area4, area5, 0.001); + BOOST_CHECK_CLOSE(area1, 0.0303822, 0.001); + //geographic + bg::read_wkt(poly1, geometry_geo); + area1 = bg::area(geometry_geo, area_geographic); + bg::read_wkt(poly2, geometry_geo); + area2 = bg::area(geometry_geo, area_geographic); + bg::read_wkt(poly3, geometry_geo); + area3 = bg::area(geometry_geo, area_geographic); + bg::read_wkt(poly4, geometry_geo); + area4 = bg::area(geometry_geo, area_geographic); + bg::read_wkt(poly5, geometry_geo); + area5 = bg::area(geometry_geo, area_geographic); + BOOST_CHECK_CLOSE(area1, area2, 0.001); + BOOST_CHECK_CLOSE(area2, area3, 0.001); + BOOST_CHECK_CLOSE(area3, area4, 0.001); + BOOST_CHECK_CLOSE(area4, area5, 0.001); + BOOST_CHECK_CLOSE(area1, 1227857282668.313, 0.001); + } + { + std::string poly1 = "POLYGON((-180 -5,-180 5,-170 5,-170 -5,-180 -5))"; + std::string poly2 = "POLYGON((175 -5,175 5,-175 5,-175 -5,175 -5))"; + std::string poly3 = "POLYGON((170 -5,170 5,180 5,180 -5,170 -5))"; + std::string poly4 = "POLYGON((170 -5,170 5,180 5,180 -5,170 -5))"; + std::string poly5 = "POLYGON((180 -5,180 5,-170 5,-170 -5,180 -5))"; + bg::read_wkt(poly1, geometry); + ct area1 = bg::area(geometry); + bg::read_wkt(poly2, geometry); + ct area2 = bg::area(geometry); + bg::read_wkt(poly3, geometry); + ct area3 = bg::area(geometry); + bg::read_wkt(poly4, geometry); + ct area4 = bg::area(geometry); + bg::read_wkt(poly5, geometry); + ct area5 = bg::area(geometry); + BOOST_CHECK_CLOSE(area1, area2, 0.001); + BOOST_CHECK_CLOSE(area2, area3, 0.001); + BOOST_CHECK_CLOSE(area3, area4, 0.001); + BOOST_CHECK_CLOSE(area4, area5, 0.001); + BOOST_CHECK_CLOSE(area1, 0.0305, 0.001); + //geographic + bg::read_wkt(poly1, geometry_geo); + area1 = bg::area(geometry_geo, area_geographic); + bg::read_wkt(poly2, geometry_geo); + area2 = bg::area(geometry_geo, area_geographic); + bg::read_wkt(poly3, geometry_geo); + area3 = bg::area(geometry_geo, area_geographic); + bg::read_wkt(poly4, geometry_geo); + area4 = bg::area(geometry_geo, area_geographic); + bg::read_wkt(poly5, geometry_geo); + area5 = bg::area(geometry_geo, area_geographic); + BOOST_CHECK_CLOSE(area1, area2, 0.001); + BOOST_CHECK_CLOSE(area2, area3, 0.001); + BOOST_CHECK_CLOSE(area3, area4, 0.001); + BOOST_CHECK_CLOSE(area4, area5, 0.001); + BOOST_CHECK_CLOSE(area1, 1232493707152.2278, 0.001); + } + // around poles + { + std::string poly1 = "POLYGON((0 80,-90 80,-180 80,90 80,0 80))"; + std::string poly2 = "POLYGON((0 80,-90 80,180 80,90 80,0 80))"; + std::string poly3 = "POLYGON((0 -80,90 -80,-180 -80,-90 -80,0 -80))"; + std::string poly4 = "POLYGON((0 -80,90 -80,180 -80,-90 -80,0 -80))"; + bg::read_wkt(poly1, geometry); + ct area1 = bg::area(geometry); + bg::read_wkt(poly2, geometry); + ct area2 = bg::area(geometry); + bg::read_wkt(poly3, geometry); + ct area3 = bg::area(geometry); + bg::read_wkt(poly4, geometry); + ct area4 = bg::area(geometry); + BOOST_CHECK_CLOSE(area1, area2, 0.001); + BOOST_CHECK_CLOSE(area2, area3, 0.001); + BOOST_CHECK_CLOSE(area3, area4, 0.001); + //geographic + bg::read_wkt(poly1, geometry_geo); + area1 = bg::area(geometry_geo, area_geographic); + bg::read_wkt(poly2, geometry_geo); + area2 = bg::area(geometry_geo, area_geographic); + bg::read_wkt(poly3, geometry_geo); + area3 = bg::area(geometry_geo, area_geographic); + bg::read_wkt(poly4, geometry_geo); + area4 = bg::area(geometry_geo, area_geographic); + BOOST_CHECK_CLOSE(area1, area2, 0.001); + BOOST_CHECK_CLOSE(area2, area3, 0.001); + BOOST_CHECK_CLOSE(area3, area4, 0.001); + } + + { + bg::model::ring aurha; // a'dam-utr-rott.-den haag-a'dam + std::string poly = "POLYGON((4.892 52.373,5.119 52.093,4.479 51.930,4.23 52.08,4.892 52.373))"; + bg::read_wkt(poly, aurha); + /*if (polar) + { + // Create colatitudes (measured from pole) + BOOST_FOREACH(pt& p, aurha) + { + bg::set<1>(p, ct(90) - bg::get<1>(p)); + } + bg::correct(aurha); + }*/ + bg::strategy::area::area_spherical + < + typename bg::point_type::type + > area_spherical(6372.795); + area = bg::area(aurha, area_spherical); + BOOST_CHECK_CLOSE(area, 1476.645675, 0.0001); + //geographic + bg::read_wkt(poly, geometry_geo); + area = bg::area(geometry_geo, area_geographic); + BOOST_CHECK_CLOSE(area, 1481555970.0765088, 0.001); + + // SQL Server gives: 1481.55595960659 + // for select geography::STGeomFromText('POLYGON((4.892 52.373,4.23 52.08,4.479 51.930,5.119 52.093,4.892 52.373))',4326).STArea()/1000000.0 + } + +} + +template +void test_ccw() +{ + typedef typename bg::coordinate_type

::type ct; + bg::model::polygon ccw_polygon; + // counterclockwise rings (second is wrongly ordered) + std::string poly1 = "POLYGON((1 1,2 2,3 1,2 0,1 1))"; + std::string poly2 = "POLYGON((1 1,2 0,3 1,2 2,1 1))"; + std::string poly3 = "POLYGON((0 0,0 7,4 2,2 0,0 0))"; + std::string poly4 = "POLYGON((0 0,2 0,4 2,0 7,0 0))"; + + bg::read_wkt(poly1, ccw_polygon); + ct area1 = bg::area(ccw_polygon); + bg::read_wkt(poly2, ccw_polygon); + ct area2 = bg::area(ccw_polygon); + bg::read_wkt(poly3, ccw_polygon); + ct area3 = bg::area(ccw_polygon); + bg::read_wkt(poly4, ccw_polygon); + ct area4 = bg::area(ccw_polygon); + BOOST_CHECK_CLOSE(area1, -1 * area2, 0.001); + BOOST_CHECK_CLOSE(area3, -1 * area4, 0.001); +} + +template +void test_open(CT expected_area) +{ + typedef bg::model::polygon open_polygon; + test_geometry("POLYGON((1 1,2 2,3 1,2 0))", expected_area); + // Note the triangular testcase used in CCW is not sensible for open/close +} + +template +void test_open_ccw(CT expected_area) +{ + typedef bg::model::polygon open_polygon; + test_geometry("POLYGON((1 1,2 0,3 1,2 2))", expected_area); + // Note the triangular testcase used in CCW is not sensible for open/close +} + +template +void test_empty_input() +{ + bg::model::polygon

poly_empty; + bg::model::ring

ring_empty; + + test_empty_input(poly_empty); + test_empty_input(ring_empty); +} + +void test_large_integers() +{ + typedef bg::model::point int_point_type; + typedef bg::model::point double_point_type; + + bg::model::polygon int_poly; + bg::model::polygon double_poly; + + std::string const polygon_li = "POLYGON((1872000 528000,1872000 192000,1536119 192000,1536000 528000,1200000 528000,1200000 863880,1536000 863880,1872000 863880,1872000 528000))"; + bg::read_wkt(polygon_li, int_poly); + bg::read_wkt(polygon_li, double_poly); + + double int_area = bg::area(int_poly); + double double_area = bg::area(double_poly); + + BOOST_CHECK_CLOSE(int_area, double_area, 0.0001); +} + +void test_variant() +{ + typedef bg::model::point double_point_type; + typedef bg::model::polygon polygon_type; + typedef bg::model::box box_type; + + polygon_type poly; + std::string const polygon_li = "POLYGON((18 5,18 1,15 1,15 5,12 5,12 8,15 8,18 8,18 5))"; + bg::read_wkt(polygon_li, poly); + + box_type box; + std::string const box_li = "BOX(0 0,2 2)"; + bg::read_wkt(box_li, box); + + boost::variant v; + + v = poly; + BOOST_CHECK_CLOSE(bg::area(v), bg::area(poly), 0.0001); + v = box; + BOOST_CHECK_CLOSE(bg::area(v), bg::area(box), 0.0001); +} + +int test_main(int, char* []) +{ + + test_all >(); + test_all >(); + test_all >(); + + test_spherical_geo(); + + typedef bg::model::point pt_crt; + typedef bg::model::point > pt_sph; + typedef bg::model::point > pt_geo; + + test_ccw(); + test_ccw(); + test_ccw(); + + test_open(2.0); + test_open(0.00060917296206278821); + test_open(24615760871.487991); + + test_open_ccw(2.0); + test_open_ccw(0.00060917296206278821); + test_open_ccw(24615760871.487991); + +#ifdef HAVE_TTMATH + test_all >(); + test_spherical_geo(); +#endif + + test_large_integers(); + + test_variant(); + + // test_empty_input >(); + + return 0; +} diff --git a/test/algorithms/area/area_multi.cpp b/test/algorithms/area/area_multi.cpp new file mode 100644 index 000000000..b57148532 --- /dev/null +++ b/test/algorithms/area/area_multi.cpp @@ -0,0 +1,52 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) +// +// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. +// +// This file was modified by Oracle on 2015, 2016. +// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates. +// +// Contributed and/or modified by Vissarion Fysikopoulos, 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) + + +#include + +#include +#include +#include + +#include + + + + +template +void test_all() +{ + typedef typename bg::model::d2::point_xy pt_crt; + typedef typename bg::model::point > pt_sph; + typedef typename bg::model::point > pt_geo; + + typedef bg::model::multi_polygon > mp_crt; + typedef bg::model::multi_polygon > mp_sph; + typedef bg::model::multi_polygon > mp_geo; + + std::string poly = "MULTIPOLYGON(((0 0,0 7,4 2,2 0,0 0)))"; + test_geometry(poly, 16.0); + test_geometry(poly, 0.0048755521103139238); + test_geometry(poly, 197020675141.16785); +} + +int test_main( int , char* [] ) +{ + test_all(); + +#ifdef HAVE_TTMATH + test_all >(); +#endif + + return 0; +} diff --git a/test/algorithms/test_area.hpp b/test/algorithms/area/test_area.hpp similarity index 100% rename from test/algorithms/test_area.hpp rename to test/algorithms/area/test_area.hpp diff --git a/test/algorithms/area_multi.cpp b/test/algorithms/area_multi.cpp deleted file mode 100644 index fdb9ea6d7..000000000 --- a/test/algorithms/area_multi.cpp +++ /dev/null @@ -1,36 +0,0 @@ -// Boost.Geometry (aka GGL, Generic Geometry Library) -// -// Copyright (c) 2007-2015 Barend Gehrels, 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) - - -#include - -#include -#include -#include - -#include - - - - -template -void test_all() -{ - typedef bg::model::multi_polygon > mp; - test_geometry("MULTIPOLYGON(((0 0,0 7,4 2,2 0,0 0)))", 16.0); -} - -int test_main( int , char* [] ) -{ - test_all >(); - -#ifdef HAVE_TTMATH - test_all >(); -#endif - - return 0; -} From d1c21baf6079e01bd83d6829aa7d980bbe5bde75 Mon Sep 17 00:00:00 2001 From: Vissarion Fysikopoulos Date: Mon, 15 Aug 2016 19:38:46 +0300 Subject: [PATCH 09/89] merge and resolve conflicts --- .../doxygen_input/sourcecode/doxygen_5.cpp | 8 +- doc/quickbook/quickref.xml | 44 +- doc/release_notes.qbk | 4 + extensions/test/algorithms/dissolve.cpp | 11 +- include/boost/geometry/algorithms/append.hpp | 2 +- include/boost/geometry/algorithms/area.hpp | 7 +- include/boost/geometry/algorithms/assign.hpp | 18 +- include/boost/geometry/algorithms/buffer.hpp | 12 +- .../boost/geometry/algorithms/centroid.hpp | 2 +- include/boost/geometry/algorithms/clear.hpp | 2 +- include/boost/geometry/algorithms/convert.hpp | 2 +- .../boost/geometry/algorithms/convex_hull.hpp | 10 +- include/boost/geometry/algorithms/correct.hpp | 2 +- .../boost/geometry/algorithms/covered_by.hpp | 6 +- include/boost/geometry/algorithms/crosses.hpp | 4 +- .../algorithms/detail/assign_box_corners.hpp | 4 +- .../detail/assign_indexed_point.hpp | 8 +- .../buffer/buffered_piece_collection.hpp | 25 +- .../detail/buffer/buffered_ring.hpp | 16 + .../detail/comparable_distance/interface.hpp | 8 +- .../algorithms/detail/disjoint/interface.hpp | 2 +- .../algorithms/detail/distance/interface.hpp | 8 +- .../algorithms/detail/envelope/interface.hpp | 4 +- .../detail/equals/collect_vectors.hpp | 2 +- .../algorithms/detail/expand/interface.hpp | 8 +- .../algorithms/detail/extreme_points.hpp | 6 +- .../detail/intersection/interface.hpp | 4 +- .../algorithms/detail/is_simple/interface.hpp | 2 +- .../algorithms/detail/is_valid/interface.hpp | 2 +- .../detail/overlay/cluster_info.hpp | 49 ++ .../detail/overlay/copy_segment_point.hpp | 14 +- .../detail/overlay/copy_segments.hpp | 2 +- .../overlay/enrich_intersection_points.hpp | 11 +- .../detail/overlay/enrichment_info.hpp | 6 +- .../overlay/get_intersection_points.hpp | 2 +- .../algorithms/detail/overlay/get_turns.hpp | 2 +- .../detail/overlay/handle_colocations.hpp | 172 +++- .../detail/overlay/handle_touch.hpp | 336 ------- .../detail/overlay/intersection_insert.hpp | 8 +- .../algorithms/detail/overlay/overlay.hpp | 31 +- .../detail/overlay/overlay_type.hpp | 38 + .../detail/overlay/select_rings.hpp | 6 +- .../detail/overlay/self_turn_points.hpp | 2 +- .../detail/overlay/sort_by_side.hpp | 190 +++- .../algorithms/detail/overlay/traversal.hpp | 672 ++++++++++++++ .../detail/overlay/traversal_ring_creator.hpp | 347 ++++++++ .../overlay/traversal_switch_detector.hpp | 291 +++++++ .../algorithms/detail/overlay/traverse.hpp | 819 +----------------- .../algorithms/detail/overlay/turn_info.hpp | 16 +- .../algorithms/detail/overlay/visit_info.hpp | 5 + .../algorithms/detail/point_on_border.hpp | 4 +- .../algorithms/detail/recalculate.hpp | 4 +- .../algorithms/detail/relate/interface.hpp | 4 +- .../algorithms/detail/relation/interface.hpp | 4 +- .../algorithms/detail/ring_identifier.hpp | 5 + .../detail/sections/range_by_section.hpp | 2 +- .../detail/sections/sectionalize.hpp | 2 +- .../detail/within/point_in_geometry.hpp | 2 +- .../boost/geometry/algorithms/difference.hpp | 18 +- include/boost/geometry/algorithms/equals.hpp | 2 +- .../boost/geometry/algorithms/for_each.hpp | 4 +- .../boost/geometry/algorithms/intersects.hpp | 6 +- .../boost/geometry/algorithms/is_empty.hpp | 2 +- include/boost/geometry/algorithms/length.hpp | 4 +- include/boost/geometry/algorithms/make.hpp | 12 +- .../geometry/algorithms/num_geometries.hpp | 2 +- .../algorithms/num_interior_rings.hpp | 2 +- .../boost/geometry/algorithms/num_points.hpp | 2 +- .../geometry/algorithms/num_segments.hpp | 2 +- .../boost/geometry/algorithms/overlaps.hpp | 4 +- .../boost/geometry/algorithms/perimeter.hpp | 2 +- .../geometry/algorithms/point_on_surface.hpp | 4 +- .../geometry/algorithms/remove_spikes.hpp | 2 +- include/boost/geometry/algorithms/reverse.hpp | 2 +- .../boost/geometry/algorithms/simplify.hpp | 14 +- .../geometry/algorithms/sym_difference.hpp | 18 +- include/boost/geometry/algorithms/touches.hpp | 6 +- .../boost/geometry/algorithms/transform.hpp | 4 +- include/boost/geometry/algorithms/union.hpp | 12 +- include/boost/geometry/algorithms/unique.hpp | 2 +- include/boost/geometry/algorithms/within.hpp | 6 +- .../boost/geometry/arithmetic/arithmetic.hpp | 30 +- .../geometry/arithmetic/cross_product.hpp | 10 +- .../boost/geometry/arithmetic/determinant.hpp | 4 +- .../boost/geometry/arithmetic/dot_product.hpp | 4 +- .../extensions/algebra/algorithms/assign.hpp | 2 +- .../algebra/algorithms/rotation.hpp | 4 +- .../algorithms/transform_geometrically.hpp | 12 +- .../algebra/algorithms/translation.hpp | 4 +- .../algebra/geometries/concepts/check.hpp | 12 +- .../geometries/concepts/matrix_concept.hpp | 4 +- .../concepts/quaternion_concept.hpp | 4 +- .../concepts/rotation_matrix_concept.hpp | 4 +- .../concepts/rotation_quaternion_concept.hpp | 4 +- .../geometries/concepts/vector_concept.hpp | 4 +- .../extensions/algebra/geometries/matrix.hpp | 2 +- .../algebra/geometries/quaternion.hpp | 2 +- .../algebra/geometries/rotation_matrix.hpp | 2 +- .../geometries/rotation_quaternion.hpp | 2 +- .../extensions/algebra/geometries/vector.hpp | 2 +- .../extensions/algorithms/connect.hpp | 8 +- .../algorithms/detail/overlay/dissolver.hpp | 4 +- .../algorithms/detail/overlay/split_rings.hpp | 4 +- .../extensions/algorithms/dissolve.hpp | 114 ++- .../extensions/algorithms/distance_info.hpp | 6 +- .../extensions/algorithms/midpoints.hpp | 2 +- .../geometry/extensions/algorithms/offset.hpp | 4 +- .../geometry/extensions/algorithms/parse.hpp | 6 +- .../extensions/algorithms/remove_holes_if.hpp | 2 +- .../extensions/algorithms/remove_marked.hpp | 2 +- .../extensions/algorithms/selected.hpp | 4 +- .../gis/io/veshape/write_veshape.hpp | 6 +- .../nsphere/geometries/concepts/check.hpp | 4 +- .../geometries/concepts/nsphere_concept.hpp | 6 +- .../extensions/nsphere/geometries/nsphere.hpp | 2 +- .../geometry/formulas/andoyer_inverse.hpp | 20 +- .../formulas/differential_quantities.hpp | 254 ++++-- .../formulas/gnomonic_intersection.hpp | 148 ++++ .../geometry/formulas/gnomonic_spheroid.hpp | 14 +- .../formulas/sjoberg_intersection.hpp | 385 ++++++++ .../boost/geometry/formulas/thomas_direct.hpp | 117 ++- .../geometry/formulas/thomas_inverse.hpp | 12 +- .../geometry/formulas/vincenty_direct.hpp | 5 +- .../geometry/formulas/vincenty_inverse.hpp | 5 +- include/boost/geometry/geometries/box.hpp | 2 +- .../geometries/concepts/box_concept.hpp | 4 +- .../geometry/geometries/concepts/check.hpp | 40 +- .../concepts/linestring_concept.hpp | 8 +- .../concepts/multi_linestring_concept.hpp | 8 +- .../concepts/multi_point_concept.hpp | 8 +- .../concepts/multi_polygon_concept.hpp | 8 +- .../geometries/concepts/point_concept.hpp | 4 +- .../geometries/concepts/polygon_concept.hpp | 12 +- .../geometries/concepts/ring_concept.hpp | 8 +- .../geometries/concepts/segment_concept.hpp | 8 +- .../boost/geometry/geometries/linestring.hpp | 2 +- .../geometry/geometries/multi_linestring.hpp | 2 +- .../boost/geometry/geometries/multi_point.hpp | 2 +- .../geometry/geometries/multi_polygon.hpp | 2 +- .../geometry/geometries/pointing_segment.hpp | 4 +- include/boost/geometry/geometries/polygon.hpp | 2 +- include/boost/geometry/geometries/ring.hpp | 2 +- include/boost/geometry/geometries/segment.hpp | 6 +- .../index/detail/algorithms/bounds.hpp | 2 +- include/boost/geometry/io/dsv/write.hpp | 2 +- include/boost/geometry/io/io.hpp | 2 +- include/boost/geometry/io/svg/svg_mapper.hpp | 122 +-- include/boost/geometry/io/svg/write.hpp | 29 +- include/boost/geometry/io/wkt/read.hpp | 2 +- include/boost/geometry/io/wkt/write.hpp | 2 +- .../strategies/cartesian/cart_intersect.hpp | 4 +- .../cartesian/distance_pythagoras.hpp | 4 +- .../cartesian/distance_pythagoras_box_box.hpp | 4 +- .../distance_pythagoras_point_box.hpp | 4 +- .../strategies/concepts/area_concept.hpp | 4 +- .../strategies/concepts/centroid_concept.hpp | 4 +- .../concepts/convex_hull_concept.hpp | 4 +- .../strategies/concepts/distance_concept.hpp | 4 +- .../concepts/segment_intersect_concept.hpp | 4 +- .../strategies/concepts/simplify_concept.hpp | 6 +- .../strategies/concepts/within_concept.hpp | 18 +- .../spherical/distance_cross_track.hpp | 4 +- .../distance_cross_track_point_box.hpp | 2 +- .../strategies/spherical/intersection.hpp | 4 +- .../geometry/util/for_each_coordinate.hpp | 4 +- test/Jamfile.v2 | 1 + test/algorithms/buffer/buffer_linestring.cpp | 4 +- .../buffer/buffer_multi_polygon.cpp | 9 +- test/algorithms/buffer/buffer_polygon.cpp | 2 +- test/algorithms/distance/distance.cpp | 2 +- test/algorithms/overlay/handle_touch.cpp | 516 ----------- .../overlay/multi_overlay_cases.hpp | 202 ++++- test/algorithms/overlay/overlay.cpp | 5 +- test/algorithms/overlay/overlay_cases.hpp | 12 +- test/algorithms/overlay/traverse_multi.cpp | 7 +- .../set_operations/difference/difference.cpp | 206 +++-- .../difference/difference_multi.cpp | 115 +-- .../difference/difference_multi_spike.cpp | 9 +- .../difference/test_difference.hpp | 3 +- .../intersection/intersection.cpp | 65 +- .../intersection/intersection_multi.cpp | 58 +- .../intersection/test_intersection.hpp | 4 +- .../set_operations/union/test_union.hpp | 21 +- .../algorithms/set_operations/union/union.cpp | 49 +- .../set_operations/union/union_multi.cpp | 150 +++- test/algorithms/test_simplify.hpp | 6 +- test/concepts/function_asserting_a_point.hpp | 4 +- test/concepts/function_requiring_a_point.hpp | 4 +- test/concepts/linestring_concept.cpp | 4 +- test/concepts/point_concept_checker.cpp | 4 +- ...int_geographic_custom_with_wrong_units.cpp | 2 +- .../point_geographic_with_wrong_units.cpp | 2 +- ...oint_spherical_custom_with_wrong_units.cpp | 2 +- .../point_well_formed_non_cartesian.cpp | 20 +- test/formulas/Jamfile.v2 | 16 + test/formulas/direct.cpp | 66 ++ test/formulas/direct_cases.hpp | 452 ++++++++++ test/formulas/intersection.cpp | 87 ++ test/formulas/intersection_cases.hpp | 129 +++ test/formulas/inverse.cpp | 71 ++ test/formulas/inverse_cases.hpp | 480 ++++++++++ test/formulas/test_formula.hpp | 59 ++ test/geometries/adapted.cpp | 6 +- test/geometries/boost_polygon.cpp | 6 +- test/geometries/concepts/check.cpp | 4 +- test/geometries/custom_linestring.cpp | 4 +- test/geometries/segment.cpp | 6 +- test/strategies/andoyer.cpp | 2 +- test/strategies/cross_track.cpp | 2 +- test/strategies/haversine.cpp | 2 +- test/strategies/pythagoras.cpp | 2 +- test/strategies/pythagoras_point_box.cpp | 2 +- test/strategies/test_projected_point.hpp | 6 +- test/strategies/test_within.hpp | 2 +- test/strategies/thomas.cpp | 2 +- test/strategies/vincenty.cpp | 2 +- 216 files changed, 5230 insertions(+), 2690 deletions(-) create mode 100644 include/boost/geometry/algorithms/detail/overlay/cluster_info.hpp delete mode 100644 include/boost/geometry/algorithms/detail/overlay/handle_touch.hpp create mode 100644 include/boost/geometry/algorithms/detail/overlay/traversal.hpp create mode 100644 include/boost/geometry/algorithms/detail/overlay/traversal_ring_creator.hpp create mode 100644 include/boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp create mode 100644 include/boost/geometry/formulas/gnomonic_intersection.hpp create mode 100644 include/boost/geometry/formulas/sjoberg_intersection.hpp delete mode 100644 test/algorithms/overlay/handle_touch.cpp create mode 100644 test/formulas/Jamfile.v2 create mode 100644 test/formulas/direct.cpp create mode 100644 test/formulas/direct_cases.hpp create mode 100644 test/formulas/intersection.cpp create mode 100644 test/formulas/intersection_cases.hpp create mode 100644 test/formulas/inverse.cpp create mode 100644 test/formulas/inverse_cases.hpp create mode 100644 test/formulas/test_formula.hpp diff --git a/doc/doxy/doxygen_input/sourcecode/doxygen_5.cpp b/doc/doxy/doxygen_input/sourcecode/doxygen_5.cpp index 942df9285..02a888b33 100644 --- a/doc/doxy/doxygen_input/sourcecode/doxygen_5.cpp +++ b/doc/doxy/doxygen_input/sourcecode/doxygen_5.cpp @@ -47,7 +47,7 @@ namespace example_legacy_point1 // The first way to check a concept at compile time: checking if the input is parameter // or return type is OK. template - BOOST_CONCEPT_REQUIRES(((boost::geometry::concept::Point

)), (void)) + BOOST_CONCEPT_REQUIRES(((boost::geometry::concepts::Point

)), (void)) test1(P& p) { } @@ -57,7 +57,7 @@ namespace example_legacy_point1 template void test2(P& p) { - BOOST_CONCEPT_ASSERT((boost::geometry::concept::Point

)); + BOOST_CONCEPT_ASSERT((boost::geometry::concepts::Point

)); } @@ -90,7 +90,7 @@ namespace example_legacy_point2 // test it using boost concept requires template - BOOST_CONCEPT_REQUIRES(((boost::geometry::concept::ConstPoint

)), (double)) + BOOST_CONCEPT_REQUIRES(((boost::geometry::concepts::ConstPoint

)), (double)) test3(P& p) { return boost::geometry::get<0>(p); @@ -123,7 +123,7 @@ namespace example_custom_linestring1 void example() { typedef custom_linestring1 L; - BOOST_CONCEPT_ASSERT((boost::geometry::concept::Linestring)); + BOOST_CONCEPT_ASSERT((boost::geometry::concepts::Linestring)); } } diff --git a/doc/quickbook/quickref.xml b/doc/quickbook/quickref.xml index 8179d7a87..3188d3287 100644 --- a/doc/quickbook/quickref.xml +++ b/doc/quickbook/quickref.xml @@ -32,28 +32,28 @@ 0-dimensional - boost::geometry::concept::Point - boost::geometry::concept::ConstPoint + boost::geometry::concepts::Point + boost::geometry::concepts::ConstPoint 1-dimensional - boost::geometry::concept::Segment - boost::geometry::concept::ConstSegment - boost::geometry::concept::Linestring - boost::geometry::concept::ConstLinestring + boost::geometry::concepts::Segment + boost::geometry::concepts::ConstSegment + boost::geometry::concepts::Linestring + boost::geometry::concepts::ConstLinestring 2-dimensional - boost::geometry::concept::Box - boost::geometry::concept::ConstBox - boost::geometry::concept::Ring - boost::geometry::concept::ConstRing - boost::geometry::concept::Polygon - boost::geometry::concept::ConstPolygon + boost::geometry::concepts::Box + boost::geometry::concepts::ConstBox + boost::geometry::concepts::Ring + boost::geometry::concepts::ConstRing + boost::geometry::concepts::Polygon + boost::geometry::concepts::ConstPolygon @@ -61,8 +61,8 @@ Functions - boost::geometry::concept::check - boost::geometry::concept::check_concepts_and_equal_dimensions + boost::geometry::concepts::check + boost::geometry::concepts::check_concepts_and_equal_dimensions @@ -496,18 +496,18 @@ - boost::geometry::concept::AreaStrategy - boost::geometry::concept::CentroidStrategy - boost::geometry::concept::ConvexHullStrategy - boost::geometry::concept::PointDistanceStrategy - boost::geometry::concept::PointSegmentDistanceStrategy + boost::geometry::concepts::AreaStrategy + boost::geometry::concepts::CentroidStrategy + boost::geometry::concepts::ConvexHullStrategy + boost::geometry::concepts::PointDistanceStrategy + boost::geometry::concepts::PointSegmentDistanceStrategy - boost::geometry::concept::SegmentIntersectStrategy - boost::geometry::concept::SimplifyStrategy - boost::geometry::concept::WithinStrategy + boost::geometry::concepts::SegmentIntersectStrategy + boost::geometry::concepts::SimplifyStrategy + boost::geometry::concepts::WithinStrategy diff --git a/doc/release_notes.qbk b/doc/release_notes.qbk index 2981028d8..cd7e52951 100644 --- a/doc/release_notes.qbk +++ b/doc/release_notes.qbk @@ -24,12 +24,16 @@ [*Improvements] +* Union: take care that output is valid (with some exceptions), also with self-tangent polygons or shared edges * SVG: support boost::variant of geometries +* SVG: coordinates are now written as double (by default) to svg +* Rename namespace concept to concepts to avoid conflicts with the newest compilers [*Solved tickets] * [@https://svn.boost.org/trac/boost/ticket/12189 12189] Relational operations not compiling when point types of inputs are different * [@https://svn.boost.org/trac/boost/ticket/12287 12287] Invalid result of rtree.query() for contains() predicate +* [@https://svn.boost.org/trac/boost/ticket/12289 12289] Avoid warning/compilation error for std::cout [/=================] [heading Boost 1.61] diff --git a/extensions/test/algorithms/dissolve.cpp b/extensions/test/algorithms/dissolve.cpp index 08cf6b2a4..9a0921b72 100644 --- a/extensions/test/algorithms/dissolve.cpp +++ b/extensions/test/algorithms/dissolve.cpp @@ -209,21 +209,23 @@ void test_all() "POLYGON((1 2,1 1,2 1,2 2.25,3 2.25,3 0,0 0,0 3,3 3,2.75 2,1 2))", 1, 12, 7.9296875); +#ifdef BOOST_GEOMETRY_TEST_INCLUDE_FAILING_TESTS // Self intersecting in last segment test_one("3", "POLYGON((0 2,2 4,2 0,4 2,0 2))", 0, 8, 4.0); - // Self tangent + // Self tangent - polygons are now included twice test_one("4", "POLYGON((0 0,0 4,4 4,4 0,2 4,0 0))", 0, 8, 8.0); - // Self tangent in corner + // Self tangent in corner - polygons are now included twice test_one("5", "POLYGON((0 0,0 4,4 4,4 0,0 4,2 0,0 0))", 0, 8, 12.0); +#endif // With spike @@ -273,6 +275,9 @@ void test_all() "POLYGON((5 0,2.5 9,9.5 3.5,0.5 3.5,7.5 9,5 0))", 0, 11, 25.6158412); +#ifdef BOOST_GEOMETRY_TEST_INCLUDE_FAILING_TESTS + // Poygons contain too many polygons + // CCW polygons should turn CW after dissolve test_one("cw", "POLYGON((2 8,8 8,8 0,0 0,0 6,4 6,4 4,2 4,2 8))", @@ -284,6 +289,7 @@ void test_all() test_one("ticket_10713", "POLYGON((-0.7189743518829346 4.1308121681213379, 0.0831791982054710 4.1034231185913086, 0.1004156470298767 4.1107301712036133, 0.1044322624802589 4.1026973724365234, 0.0831791982054710 4.1034231185913086, -0.7711903452873230 3.7412264347076416, -0.7189743518829346 4.1308121681213379))", 0, 8, 0.157052766); +#endif // Multi-geometries @@ -347,7 +353,6 @@ void test_all() test_one("ticket17", ticket17, 1, 228, 0.00920834633689); - return; // next one does not work for gcc/linux // Real-life std::string const toolkit = "POLYGON((170718 605997,170718 605997,170776 606016,170773 606015,170786 606020,170778 606016,170787 606021,170781 606017,170795 606028,170795 606028,170829 606055,170939 606140,170933 605968,170933 605968,170932 605908,170929 605834,170920 605866,170961 605803,170739 605684,170699 605749,170691 605766,170693 605762,170686 605775,170688 605771,170673 605794,170676 605790,170668 605800,170672 605796,170651 605818,170653 605816,170639 605829,170568 605899,170662 605943,170633 605875,170603 605961,170718 605997))"; test_one("toolkit", toolkit, diff --git a/include/boost/geometry/algorithms/append.hpp b/include/boost/geometry/algorithms/append.hpp index 894f52c68..5cfad0c52 100644 --- a/include/boost/geometry/algorithms/append.hpp +++ b/include/boost/geometry/algorithms/append.hpp @@ -284,7 +284,7 @@ struct append int ring_index, int multi_index) { - concept::check(); + concepts::check(); dispatch::append::apply(geometry, range_or_point, ring_index, diff --git a/include/boost/geometry/algorithms/area.hpp b/include/boost/geometry/algorithms/area.hpp index 1d68b2c37..4751d4e74 100644 --- a/include/boost/geometry/algorithms/area.hpp +++ b/include/boost/geometry/algorithms/area.hpp @@ -82,7 +82,7 @@ struct ring_area static inline typename Strategy::return_type apply(Ring const& ring, Strategy const& strategy) { - BOOST_CONCEPT_ASSERT( (geometry::concept::AreaStrategy) ); + BOOST_CONCEPT_ASSERT( (geometry::concepts::AreaStrategy) ); assert_dimension(); // Ignore warning (because using static method sometimes) on strategy @@ -266,7 +266,7 @@ and Geographic as well. template inline typename default_area_result::type area(Geometry const& geometry) { - concept::check(); + concepts::check(); // TODO put this into a resolve_strategy stage // (and take the return type from resolve_variant) @@ -310,7 +310,7 @@ template inline typename Strategy::return_type area( Geometry const& geometry, Strategy const& strategy) { - concept::check(); + concepts::check(); // detail::throw_on_empty_input(geometry); @@ -320,4 +320,5 @@ inline typename Strategy::return_type area( }} // namespace boost::geometry + #endif // BOOST_GEOMETRY_ALGORITHMS_AREA_HPP diff --git a/include/boost/geometry/algorithms/assign.hpp b/include/boost/geometry/algorithms/assign.hpp index e3d664de3..589a5c545 100644 --- a/include/boost/geometry/algorithms/assign.hpp +++ b/include/boost/geometry/algorithms/assign.hpp @@ -69,7 +69,7 @@ namespace boost { namespace geometry template inline void assign_points(Geometry& geometry, Range const& range) { - concept::check(); + concepts::check(); clear(geometry); geometry::append(geometry, range, -1, 0); @@ -96,7 +96,7 @@ collect the minimum bounding box of a geometry. template inline void assign_inverse(Geometry& geometry) { - concept::check(); + concepts::check(); dispatch::assign_inverse < @@ -116,7 +116,7 @@ inline void assign_inverse(Geometry& geometry) template inline void assign_zero(Geometry& geometry) { - concept::check(); + concepts::check(); dispatch::assign_zero < @@ -146,7 +146,7 @@ inline void assign_zero(Geometry& geometry) template inline void assign_values(Geometry& geometry, Type const& c1, Type const& c2) { - concept::check(); + concepts::check(); dispatch::assign < @@ -179,7 +179,7 @@ template inline void assign_values(Geometry& geometry, Type const& c1, Type const& c2, Type const& c3) { - concept::check(); + concepts::check(); dispatch::assign < @@ -206,7 +206,7 @@ template inline void assign_values(Geometry& geometry, Type const& c1, Type const& c2, Type const& c3, Type const& c4) { - concept::check(); + concepts::check(); dispatch::assign < @@ -227,9 +227,9 @@ struct assign static inline void apply(Geometry1& geometry1, const Geometry2& geometry2) { - concept::check(); - concept::check(); - concept::check_concepts_and_equal_dimensions(); + concepts::check(); + concepts::check(); + concepts::check_concepts_and_equal_dimensions(); static bool const same_point_order = point_order::value == point_order::value; diff --git a/include/boost/geometry/algorithms/buffer.hpp b/include/boost/geometry/algorithms/buffer.hpp index 5dfe9d884..e1d3c20e4 100644 --- a/include/boost/geometry/algorithms/buffer.hpp +++ b/include/boost/geometry/algorithms/buffer.hpp @@ -182,8 +182,8 @@ template inline void buffer(Input const& geometry_in, Output& geometry_out, Distance const& distance, Distance const& chord_length = -1) { - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); resolve_variant::buffer::apply(geometry_in, distance, chord_length, geometry_out); } @@ -204,8 +204,8 @@ inline void buffer(Input const& geometry_in, Output& geometry_out, template Output return_buffer(Input const& geometry, Distance const& distance, Distance const& chord_length = -1) { - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); Output geometry_out; @@ -256,8 +256,8 @@ inline void buffer(GeometryIn const& geometry_in, PointStrategy const& point_strategy) { typedef typename boost::range_value::type polygon_type; - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); typedef typename point_type::type point_type; typedef typename rescale_policy_type::type rescale_policy_type; diff --git a/include/boost/geometry/algorithms/centroid.hpp b/include/boost/geometry/algorithms/centroid.hpp index 8ef017a3f..fc2908ab1 100644 --- a/include/boost/geometry/algorithms/centroid.hpp +++ b/include/boost/geometry/algorithms/centroid.hpp @@ -545,7 +545,7 @@ struct centroid template static inline void apply(Geometry const& geometry, Point& out, Strategy const& strategy) { - concept::check_concepts_and_equal_dimensions(); + concepts::check_concepts_and_equal_dimensions(); resolve_strategy::centroid::apply(geometry, out, strategy); } }; diff --git a/include/boost/geometry/algorithms/clear.hpp b/include/boost/geometry/algorithms/clear.hpp index 54b216276..97f5efa45 100644 --- a/include/boost/geometry/algorithms/clear.hpp +++ b/include/boost/geometry/algorithms/clear.hpp @@ -185,7 +185,7 @@ struct clear > template inline void clear(Geometry& geometry) { - concept::check(); + concepts::check(); resolve_variant::clear::apply(geometry); } diff --git a/include/boost/geometry/algorithms/convert.hpp b/include/boost/geometry/algorithms/convert.hpp index 78618aed2..6a8ba1acb 100644 --- a/include/boost/geometry/algorithms/convert.hpp +++ b/include/boost/geometry/algorithms/convert.hpp @@ -494,7 +494,7 @@ struct convert { static inline void apply(Geometry1 const& geometry1, Geometry2& geometry2) { - concept::check_concepts_and_equal_dimensions(); + concepts::check_concepts_and_equal_dimensions(); dispatch::convert::apply(geometry1, geometry2); } }; diff --git a/include/boost/geometry/algorithms/convex_hull.hpp b/include/boost/geometry/algorithms/convex_hull.hpp index 19d28bc7b..26bb8509e 100644 --- a/include/boost/geometry/algorithms/convex_hull.hpp +++ b/include/boost/geometry/algorithms/convex_hull.hpp @@ -154,7 +154,7 @@ struct convex_hull OutputGeometry& out, Strategy const& strategy) { - BOOST_CONCEPT_ASSERT( (geometry::concept::ConvexHullStrategy) ); + BOOST_CONCEPT_ASSERT( (geometry::concepts::ConvexHullStrategy) ); dispatch::convex_hull::apply(geometry, out, strategy); } @@ -179,7 +179,7 @@ struct convex_hull_insert OutputIterator& out, Strategy const& strategy) { - BOOST_CONCEPT_ASSERT( (geometry::concept::ConvexHullStrategy) ); + BOOST_CONCEPT_ASSERT( (geometry::concepts::ConvexHullStrategy) ); return dispatch::convex_hull_insert< geometry::point_order::value, @@ -212,7 +212,7 @@ struct convex_hull template static inline void apply(Geometry const& geometry, OutputGeometry& out, Strategy const& strategy) { - concept::check_concepts_and_equal_dimensions< + concepts::check_concepts_and_equal_dimensions< const Geometry, OutputGeometry >(); @@ -258,8 +258,8 @@ struct convex_hull_insert static inline OutputIterator apply(Geometry const& geometry, OutputIterator& out, Strategy const& strategy) { // Concept: output point type = point type of input geometry - concept::check(); - concept::check::type>(); + concepts::check(); + concepts::check::type>(); return resolve_strategy::convex_hull_insert::apply(geometry, out, strategy); } diff --git a/include/boost/geometry/algorithms/correct.hpp b/include/boost/geometry/algorithms/correct.hpp index 11ed6ecff..5d3b6939a 100644 --- a/include/boost/geometry/algorithms/correct.hpp +++ b/include/boost/geometry/algorithms/correct.hpp @@ -283,7 +283,7 @@ struct correct { static inline void apply(Geometry& geometry) { - concept::check(); + concepts::check(); dispatch::correct::apply(geometry); } }; diff --git a/include/boost/geometry/algorithms/covered_by.hpp b/include/boost/geometry/algorithms/covered_by.hpp index eb8e73240..2001d5810 100644 --- a/include/boost/geometry/algorithms/covered_by.hpp +++ b/include/boost/geometry/algorithms/covered_by.hpp @@ -260,15 +260,15 @@ struct covered_by Geometry2 const& geometry2, Strategy const& strategy) { - concept::within::check + concepts::within::check < typename tag::type, typename tag::type, typename tag_cast::type, areal_tag>::type, Strategy >(); - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); assert_dimension_equal(); return dispatch::covered_by::apply(geometry1, diff --git a/include/boost/geometry/algorithms/crosses.hpp b/include/boost/geometry/algorithms/crosses.hpp index 9546a5335..73d86ef52 100644 --- a/include/boost/geometry/algorithms/crosses.hpp +++ b/include/boost/geometry/algorithms/crosses.hpp @@ -72,8 +72,8 @@ namespace resolve_variant const Geometry1& geometry1, const Geometry2& geometry2) { - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); return dispatch::crosses::apply(geometry1, geometry2); } diff --git a/include/boost/geometry/algorithms/detail/assign_box_corners.hpp b/include/boost/geometry/algorithms/detail/assign_box_corners.hpp index 669d6d365..bd8b84afc 100644 --- a/include/boost/geometry/algorithms/detail/assign_box_corners.hpp +++ b/include/boost/geometry/algorithms/detail/assign_box_corners.hpp @@ -54,8 +54,8 @@ inline void assign_box_corners(Box const& box, Point& lower_left, Point& lower_right, Point& upper_left, Point& upper_right) { - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); detail::assign::assign_box_2d_corner (box, lower_left); diff --git a/include/boost/geometry/algorithms/detail/assign_indexed_point.hpp b/include/boost/geometry/algorithms/detail/assign_indexed_point.hpp index acfc37e25..e5d9358c1 100644 --- a/include/boost/geometry/algorithms/detail/assign_indexed_point.hpp +++ b/include/boost/geometry/algorithms/detail/assign_indexed_point.hpp @@ -46,8 +46,8 @@ namespace detail template inline void assign_point_to_index(Point const& point, Geometry& geometry) { - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); detail::assign::assign_point_to_index < @@ -74,8 +74,8 @@ inline void assign_point_to_index(Point const& point, Geometry& geometry) template inline void assign_point_from_index(Geometry const& geometry, Point& point) { - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); detail::assign::assign_point_from_index < 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 3fc3c2347..e7214428e 100644 --- a/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp @@ -35,6 +35,7 @@ #include #include +#include #include #include #include @@ -297,7 +298,7 @@ struct buffered_piece_collection typedef std::map < signed_size_type, - std::set + detail::overlay::cluster_info > cluster_type; cluster_type m_clusters; @@ -1216,9 +1217,8 @@ struct buffered_piece_collection typename cs_tag::type >::type side_strategy_type; - enrich_intersection_points(m_turns, - m_clusters, detail::overlay::operation_union, - offsetted_rings, offsetted_rings, + enrich_intersection_points(m_turns, + m_clusters, offsetted_rings, offsetted_rings, m_robust_policy, side_strategy_type()); } @@ -1330,17 +1330,12 @@ struct buffered_piece_collection for (typename boost::range_iterator::type it = boost::begin(m_turns); it != boost::end(m_turns); ++it) { - if (it->location != location_ok) + buffer_turn_info_type& turn = *it; + if (turn.location != location_ok) { - // Set it to blocked. They should not be discarded, to avoid - // generating rings over these turns - // Performance goes down a tiny bit from 161 s to 173 because there - // are sometimes much more turns. - // We might speed it up a bit by keeping only one blocked - // intersection per segment, but that is complex to program - // because each turn involves two segments - it->operations[0].operation = detail::overlay::operation_blocked; - it->operations[1].operation = detail::overlay::operation_blocked; + // Discard this turn (don't set it to blocked to avoid colocated + // clusters being discarded afterwards + turn.discarded = true; } } } @@ -1352,7 +1347,7 @@ struct buffered_piece_collection false, false, buffered_ring_collection >, buffered_ring_collection >, - detail::overlay::operation_union, + overlay_buffer, backtrack_for_buffer > traverser; diff --git a/include/boost/geometry/algorithms/detail/buffer/buffered_ring.hpp b/include/boost/geometry/algorithms/detail/buffer/buffered_ring.hpp index db6136e1a..4fd24b145 100644 --- a/include/boost/geometry/algorithms/detail/buffer/buffered_ring.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/buffered_ring.hpp @@ -16,6 +16,8 @@ #include #include +#include +#include #include #include @@ -147,6 +149,20 @@ struct ring_type typedef Ring type; }; + +// There is a specific tag, so this specialization cannot be placed in traits +template +struct point_order + > > +{ + static const order_selector value + = core_dispatch::point_order::value; +}; + + } diff --git a/include/boost/geometry/algorithms/detail/comparable_distance/interface.hpp b/include/boost/geometry/algorithms/detail/comparable_distance/interface.hpp index 86eec4c03..3e48a05ba 100644 --- a/include/boost/geometry/algorithms/detail/comparable_distance/interface.hpp +++ b/include/boost/geometry/algorithms/detail/comparable_distance/interface.hpp @@ -318,8 +318,8 @@ inline typename comparable_distance_result::type comparable_distance(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); return resolve_variant::comparable_distance < @@ -350,8 +350,8 @@ template inline typename default_comparable_distance_result::type comparable_distance(Geometry1 const& geometry1, Geometry2 const& geometry2) { - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); return geometry::comparable_distance(geometry1, geometry2, default_strategy()); } diff --git a/include/boost/geometry/algorithms/detail/disjoint/interface.hpp b/include/boost/geometry/algorithms/detail/disjoint/interface.hpp index 18c010731..ce7fe6d45 100644 --- a/include/boost/geometry/algorithms/detail/disjoint/interface.hpp +++ b/include/boost/geometry/algorithms/detail/disjoint/interface.hpp @@ -73,7 +73,7 @@ struct disjoint { static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2) { - concept::check_concepts_and_equal_dimensions + concepts::check_concepts_and_equal_dimensions < Geometry1 const, Geometry2 const diff --git a/include/boost/geometry/algorithms/detail/distance/interface.hpp b/include/boost/geometry/algorithms/detail/distance/interface.hpp index 1e7cc433e..53d24d992 100644 --- a/include/boost/geometry/algorithms/detail/distance/interface.hpp +++ b/include/boost/geometry/algorithms/detail/distance/interface.hpp @@ -361,8 +361,8 @@ distance(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); detail::throw_on_empty_input(geometry1); detail::throw_on_empty_input(geometry2); @@ -392,8 +392,8 @@ inline typename default_distance_result::type distance(Geometry1 const& geometry1, Geometry2 const& geometry2) { - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); return geometry::distance(geometry1, geometry2, default_strategy()); } diff --git a/include/boost/geometry/algorithms/detail/envelope/interface.hpp b/include/boost/geometry/algorithms/detail/envelope/interface.hpp index 997ac1b23..befe4e42d 100644 --- a/include/boost/geometry/algorithms/detail/envelope/interface.hpp +++ b/include/boost/geometry/algorithms/detail/envelope/interface.hpp @@ -40,8 +40,8 @@ struct envelope template static inline void apply(Geometry const& geometry, Box& box) { - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); dispatch::envelope::apply(geometry, box); } diff --git a/include/boost/geometry/algorithms/detail/equals/collect_vectors.hpp b/include/boost/geometry/algorithms/detail/equals/collect_vectors.hpp index 2f9132146..eab73ea68 100644 --- a/include/boost/geometry/algorithms/detail/equals/collect_vectors.hpp +++ b/include/boost/geometry/algorithms/detail/equals/collect_vectors.hpp @@ -521,7 +521,7 @@ struct collect_vectors template inline void collect_vectors(Collection& collection, Geometry const& geometry) { - concept::check(); + concepts::check(); dispatch::collect_vectors < diff --git a/include/boost/geometry/algorithms/detail/expand/interface.hpp b/include/boost/geometry/algorithms/detail/expand/interface.hpp index 01936387a..140754af4 100644 --- a/include/boost/geometry/algorithms/detail/expand/interface.hpp +++ b/include/boost/geometry/algorithms/detail/expand/interface.hpp @@ -42,9 +42,9 @@ struct expand template static inline void apply(Box& box, Geometry const& geometry) { - concept::check(); - concept::check(); - concept::check_concepts_and_equal_dimensions(); + concepts::check(); + concepts::check(); + concepts::check_concepts_and_equal_dimensions(); dispatch::expand::apply(box, geometry); } @@ -100,7 +100,7 @@ inline void expand(Box& box, Geometry const& geometry, StrategyLess const& strategy_less, StrategyGreater const& strategy_greater) { - concept::check_concepts_and_equal_dimensions(); + concepts::check_concepts_and_equal_dimensions(); dispatch::expand::apply(box, geometry); } diff --git a/include/boost/geometry/algorithms/detail/extreme_points.hpp b/include/boost/geometry/algorithms/detail/extreme_points.hpp index 61839d296..65795cd05 100644 --- a/include/boost/geometry/algorithms/detail/extreme_points.hpp +++ b/include/boost/geometry/algorithms/detail/extreme_points.hpp @@ -492,15 +492,15 @@ struct extreme_points template inline bool extreme_points(Geometry const& geometry, Extremes& extremes, Intruders& intruders) { - concept::check(); + concepts::check(); // Extremes is not required to follow a geometry concept (but it should support an output iterator), // but its elements should fulfil the point-concept - concept::check::type>(); + concepts::check::type>(); // Intruders should contain collections which value type is point-concept // Extremes might be anything (supporting an output iterator), but its elements should fulfil the point-concept - concept::check + concepts::check < typename boost::range_value < diff --git a/include/boost/geometry/algorithms/detail/intersection/interface.hpp b/include/boost/geometry/algorithms/detail/intersection/interface.hpp index 56b859b85..e0955de3d 100644 --- a/include/boost/geometry/algorithms/detail/intersection/interface.hpp +++ b/include/boost/geometry/algorithms/detail/intersection/interface.hpp @@ -110,8 +110,8 @@ struct intersection const Geometry2& geometry2, GeometryOut& geometry_out) { - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); typedef typename geometry::rescale_overlay_policy_type < diff --git a/include/boost/geometry/algorithms/detail/is_simple/interface.hpp b/include/boost/geometry/algorithms/detail/is_simple/interface.hpp index fd8482697..6d425232b 100644 --- a/include/boost/geometry/algorithms/detail/is_simple/interface.hpp +++ b/include/boost/geometry/algorithms/detail/is_simple/interface.hpp @@ -30,7 +30,7 @@ struct is_simple { static inline bool apply(Geometry const& geometry) { - concept::check(); + concepts::check(); return dispatch::is_simple::apply(geometry); } }; diff --git a/include/boost/geometry/algorithms/detail/is_valid/interface.hpp b/include/boost/geometry/algorithms/detail/is_valid/interface.hpp index 0ec13b1b3..5a04a9282 100644 --- a/include/boost/geometry/algorithms/detail/is_valid/interface.hpp +++ b/include/boost/geometry/algorithms/detail/is_valid/interface.hpp @@ -37,7 +37,7 @@ struct is_valid template static inline bool apply(Geometry const& geometry, VisitPolicy& visitor) { - concept::check(); + concepts::check(); return dispatch::is_valid::apply(geometry, visitor); } }; diff --git a/include/boost/geometry/algorithms/detail/overlay/cluster_info.hpp b/include/boost/geometry/algorithms/detail/overlay/cluster_info.hpp new file mode 100644 index 000000000..5b460919f --- /dev/null +++ b/include/boost/geometry/algorithms/detail/overlay/cluster_info.hpp @@ -0,0 +1,49 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2016 Barend Gehrels, 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_OVERLAY_CLUSTER_INFO_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CLUSTER_INFO_HPP + + +#include +#include + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace overlay +{ + + +struct cluster_info +{ + std::set turn_indices; + + bool switch_source; // For clusters with a touch, conform turn_info uu + + //! Number of open spaces (e.g. 2 for touch) + std::size_t open_count; + + inline cluster_info() + : switch_source(false) + , open_count(0) + {} +}; + + +}} // namespace detail::overlay +#endif //DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CLUSTER_INFO_HPP + diff --git a/include/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp b/include/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp index 790819917..795523d7a 100644 --- a/include/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp @@ -284,7 +284,7 @@ inline bool copy_segment_point(Geometry const& geometry, SegmentIdentifier const& seg_id, int offset, PointOut& point_out) { - concept::check(); + concepts::check(); return dispatch::copy_segment_point < @@ -313,8 +313,8 @@ inline bool copy_segment_point(Geometry1 const& geometry1, Geometry2 const& geom SegmentIdentifier const& seg_id, int offset, PointOut& point_out) { - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); BOOST_GEOMETRY_ASSERT(seg_id.source_index == 0 || seg_id.source_index == 1); @@ -361,8 +361,8 @@ inline bool copy_segment_points(Geometry1 const& geometry1, Geometry2 const& geo SegmentIdentifier const& seg_id, PointOut& point1, PointOut& point2) { - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); return copy_segment_point(geometry1, geometry2, seg_id, 0, point1) && copy_segment_point(geometry1, geometry2, seg_id, 1, point2); @@ -384,8 +384,8 @@ inline bool copy_segment_points(Geometry1 const& geometry1, Geometry2 const& geo SegmentIdentifier const& seg_id, PointOut& point1, PointOut& point2, PointOut& point3) { - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); return copy_segment_point(geometry1, geometry2, seg_id, 0, point1) && copy_segment_point(geometry1, geometry2, seg_id, 1, point2) diff --git a/include/boost/geometry/algorithms/detail/overlay/copy_segments.hpp b/include/boost/geometry/algorithms/detail/overlay/copy_segments.hpp index 2eefa03c6..fe1a034f8 100644 --- a/include/boost/geometry/algorithms/detail/overlay/copy_segments.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/copy_segments.hpp @@ -349,7 +349,7 @@ inline void copy_segments(Geometry const& geometry, RobustPolicy const& robust_policy, RangeOut& range_out) { - concept::check(); + concepts::check(); dispatch::copy_segments < diff --git a/include/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp b/include/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp index bc5d3b91e..5cab2b4cb 100644 --- a/include/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp @@ -159,6 +159,7 @@ inline void enrich_assign(Operations& operations, Turns& turns) << " nxt=" << op.enriched.next_ip_index << " / " << op.enriched.travels_to_ip_index << " [vx " << op.enriched.travels_to_vertex_index << "]" + << std::boolalpha << turns[it->turn_index].discarded << std::endl; ; } @@ -235,11 +236,12 @@ inline void create_map(Turns const& turns, \ingroup overlay \tparam Turns type of intersection container (e.g. vector of "intersection/turn point"'s) +\tparam Clusters type of cluster container \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \tparam Strategy side strategy type -\param turns container containing intersectionpoints -\param for_operation operation_type (union or intersection) +\param turns container containing intersection points +\param clusters container containing clusters \param geometry1 \param_geometry \param geometry2 \param_geometry \param robust_policy policy to handle robustness issues @@ -257,11 +259,12 @@ template > inline void enrich_intersection_points(Turns& turns, Clusters& clusters, - detail::overlay::operation_type for_operation, Geometry1 const& geometry1, Geometry2 const& geometry2, RobustPolicy const& robust_policy, Strategy const& strategy) { + static const detail::overlay::operation_type for_operation + = detail::overlay::operation_from_overlay::value; typedef typename boost::range_value::type turn_type; typedef typename turn_type::turn_operation_type op_type; typedef detail::overlay::indexed_turn_operation @@ -328,7 +331,7 @@ inline void enrich_intersection_points(Turns& turns, if (has_colocations) { - detail::overlay::assign_startable_in_clusters( + detail::overlay::gather_cluster_properties( clusters, turns, for_operation, geometry1, geometry2); } diff --git a/include/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp b/include/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp index f5c5cc6a2..cc5541487 100644 --- a/include/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp @@ -9,6 +9,8 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ENRICHMENT_INFO_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ENRICHMENT_INFO_HPP +#include + namespace boost { namespace geometry { @@ -25,7 +27,7 @@ namespace detail { namespace overlay of the overlay process). The information is gathered during the enrichment phase */ -template +template struct enrichment_info { inline enrichment_info() @@ -35,6 +37,7 @@ struct enrichment_info , startable(true) , count_left(0) , count_right(0) + , zone(-1) {} // vertex to which is free travel after this IP, @@ -53,6 +56,7 @@ struct enrichment_info // Counts if polygons left/right of this operation std::size_t count_left; std::size_t count_right; + signed_size_type zone; // open zone, in cluster }; diff --git a/include/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp b/include/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp index 4d5211919..99281eaec 100644 --- a/include/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp @@ -109,7 +109,7 @@ inline void get_intersection_points(Geometry1 const& geometry1, RobustPolicy const& robust_policy, Turns& turns) { - concept::check_concepts_and_equal_dimensions(); + concepts::check_concepts_and_equal_dimensions(); typedef detail::get_intersection_points::get_turn_without_info < diff --git a/include/boost/geometry/algorithms/detail/overlay/get_turns.hpp b/include/boost/geometry/algorithms/detail/overlay/get_turns.hpp index 23cf77125..1eb18b74d 100644 --- a/include/boost/geometry/algorithms/detail/overlay/get_turns.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/get_turns.hpp @@ -972,7 +972,7 @@ inline void get_turns(Geometry1 const& geometry1, Turns& turns, InterruptPolicy& interrupt_policy) { - concept::check_concepts_and_equal_dimensions(); + concepts::check_concepts_and_equal_dimensions(); typedef detail::overlay::get_turn_info TurnPolicy; //typedef detail::get_turns::get_turn_info_type TurnPolicy; diff --git a/include/boost/geometry/algorithms/detail/overlay/handle_colocations.hpp b/include/boost/geometry/algorithms/detail/overlay/handle_colocations.hpp index 1028f9870..b21733912 100644 --- a/include/boost/geometry/algorithms/detail/overlay/handle_colocations.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/handle_colocations.hpp @@ -15,6 +15,9 @@ #include #include +#include +#include +#include #include #include #include @@ -195,13 +198,14 @@ inline signed_size_type add_turn_to_cluster(Turn const& turn, // Both operations.seg_id/fraction were already part of any cluster, and // these clusters are not the same. Merge of two clusters is necessary +#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_COLOCATIONS) std::cout << " TODO: merge " << cid0 << " and " << cid1 << std::endl; +#endif return cid0; } template < - bool Reverse1, bool Reverse2, typename Turns, typename ClusterPerSegment, typename Operations, @@ -312,13 +316,15 @@ inline void assign_cluster_to_turns(Turns& turns, typename ClusterPerSegment::const_iterator it = cluster_per_segment.find(seg_frac); if (it != cluster_per_segment.end()) { +#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_COLOCATIONS) if (turn.cluster_id != -1 && turn.cluster_id != it->second) { std::cout << " CONFLICT " << std::endl; } +#endif turn.cluster_id = it->second; - clusters[turn.cluster_id].insert(turn_index); + clusters[turn.cluster_id].turn_indices.insert(turn_index); } } } @@ -339,7 +345,8 @@ inline void remove_clusters(Turns& turns, Clusters& clusters) typename Clusters::iterator current_it = it; ++it; - std::set const& turn_indices = current_it->second; + std::set const& turn_indices + = current_it->second.turn_indices; if (turn_indices.size() == 1) { signed_size_type turn_index = *turn_indices.begin(); @@ -349,6 +356,134 @@ inline void remove_clusters(Turns& turns, Clusters& clusters) } } +template +inline void discard_ie_turn(Turn& turn, IdSet& ids, signed_size_type id) +{ + turn.discarded = true; + turn.cluster_id = -1; + // To remove it later from clusters + ids.insert(id); +} + +template +inline bool is_interior(segment_identifier const& seg_id) +{ + return Reverse ? seg_id.ring_index == -1 : seg_id.ring_index >= 0; +} + +template +inline bool is_ie_turn(segment_identifier const& ext_seg_0, + segment_identifier const& ext_seg_1, + segment_identifier const& int_seg_0, + segment_identifier const& other_seg_1) +{ + // Compares two segment identifiers from two turns (external / one internal) + + // From first turn [0], both are from same polygon (multi_index), + // one is exterior (-1), the other is interior (>= 0), + // and the second turn [1] handles the same ring + + // For difference, where the rings are processed in reversal, all interior + // rings become exterior and vice versa. But also the multi property changes: + // rings originally from the same multi should now be considered as from + // different multi polygons. + // But this is not always the case, and at this point hard to figure out + // (not yet implemented, TODO) + + bool const same_multi0 = ! Reverse0 + && ext_seg_0.multi_index == int_seg_0.multi_index; + + bool const same_multi1 = ! Reverse1 + && ext_seg_1.multi_index == other_seg_1.multi_index; + + return same_multi0 + && same_multi1 + && ! is_interior(ext_seg_0) + && is_interior(int_seg_0) + && ext_seg_1.ring_index == other_seg_1.ring_index; + + // The other way round is tested in another call +} + +template +< + bool Reverse0, bool Reverse1, // Reverse interpretation interior/exterior + typename Turns, + typename Clusters +> +inline void discard_interior_exterior_turns(Turns& turns, Clusters& clusters) +{ + typedef std::set::const_iterator set_iterator; + typedef typename boost::range_value::type turn_type; + + std::set ids_to_remove; + + for (typename Clusters::iterator cit = clusters.begin(); + cit != clusters.end(); ++cit) + { + cluster_info& cinfo = cit->second; + std::set& ids = cinfo.turn_indices; + + ids_to_remove.clear(); + + for (set_iterator it = ids.begin(); it != ids.end(); ++it) + { + turn_type& turn = turns[*it]; + segment_identifier const& seg_0 = turn.operations[0].seg_id; + segment_identifier const& seg_1 = turn.operations[1].seg_id; + + if (turn.both(operation_intersection) + && Reverse0 == Reverse1) + { + if ( is_interior(seg_0) + && is_interior(seg_1)) + { + // ii touch with, two interior rings + discard_ie_turn(turn, ids_to_remove, *it); + } + + continue; + } + + if (! (turn.both(operation_union) + || turn.combination(operation_union, operation_blocked))) + { + // Not a uu/ux, so cannot be colocated with a iu turn + continue; + } + + for (set_iterator int_it = ids.begin(); int_it != ids.end(); ++int_it) + { + if (*it == *int_it) + { + continue; + } + + // Turn with, possibly, an interior ring involved + turn_type& int_turn = turns[*int_it]; + segment_identifier const& int_seg_0 = int_turn.operations[0].seg_id; + segment_identifier const& int_seg_1 = int_turn.operations[1].seg_id; + + if (is_ie_turn(seg_0, seg_1, int_seg_0, int_seg_1)) + { + discard_ie_turn(int_turn, ids_to_remove, *int_it); + } + if (is_ie_turn(seg_1, seg_0, int_seg_1, int_seg_0)) + { + discard_ie_turn(int_turn, ids_to_remove, *int_it); + } + } + } + + // Erase from the ids (which cannot be done above) + for (set_iterator sit = ids_to_remove.begin(); + sit != ids_to_remove.end(); ++sit) + { + ids.erase(*sit); + } + } +} + // Checks colocated turns and flags combinations of uu/other, possibly a // combination of a ring touching another geometry's interior ring which is @@ -434,13 +569,17 @@ inline bool handle_colocations(Turns& turns, Clusters& clusters, { if (it->second.size() > 1u) { - handle_colocation_cluster(turns, cluster_id, - cluster_per_segment, it->second, - geometry1, geometry2); + handle_colocation_cluster(turns, cluster_id, cluster_per_segment, + it->second, geometry1, geometry2); } } assign_cluster_to_turns(turns, clusters, cluster_per_segment); + discard_interior_exterior_turns + < + do_reverse::value>::value != Reverse1, + do_reverse::value>::value != Reverse2 + >(turns, clusters); remove_clusters(turns, clusters); #if defined(BOOST_GEOMETRY_DEBUG_HANDLE_COLOCATIONS) @@ -497,7 +636,7 @@ template typename Geometry1, typename Geometry2 > -inline void assign_startable_in_clusters(Clusters& clusters, Turns& turns, +inline void gather_cluster_properties(Clusters& clusters, Turns& turns, operation_type for_operation, Geometry1 const& geometry1, Geometry2 const& geometry2) { @@ -515,7 +654,8 @@ inline void assign_startable_in_clusters(Clusters& clusters, Turns& turns, for (typename Clusters::iterator mit = clusters.begin(); mit != clusters.end(); ++mit) { - std::set const& ids = mit->second; + cluster_info& cinfo = mit->second; + std::set const& ids = cinfo.turn_indices; if (ids.empty()) { continue; @@ -545,30 +685,32 @@ inline void assign_startable_in_clusters(Clusters& clusters, Turns& turns, sbs.find_open(); - // Unset the startable flag for all 'closed' spaces + // Unset the startable flag for all 'closed' zones for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++) { const typename sbs_type::rp& ranked = sbs.m_ranked_points[i]; turn_type& turn = turns[ranked.turn_index]; - turn_operation_type& op = turn.operations[ranked.op_index]; + turn_operation_type& op = turn.operations[ranked.operation_index]; - if (ranked.index != sort_by_side::index_to) + if (ranked.direction != sort_by_side::dir_to) { continue; } - op.enriched.count_left = ranked.left_count; - op.enriched.count_right = ranked.right_count; + op.enriched.count_left = ranked.count_left; + op.enriched.count_right = ranked.count_right; + op.enriched.zone = ranked.zone; if ((for_operation == operation_union - && ranked.left_count != 0) + && ranked.count_left != 0) || (for_operation == operation_intersection - && ranked.right_count != 2)) + && ranked.count_right != 2)) { op.enriched.startable = false; } } + cinfo.open_count = sbs.open_count(turns); } } diff --git a/include/boost/geometry/algorithms/detail/overlay/handle_touch.hpp b/include/boost/geometry/algorithms/detail/overlay/handle_touch.hpp deleted file mode 100644 index 399193d48..000000000 --- a/include/boost/geometry/algorithms/detail/overlay/handle_touch.hpp +++ /dev/null @@ -1,336 +0,0 @@ -// Boost.Geometry (aka GGL, Generic Geometry Library) - -// Copyright (c) 2015 Barend Gehrels, 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_OVERLAY_HANDLE_TOUCH_HPP -#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_HANDLE_TOUCH_HPP - -#include - -#include - -#include -#include -#include -#include - - -namespace boost { namespace geometry -{ - -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace overlay -{ - - -template -class handle_touch_uu -{ -private : - typedef typename boost::range_value::type turn_type; - typedef typename boost::range_iterator::type turn_iterator; - typedef typename boost::range_iterator::type turn_const_iterator; - - typedef typename boost::range_iterator - < - typename turn_type::container_type const - >::type operation_const_iterator; - -public : - - handle_touch_uu(Visitor& visitor) - : m_visitor(visitor) - {} - - inline void apply(detail::overlay::operation_type /*operation*/, Turns& turns) - { - if (! has_uu(turns)) - { - // Performance - if there is no u/u at all, nothing to be done - return; - } - - // Iterate through all u/u points - int turn_index = 0; - for (turn_iterator it = boost::begin(turns); - it != boost::end(turns); - ++it, ++turn_index) - { - turn_type& turn = *it; - if (! turn.both(operation_union)) - { - continue; - } - - m_visitor.print("handle_touch uu:", turns, turn_index); - - bool const traverse = turn_should_be_traversed(turns, turn, turn_index); - bool const start = traverse - && turn_should_be_startable(turns, turn, turn_index); - m_visitor.print("handle_touch, ready ", turns, turn_index); -// << std::boolalpha -// << traverse << " " << start - - if (traverse) - { - // Indicate the sources should switch here to create - // separate rings (outer ring / inner ring) - turn.switch_source = true; - } - // TODO: this is often not correct, fix this - turn.operations[0].enriched.startable = start; - turn.operations[1].enriched.startable = start; - } - } - -private : - - // Generic utility to be moved somewhere else - static inline - ring_identifier ring_id_from_seg_id(const segment_identifier& seg_id) - { - return ring_identifier(seg_id.source_index, - seg_id.multi_index, - seg_id.ring_index); - } - - static inline - ring_identifier ring_id_from_op(const turn_type& turn, - int operation_index) - { - return ring_id_from_seg_id(turn.operations[operation_index].seg_id); - } - - static inline bool in_range(const Turns& turns, signed_size_type index) - { - signed_size_type const turns_size = - static_cast(boost::size(turns)); - return index >= 0 && index < turns_size; - } - - static inline bool has_uu(const Turns& turns) - { - for (turn_const_iterator it = boost::begin(turns); - it != boost::end(turns); - ++it) - { - const turn_type& turn = *it; - if (turn.both(operation_union)) - { - return true; - } - } - return false; - } - - static inline - bool turn_should_be_startable(const Turns& turns, - const turn_type& uu_turn, - signed_size_type uu_turn_index) - { - return turn_startable(turns, uu_turn, 0, uu_turn_index) - || turn_startable(turns, uu_turn, 1, uu_turn_index); - - } - - static inline - bool turn_startable(const Turns& turns, - const turn_type& uu_turn, - std::size_t op_index, - signed_size_type original_turn_index, - std::size_t iteration = 0) - { - if (iteration >= boost::size(turns)) - { - // Defensive check to avoid infinite recursion - return false; - } - - signed_size_type const index - = uu_turn.operations[op_index].enriched.travels_to_ip_index; - if (index == original_turn_index) - { - // Completely traveled, having u/u only, via this op_index - return true; - } - - if (! in_range(turns, index)) - { - return false; - } - - const turn_type& new_turn = turns[index]; - - if (new_turn.operations[0].enriched.startable) - { - // Already selectable - no need to select u/u turn too - return false; - } - - // If this u/u turn is traversed normally (without skipping), sources are switched - return turn_startable(turns, new_turn, 1 - op_index, - original_turn_index, iteration + 1); - } - - inline bool turn_should_be_traversed(const Turns& turns, - const turn_type& uu_turn, - signed_size_type uu_turn_index) - { - return turn_should_be_traversed(turns, uu_turn, uu_turn_index, 0) - || turn_should_be_traversed(turns, uu_turn, uu_turn_index, 1); - } - - inline bool turn_should_be_traversed(const Turns& turns, - const turn_type& uu_turn, - signed_size_type uu_turn_index, - int uu_operation_index) - { - // Suppose this is a u/u turn between P and Q - // Examine all other turns on P and check if Q can be reached - // Use one of the operations and check if you can reach the other - signed_size_type const to_turn_index - = uu_turn.operations[uu_operation_index].enriched.travels_to_ip_index; - if (! in_range(turns, to_turn_index)) - { - return false; - } - - m_visitor.print("Examine:", turns, to_turn_index); - ring_identifier const other_ring_id - = ring_id_from_op(uu_turn, 1 - uu_operation_index); - - bool complete = false; - return can_reach(complete, turns, turns[to_turn_index], uu_operation_index, - other_ring_id, uu_turn_index, to_turn_index); - } - - inline bool can_reach(bool& complete, const Turns& turns, - const turn_type& turn, - signed_size_type uu_operation_index, - const ring_identifier& target_ring_id, - signed_size_type uu_turn_index, - signed_size_type to_turn_index, - std::size_t iteration = 0) - { - if (complete) - { - return false; - } - - if (turn.cluster_id >= 0) - { - // Clustered turns are yet not supported - return false; - } - - if (iteration >= boost::size(turns)) - { - m_visitor.print("Too much iterations"); - // Defensive check to avoid infinite recursion - return false; - } - - if (uu_operation_index != -1 && turn.both(operation_union)) - { - // If we end up in a u/u turn, check the way how, for this operation - m_visitor.print("Via u/u"); - return can_reach_via(complete, turns, uu_operation_index, - turn.operations[uu_operation_index], - target_ring_id, - uu_turn_index, to_turn_index, iteration); - } - else - { - // Check if specified ring can be reached via one of both operations - return can_reach_via(complete, turns, 0, turn.operations[0], target_ring_id, - uu_turn_index, to_turn_index, iteration) - || can_reach_via(complete, turns, 1, turn.operations[1], target_ring_id, - uu_turn_index, to_turn_index, iteration); - } - } - - template - inline bool can_reach_via(bool& complete, const Turns& turns, - signed_size_type operation_index, - const Operation& operation, - const ring_identifier& target_ring_id, - signed_size_type uu_turn_index, - signed_size_type to_turn_index, - std::size_t iteration = 0) - { - if (operation.operation != operation_union - && operation.operation != operation_continue) - { - return false; - } - - signed_size_type const index = operation.enriched.travels_to_ip_index; - if (index == to_turn_index) - { - m_visitor.print("Dead end at", turns, index); - // Completely traveled, the target is not found - return false; - } - if (index == uu_turn_index) - { - // End up where trial was started - m_visitor.print("Travel complete at", turns, index); - complete = true; - return false; - } - - if (! in_range(turns, index)) - { - return false; - } - - m_visitor.print("Now to", turns, index, operation_index); - const turn_type& new_turn = turns[index]; - - if (new_turn.both(operation_union)) - { - ring_identifier const ring_id = ring_id_from_op(new_turn, operation_index); - if (ring_id == target_ring_id) - { - m_visitor.print("Found (at u/u)!"); - return true; - } - } - else - { - ring_identifier const ring_id1 = ring_id_from_op(new_turn, 0); - ring_identifier const ring_id2 = ring_id_from_op(new_turn, 1); - if (ring_id1 == target_ring_id || ring_id2 == target_ring_id) - { - m_visitor.print("Found!"); - return true; - } - } - - // Recursively check this turn - return can_reach(complete, turns, new_turn, operation_index, target_ring_id, - uu_turn_index, to_turn_index, iteration + 1); - } - -private : - Visitor m_visitor; -}; - -template -inline void handle_touch(detail::overlay::operation_type operation, - Turns& turns, Visitor& visitor) -{ - handle_touch_uu handler(visitor); - handler.apply(operation, turns); -} - -}} // namespace detail::overlay -#endif // DOXYGEN_NO_DETAIL - -}} // namespace boost::geometry - -#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_HANDLE_TOUCH_HPP diff --git a/include/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp b/include/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp index 2817ba9d6..bb82003a2 100644 --- a/include/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp @@ -993,8 +993,8 @@ inline OutputIterator intersection_insert(Geometry1 const& geometry1, OutputIterator out, Strategy const& strategy) { - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); typedef typename Strategy::rescale_policy_type rescale_policy_type; rescale_policy_type robust_policy @@ -1034,8 +1034,8 @@ inline OutputIterator intersection_insert(Geometry1 const& geometry1, Geometry2 const& geometry2, OutputIterator out) { - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); typedef typename geometry::rescale_policy_type < diff --git a/include/boost/geometry/algorithms/detail/overlay/overlay.hpp b/include/boost/geometry/algorithms/detail/overlay/overlay.hpp index c3ecaa0b0..09c80025a 100644 --- a/include/boost/geometry/algorithms/detail/overlay/overlay.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/overlay.hpp @@ -23,10 +23,10 @@ #include +#include #include #include #include -#include #include #include #include @@ -220,11 +220,9 @@ struct overlay typedef std::map < signed_size_type, - std::set + cluster_info > cluster_type; - cluster_type clusters; - turn_container_type turns; #ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE @@ -239,18 +237,14 @@ std::cout << "get turns" << std::endl; visitor.visit_turns(1, turns); - static const operation_type op_type - = OverlayType == overlay_union - ? geometry::detail::overlay::operation_union - : geometry::detail::overlay::operation_intersection; - #ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE std::cout << "enrich" << std::endl; #endif typename Strategy::side_strategy_type side_strategy; + cluster_type clusters; + geometry::enrich_intersection_points(turns, - clusters, op_type, - geometry1, geometry2, + clusters, geometry1, geometry2, robust_policy, side_strategy); @@ -258,19 +252,6 @@ std::cout << "enrich" << std::endl; visitor.visit_clusters(clusters, turns); - -#if 0 - // TODO: does not work always correctly, move to traverse and fix - if (op_type == geometry::detail::overlay::operation_union) - { - #ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE - std::cout << "handle_touch" << std::endl; - #endif - - handle_touch(op_type, turns, visitor); - } -#endif - #ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE std::cout << "traverse" << std::endl; #endif @@ -278,7 +259,7 @@ std::cout << "traverse" << std::endl; // Note that these rings are always in clockwise order, even in CCW polygons, // and are marked as "to be reversed" below ring_container_type rings; - traverse::apply + traverse::apply ( geometry1, geometry2, robust_policy, diff --git a/include/boost/geometry/algorithms/detail/overlay/overlay_type.hpp b/include/boost/geometry/algorithms/detail/overlay/overlay_type.hpp index af62131f0..0f6084097 100644 --- a/include/boost/geometry/algorithms/detail/overlay/overlay_type.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/overlay_type.hpp @@ -14,14 +14,52 @@ namespace boost { namespace geometry { +// TODO: move to detail enum overlay_type { overlay_union, overlay_intersection, overlay_difference, + overlay_buffer, overlay_dissolve }; +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace overlay +{ + +enum operation_type +{ + operation_none, + operation_union, + operation_intersection, + operation_blocked, + operation_continue, + operation_opposite +}; + + +template +struct operation_from_overlay +{ + static const operation_type value = operation_union; +}; + +template <> +struct operation_from_overlay +{ + static const operation_type value = operation_intersection; +}; + +template <> +struct operation_from_overlay +{ + static const operation_type value = operation_intersection; +}; + +}} // namespace detail::overlay +#endif //DOXYGEN_NO_DETAIL + }} // namespace boost::geometry diff --git a/include/boost/geometry/algorithms/detail/overlay/select_rings.hpp b/include/boost/geometry/algorithms/detail/overlay/select_rings.hpp index 1b3cd866d..de5eac8ac 100644 --- a/include/boost/geometry/algorithms/detail/overlay/select_rings.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/select_rings.hpp @@ -165,11 +165,8 @@ namespace dispatch template struct decide -{}; - -template<> -struct decide { + // Default implementation (union, inflate, deflate, dissolve) static bool include(ring_identifier const& , ring_turn_info const& info) { return ! info.within_other; @@ -179,6 +176,7 @@ struct decide { return false; } + }; template<> diff --git a/include/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp b/include/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp index a74cb83f7..aedf22e1f 100644 --- a/include/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp @@ -276,7 +276,7 @@ inline void self_turns(Geometry const& geometry, RobustPolicy const& robust_policy, Turns& turns, InterruptPolicy& interrupt_policy) { - concept::check(); + concepts::check(); typedef detail::overlay::get_turn_info turn_policy; diff --git a/include/boost/geometry/algorithms/detail/overlay/sort_by_side.hpp b/include/boost/geometry/algorithms/detail/overlay/sort_by_side.hpp index 894cddab8..429ef4f92 100644 --- a/include/boost/geometry/algorithms/detail/overlay/sort_by_side.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/sort_by_side.hpp @@ -23,42 +23,44 @@ namespace boost { namespace geometry namespace detail { namespace overlay { namespace sort_by_side { -enum index_type { index_unknown = -1, index_from = 0, index_to = 1 }; +enum direction_type { dir_unknown = -1, dir_from = 0, dir_to = 1 }; // Point-wrapper, adding some properties template struct ranked_point { ranked_point() - : main_rank(0) + : rank(0) , turn_index(-1) - , op_index(-1) - , index(index_unknown) - , left_count(0) - , right_count(0) + , operation_index(-1) + , direction(dir_unknown) + , count_left(0) + , count_right(0) , operation(operation_none) {} - ranked_point(const Point& p, signed_size_type ti, signed_size_type oi, - index_type i, operation_type op, segment_identifier sid) + ranked_point(const Point& p, signed_size_type ti, int oi, + direction_type d, operation_type op, segment_identifier sid) : point(p) - , main_rank(0) + , rank(0) + , zone(-1) , turn_index(ti) - , op_index(oi) - , index(i) - , left_count(0) - , right_count(0) + , operation_index(oi) + , direction(d) + , count_left(0) + , count_right(0) , operation(op) , seg_id(sid) {} Point point; - std::size_t main_rank; + std::size_t rank; + signed_size_type zone; // index of closed zone, in uu turn there would be 2 zones signed_size_type turn_index; - signed_size_type op_index; - index_type index; - std::size_t left_count; - std::size_t right_count; + int operation_index; // 0,1 + direction_type direction; + std::size_t count_left; + std::size_t count_right; operation_type operation; segment_identifier seg_id; }; @@ -81,9 +83,9 @@ struct less_by_index inline bool operator()(const T& first, const T& second) const { // First order by from/to - if (first.index != second.index) + if (first.direction != second.direction) { - return first.index < second.index; + return first.direction < second.direction; } // All the same, order by turn index (we might consider length too) return first.turn_index < second.turn_index; @@ -200,8 +202,8 @@ struct side_sorter op.seg_id, point1, point2, point3); Point const& point_to = op.fraction.is_one() ? point3 : point2; - m_ranked_points.push_back(rp(point1, turn_index, op_index, index_from, op.operation, op.seg_id)); - m_ranked_points.push_back(rp(point_to, turn_index, op_index, index_to, op.operation, op.seg_id)); + m_ranked_points.push_back(rp(point1, turn_index, op_index, dir_from, op.operation, op.seg_id)); + m_ranked_points.push_back(rp(point_to, turn_index, op_index, dir_to, op.operation, op.seg_id)); if (is_origin) { @@ -233,7 +235,7 @@ struct side_sorter colinear_rank++; } - m_ranked_points[i].main_rank = colinear_rank; + m_ranked_points[i].rank = colinear_rank; } } @@ -243,7 +245,7 @@ struct side_sorter for (std::size_t i = 0; i < m_ranked_points.size(); i++) { const rp& ranked = m_ranked_points[i]; - if (ranked.index != index_from) + if (ranked.direction != dir_from) { continue; } @@ -290,6 +292,8 @@ struct side_sorter &segment_identifier::source_index >(handled); } + + assign_zones(); } void reverse() @@ -299,25 +303,25 @@ struct side_sorter return; } - int const last = 1 + m_ranked_points.back().main_rank; + std::size_t const last = 1 + m_ranked_points.back().rank; - // Move iterator after main_rank==0 + // Move iterator after rank==0 bool has_first = false; typename container_type::iterator it = m_ranked_points.begin() + 1; - for (; it != m_ranked_points.end() && it->main_rank == 0; ++it) + for (; it != m_ranked_points.end() && it->rank == 0; ++it) { has_first = true; } if (has_first) { - // Reverse first part (having main_rank == 0), if any, + // Reverse first part (having rank == 0), if any, // but skip the very first row std::reverse(m_ranked_points.begin() + 1, it); for (typename container_type::iterator fit = m_ranked_points.begin(); fit != it; ++fit) { - BOOST_ASSERT(fit->main_rank == 0); + BOOST_ASSERT(fit->rank == 0); } } @@ -325,11 +329,41 @@ struct side_sorter std::reverse(it, m_ranked_points.end()); for (; it != m_ranked_points.end(); ++it) { - BOOST_ASSERT(it->main_rank > 0); - it->main_rank = last - it->main_rank; + BOOST_ASSERT(it->rank > 0); + it->rank = last - it->rank; } } + //! Check how many open spaces there are + template + std::size_t open_count(Turns const& turns) const + { + typedef typename boost::range_value::type turn_type; + typedef typename turn_type::turn_operation_type turn_operation_type; + + std::size_t result = 0; + std::size_t last_rank = 0; + for (std::size_t i = 0; i < m_ranked_points.size(); i++) + { + rp const& ranked_point = m_ranked_points[i]; + + if (ranked_point.rank > last_rank + && ranked_point.direction == sort_by_side::dir_to) + { + // TODO: take count-left / count_right from rank itself + turn_type const& ranked_turn = turns[ranked_point.turn_index]; + turn_operation_type const& ranked_op = ranked_turn.operations[ranked_point.operation_index]; + if (ranked_op.enriched.count_left == 0 + && ranked_op.enriched.count_right > 0) + { + result++; + last_rank = ranked_point.rank; + } + } + } + return result; + } + //protected : typedef std::vector container_type; @@ -366,19 +400,19 @@ private : // if min=5,max=2: assign from 5,6,7,1,2 bool const in_range = max_rank >= min_rank - ? ranked.main_rank >= min_rank && ranked.main_rank <= max_rank - : ranked.main_rank >= min_rank || ranked.main_rank <= max_rank + ? ranked.rank >= min_rank && ranked.rank <= max_rank + : ranked.rank >= min_rank || ranked.rank <= max_rank ; if (in_range) { if (side_index == 1) { - ranked.left_count++; + ranked.count_left++; } else if (side_index == 2) { - ranked.right_count++; + ranked.count_right++; } } } @@ -389,8 +423,8 @@ private : std::size_t start_index) { int state = 1; // 'closed', because start_index is "from", arrives at the turn - std::size_t last_from_rank = m_ranked_points[start_index].main_rank; - std::size_t previous_rank = m_ranked_points[start_index].main_rank; + std::size_t last_from_rank = m_ranked_points[start_index].rank; + std::size_t previous_rank = m_ranked_points[start_index].rank; for (std::size_t index = move(the_index, start_index); ; @@ -398,7 +432,7 @@ private : { rp& ranked = m_ranked_points[index]; - if (ranked.main_rank != previous_rank && state == 0) + if (ranked.rank != previous_rank && state == 0) { assign_ranks(last_from_rank, previous_rank - 1, 1); assign_ranks(last_from_rank + 1, previous_rank, 2); @@ -409,19 +443,91 @@ private : return; } - if (ranked.index == index_from) + if (ranked.direction == dir_from) { - last_from_rank = ranked.main_rank; + last_from_rank = ranked.rank; state++; } - else if (ranked.index == index_to) + else if (ranked.direction == dir_to) { state--; } - previous_rank = ranked.main_rank; + previous_rank = ranked.rank; } } + + //! Find closed zones and assign it + void assign_zones() + { + // Find a starting point (the first rank after an outgoing rank + // with no polygons on the left side) + std::size_t start_rank = m_ranked_points.size() + 1; + std::size_t start_index = 0; + std::size_t max_rank = 0; + for (std::size_t i = 0; i < m_ranked_points.size(); i++) + { + rp const& ranked_point = m_ranked_points[i]; + if (ranked_point.rank > max_rank) + { + max_rank = ranked_point.rank; + } + if (ranked_point.direction == sort_by_side::dir_to + && ranked_point.count_left == 0 + && ranked_point.count_right > 0) + { + start_rank = ranked_point.rank + 1; + } + if (ranked_point.rank == start_rank && start_index == 0) + { + start_index = i; + } + } + + // Assign the zones + std::size_t const undefined_rank = max_rank + 1; + std::size_t zone_id = 0; + std::size_t last_rank = 0; + std::size_t rank_at_next_zone = undefined_rank; + std::size_t index = start_index; + for (std::size_t i = 0; i < m_ranked_points.size(); i++) + { + rp& ranked_point = m_ranked_points[index]; + + // Implement cyclic behavior + index++; + if (index == m_ranked_points.size()) + { + index = 0; + } + + if (ranked_point.rank != last_rank) + { + if (ranked_point.rank == rank_at_next_zone) + { + zone_id++; + rank_at_next_zone = undefined_rank; + } + + if (ranked_point.direction == sort_by_side::dir_to + && ranked_point.count_left == 0 + && ranked_point.count_right > 0) + { + rank_at_next_zone = ranked_point.rank + 1; + if (rank_at_next_zone > max_rank) + { + rank_at_next_zone = 0; + } + } + + last_rank = ranked_point.rank; + } + + ranked_point.zone = zone_id; + } + } + + }; diff --git a/include/boost/geometry/algorithms/detail/overlay/traversal.hpp b/include/boost/geometry/algorithms/detail/overlay/traversal.hpp new file mode 100644 index 000000000..1156644bc --- /dev/null +++ b/include/boost/geometry/algorithms/detail/overlay/traversal.hpp @@ -0,0 +1,672 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, 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_OVERLAY_TRAVERSAL_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_HPP + +#include + +#include + +#include +#include +#include +#include + +#if defined(BOOST_GEOMETRY_DEBUG_INTERSECTION) \ + || defined(BOOST_GEOMETRY_OVERLAY_REPORT_WKT) \ + || defined(BOOST_GEOMETRY_DEBUG_TRAVERSE) +# include +# include +# include +#endif + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace overlay +{ + +template +#ifdef BOOST_GEOMETRY_DEBUG_TRAVERSE +inline void debug_traverse(Turn const& turn, Operation op, + std::string const& header) +{ + std::cout << header + << " at " << op.seg_id + << " meth: " << method_char(turn.method) + << " op: " << operation_char(op.operation) + << " vis: " << visited_char(op.visited) + << " of: " << operation_char(turn.operations[0].operation) + << operation_char(turn.operations[1].operation) + << " " << geometry::wkt(turn.point) + << std::endl; + + if (boost::contains(header, "Finished")) + { + std::cout << std::endl; + } +} +#else +inline void debug_traverse(Turn const& , Operation, const char*) +{ +} +#endif + + +//! Metafunction to define side_order (clockwise, ccw) by operation_type +template +struct side_compare {}; + +template <> +struct side_compare +{ + typedef std::greater type; +}; + +template <> +struct side_compare +{ + typedef std::less type; +}; + + +template +< + bool Reverse1, + bool Reverse2, + overlay_type OverlayType, + typename Geometry1, + typename Geometry2, + typename Turns, + typename Clusters, + typename RobustPolicy, + typename Visitor +> +struct traversal +{ + static const operation_type target_operation = operation_from_overlay::value; + + typedef typename side_compare::type side_compare_type; + typedef typename boost::range_value::type turn_type; + typedef typename turn_type::turn_operation_type turn_operation_type; + + typedef typename geometry::point_type::type point_type; + typedef sort_by_side::side_sorter + < + Reverse1, Reverse2, + point_type, side_compare_type + > sbs_type; + + inline traversal(Geometry1 const& geometry1, Geometry2 const& geometry2, + Turns& turns, Clusters const& clusters, + RobustPolicy const& robust_policy, Visitor& visitor) + : m_geometry1(geometry1) + , m_geometry2(geometry2) + , m_turns(turns) + , m_clusters(clusters) + , m_robust_policy(robust_policy) + , m_visitor(visitor) + { + } + + inline void finalize_visit_info() + { + for (typename boost::range_iterator::type + it = boost::begin(m_turns); + it != boost::end(m_turns); + ++it) + { + turn_type& turn = *it; + for (int i = 0; i < 2; i++) + { + turn_operation_type& op = turn.operations[i]; + op.visited.finalize(); + } + } + } + + inline void set_visited(turn_type& turn, turn_operation_type& op) + { + // On "continue", set "visited" for ALL directions in this turn + if (op.operation == detail::overlay::operation_continue) + { + for (int i = 0; i < 2; i++) + { + turn_operation_type& op = turn.operations[i]; + if (op.visited.none()) + { + op.visited.set_visited(); + } + } + } + else + { + op.visited.set_visited(); + } + } + + inline bool is_visited(turn_type const& turn, turn_operation_type const& op, + signed_size_type turn_index, int op_index) const + { + return op.visited.visited(); + } + + inline bool select_source(signed_size_type turn_index, + segment_identifier const& seg_id1, + segment_identifier const& seg_id2) const + { + if (target_operation == operation_intersection) + { + // For intersections always switch sources + return seg_id1.source_index != seg_id2.source_index; + } + else if (target_operation == operation_union) + { + // For uu, only switch sources if indicated + turn_type const& turn = m_turns[turn_index]; + + if (OverlayType == overlay_buffer) + { + // Buffer does not use source_index (always 0) + return turn.switch_source + ? seg_id1.multi_index != seg_id2.multi_index + : seg_id1.multi_index == seg_id2.multi_index; + } + +#if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR) + if (turn.switch_source == 1) + { + std::cout << "Switch source at " << turn_index << std::endl; + } + else + { + std::cout << "DON'T SWITCH SOURCES at " << turn_index << std::endl; + } +#endif + return turn.switch_source + ? seg_id1.source_index != seg_id2.source_index + : seg_id1.source_index == seg_id2.source_index; + } + return false; + } + + inline + signed_size_type get_next_turn_index(turn_operation_type const& op) const + { + return op.enriched.next_ip_index == -1 + ? op.enriched.travels_to_ip_index + : op.enriched.next_ip_index; + } + + inline bool traverse_possible(signed_size_type turn_index) const + { + if (turn_index == -1) + { + return false; + } + + turn_type const& turn = m_turns[turn_index]; + + // It is not a dead end if there is an operation to continue, or of + // there is a cluster (assuming for now we can get out of the cluster) + return turn.cluster_id >= 0 + || turn.has(target_operation) + || turn.has(operation_continue); + } + + inline + bool select_cc_operation(turn_type const& turn, + signed_size_type start_turn_index, + int& selected_op_index) const + { + // For "cc", take either one, but if there is a starting one, + // take that one. If next is dead end, skip that one. + + bool result = false; + + typename turn_operation_type::comparable_distance_type + max_remaining_distance = 0; + + for (int i = 0; i < 2; i++) + { + turn_operation_type const& op = turn.operations[i]; + + signed_size_type const next_turn_index = get_next_turn_index(op); + + if (! result && traverse_possible(next_turn_index)) + { + max_remaining_distance = op.remaining_distance; + selected_op_index = i; + debug_traverse(turn, op, " Candidate"); + result = true; + } + + if (result) + { + if (next_turn_index == start_turn_index) + { + selected_op_index = i; + debug_traverse(turn, op, " Candidate cc override (start)"); + } + else if (op.remaining_distance > max_remaining_distance) + { + max_remaining_distance = op.remaining_distance; + selected_op_index = i; + debug_traverse(turn, op, " Candidate cc override (remaining)"); + } + } + } + + return result; + } + + inline + bool select_noncc_operation(turn_type const& turn, + signed_size_type turn_index, + segment_identifier const& seg_id, + int& selected_op_index) const + { + // For "ii", take the other one (alternate) + // UNLESS the other one is already visited + // For "uu", take the same one (see above); + + bool result = false; + + for (int i = 0; i < 2; i++) + { + turn_operation_type const& op = turn.operations[i]; + + if (op.operation == target_operation + && ! op.visited.finished() + && (! result || select_source(turn_index, op.seg_id, seg_id))) + { + selected_op_index = i; + debug_traverse(turn, op, " Candidate"); + result = true; + } + } + + return result; + } + + inline + bool select_operation(const turn_type& turn, + signed_size_type turn_index, + signed_size_type start_turn_index, + segment_identifier const& previous_seg_id, + int& selected_op_index) const + { + bool result = false; + selected_op_index = -1; + if (turn.both(operation_continue)) + { + result = select_cc_operation(turn, start_turn_index, + selected_op_index); + } + else + { + result = select_noncc_operation(turn, turn_index, + previous_seg_id, selected_op_index); + } + if (result) + { + debug_traverse(turn, turn.operations[selected_op_index], " Accepted"); + } + + return result; + } + + inline int starting_operation_index(const turn_type& turn) const + { + for (int i = 0; i < 2; i++) + { + if (turn.operations[i].visited.started()) + { + return i; + } + } + return -1; + } + + inline bool both_finished(const turn_type& turn) const + { + for (int i = 0; i < 2; i++) + { + if (! turn.operations[i].visited.finished()) + { + return false; + } + } + return true; + } + + inline bool select_from_cluster(signed_size_type& turn_index, + int& op_index, signed_size_type start_turn_index, + sbs_type const& sbs, bool is_touching) const + { + bool const is_union = target_operation == operation_union; + bool const is_intersection = target_operation == operation_intersection; + + std::size_t selected_rank = 0; + std::size_t min_rank = 0; + bool result = false; + for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++) + { + typename sbs_type::rp const& ranked_point = sbs.m_ranked_points[i]; + if (result && ranked_point.rank > selected_rank) + { + return result; + } + + turn_type const& ranked_turn = m_turns[ranked_point.turn_index]; + turn_operation_type const& ranked_op = ranked_turn.operations[ranked_point.operation_index]; + + if (result && ranked_op.visited.finalized()) + { + // One of the arcs in the same direction as the selected result + // is already traversed. + return false; + } + + if (! is_touching && ranked_op.visited.finalized()) + { + // Skip this one, go to next + min_rank = ranked_point.rank; + continue; + } + + if (ranked_point.direction == sort_by_side::dir_to + && (ranked_point.rank > min_rank + || ranked_turn.both(operation_continue))) + { + if ((is_union + && ranked_op.enriched.count_left == 0 + && ranked_op.enriched.count_right > 0) + || (is_intersection + && ranked_op.enriched.count_right == 2)) + { + if (result && ranked_point.turn_index != start_turn_index) + { + // Don't override - only override if arrive at start + continue; + } + + turn_index = ranked_point.turn_index; + op_index = ranked_point.operation_index; + + if (is_intersection + && ranked_turn.both(operation_intersection) + && ranked_op.visited.finalized()) + { + // Override: + // For a ii turn, even though one operation might be selected, + // it should take the other one if the first one is used in a completed ring + op_index = 1 - ranked_point.operation_index; + } + + result = true; + selected_rank = ranked_point.rank; + } + else if (! is_touching) + { + return result; + } + } + } + return result; + } + + inline bool select_turn_from_cluster(signed_size_type& turn_index, + int& op_index, bool& is_touching, + signed_size_type start_turn_index, + segment_identifier const& previous_seg_id) const + { + bool const is_union = target_operation == operation_union; + + turn_type const& turn = m_turns[turn_index]; + BOOST_ASSERT(turn.cluster_id >= 0); + + typename Clusters::const_iterator mit = m_clusters.find(turn.cluster_id); + BOOST_ASSERT(mit != m_clusters.end()); + + cluster_info const& cinfo = mit->second; + std::set const& ids = cinfo.turn_indices; + + sbs_type sbs; + + bool has_origin = false; + + for (typename std::set::const_iterator sit = ids.begin(); + sit != ids.end(); ++sit) + { + signed_size_type cluster_turn_index = *sit; + turn_type const& cluster_turn = m_turns[cluster_turn_index]; + if (cluster_turn.discarded) + { + // Defensive check, discarded turns should not be in cluster + continue; + } + + for (int i = 0; i < 2; i++) + { + turn_operation_type const& op = cluster_turn.operations[i]; + bool is_origin = false; + if (cluster_turn_index == turn_index) + { + // Check if this is the origin + if (OverlayType == overlay_buffer) + { + is_origin = op.seg_id.multi_index == previous_seg_id.multi_index; + } + else + { + is_origin = op.seg_id.source_index + == previous_seg_id.source_index; + } + if (is_origin) + { + has_origin = true; + } + } + + sbs.add(op, cluster_turn_index, i, m_geometry1, m_geometry2, + is_origin); + } + } + + if (! has_origin) + { + return false; + } + + sbs.apply(turn.point); + +#if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR) + is_touching = is_union && cinfo.open_count > 1; + if (is_touching) + { + if (cinfo.switch_source) + { + is_touching = false; + std::cout << "CLUSTER: SWITCH SOURCES at " << turn_index << std::endl; + } + else + { + std::cout << "CLUSTER: CONTINUE at " << turn_index << std::endl; + } + } +#else + is_touching = is_union && cinfo.open_count > 1 && ! cinfo.switch_source; +#endif + if (is_touching) + { + sbs.reverse(); + } + + return select_from_cluster(turn_index, op_index, start_turn_index, sbs, + is_touching); + } + + inline void change_index_for_self_turn(signed_size_type& to_vertex_index, + turn_type const& start_turn, + turn_operation_type const& start_op, + int start_op_index) const + { + if (OverlayType != overlay_buffer) + { + return; + } + + // It travels to itself, can happen. If this is a buffer, it can + // sometimes travel to itself in the following configuration: + // + // +---->--+ + // | | + // | +---*----+ *: one turn, with segment index 2/7 + // | | | | + // | +---C | C: closing point (start/end) + // | | + // +------------+ + // + // If it starts on segment 2 and travels to itself on segment 2, that + // should be corrected to 7 because that is the shortest path + // + // Also a uu turn (touching with another buffered ring) might have this + // apparent configuration, but there it should + // always travel the whole ring + + turn_operation_type const& other_op + = start_turn.operations[1 - start_op_index]; + + bool const correct + = ! start_turn.both(operation_union) + && start_op.seg_id.segment_index == to_vertex_index; + +#if defined(BOOST_GEOMETRY_DEBUG_TRAVERSE) + std::cout << " WARNING: self-buffer " + << " correct=" << correct + << " turn=" << operation_char(start_turn.operations[0].operation) + << operation_char(start_turn.operations[1].operation) + << " start=" << start_op.seg_id.segment_index + << " from=" << to_vertex_index + << " to=" << other_op.enriched.travels_to_vertex_index + << std::endl; +#endif + + if (correct) + { + to_vertex_index = other_op.enriched.travels_to_vertex_index; + } + } + + bool select_turn_from_enriched(signed_size_type& turn_index, + segment_identifier& previous_seg_id, + signed_size_type& to_vertex_index, + signed_size_type start_turn_index, + int start_op_index, + turn_type const& previous_turn, + turn_operation_type const& previous_op, + bool is_start) const + { + to_vertex_index = -1; + + if (previous_op.enriched.next_ip_index < 0) + { + // There is no next IP on this segment + if (previous_op.enriched.travels_to_vertex_index < 0 + || previous_op.enriched.travels_to_ip_index < 0) + { + return false; + } + + to_vertex_index = previous_op.enriched.travels_to_vertex_index; + + if (is_start && + previous_op.enriched.travels_to_ip_index == start_turn_index) + { + change_index_for_self_turn(to_vertex_index, previous_turn, + previous_op, start_op_index); + } + + turn_index = previous_op.enriched.travels_to_ip_index; + previous_seg_id = previous_op.seg_id; + } + else + { + // Take the next IP on this segment + turn_index = previous_op.enriched.next_ip_index; + previous_seg_id = previous_op.seg_id; + } + return true; + } + + bool select_turn(signed_size_type start_turn_index, + signed_size_type& turn_index, + int& op_index, + bool& is_touching, + int previous_op_index, + signed_size_type previous_turn_index, + segment_identifier const& previous_seg_id, + bool is_start) + { + if (m_turns[turn_index].cluster_id >= 0) + { + if (! select_turn_from_cluster(turn_index, op_index, is_touching, + start_turn_index, previous_seg_id)) + { + return false; + } + + if (is_start && turn_index == previous_turn_index) + { + op_index = previous_op_index; + } + } + else + { + turn_type const& current_turn = m_turns[turn_index]; + + op_index = starting_operation_index(current_turn); + if (op_index == -1) + { + if (both_finished(current_turn)) + { + return false; + } + + if (! select_operation(current_turn, turn_index, + start_turn_index, + previous_seg_id, + op_index)) + { + return false; + } + } + } + return true; + } + +private : + Geometry1 const& m_geometry1; + Geometry2 const& m_geometry2; + Turns& m_turns; + Clusters const& m_clusters; + RobustPolicy const& m_robust_policy; + Visitor& m_visitor; +}; + + + +}} // namespace detail::overlay +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_HPP diff --git a/include/boost/geometry/algorithms/detail/overlay/traversal_ring_creator.hpp b/include/boost/geometry/algorithms/detail/overlay/traversal_ring_creator.hpp new file mode 100644 index 000000000..104bd6b8e --- /dev/null +++ b/include/boost/geometry/algorithms/detail/overlay/traversal_ring_creator.hpp @@ -0,0 +1,347 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, 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_OVERLAY_TRAVERSAL_RING_CREATOR_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_RING_CREATOR_HPP + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace overlay +{ + + +template +< + bool Reverse1, + bool Reverse2, + overlay_type OverlayType, + typename Geometry1, + typename Geometry2, + typename Turns, + typename Clusters, + typename RobustPolicy, + typename Visitor, + typename Backtrack +> +struct traversal_ring_creator +{ + typedef traversal + traversal_type; + + typedef typename boost::range_value::type turn_type; + typedef typename turn_type::turn_operation_type turn_operation_type; + + static const operation_type target_operation + = operation_from_overlay::value; + + inline traversal_ring_creator(Geometry1 const& geometry1, Geometry2 const& geometry2, + Turns& turns, Clusters const& clusters, + RobustPolicy const& robust_policy, Visitor& visitor) + : m_trav(geometry1, geometry2, turns, clusters, robust_policy,visitor) + , m_geometry1(geometry1) + , m_geometry2(geometry2) + , m_turns(turns) + , m_clusters(clusters) + , m_robust_policy(robust_policy) + , m_visitor(visitor) + , m_has_uu(false) + { + + } + + template + inline traverse_error_type travel_to_next_turn(signed_size_type start_turn_index, + int start_op_index, + signed_size_type& turn_index, + int& op_index, + Ring& current_ring, + bool is_start) + { + int const previous_op_index = op_index; + signed_size_type const previous_turn_index = turn_index; + turn_type& previous_turn = m_turns[turn_index]; + turn_operation_type& previous_op = previous_turn.operations[op_index]; + segment_identifier previous_seg_id; + + signed_size_type to_vertex_index = -1; + if (! m_trav.select_turn_from_enriched(turn_index, previous_seg_id, + to_vertex_index, start_turn_index, start_op_index, + previous_turn, previous_op, is_start)) + { + return is_start + ? traverse_error_no_next_ip_at_start + : traverse_error_no_next_ip; + } + if (to_vertex_index >= 0) + { + if (previous_op.seg_id.source_index == 0) + { + geometry::copy_segments(m_geometry1, + previous_op.seg_id, to_vertex_index, + m_robust_policy, current_ring); + } + else + { + geometry::copy_segments(m_geometry2, + previous_op.seg_id, to_vertex_index, + m_robust_policy, current_ring); + } + } + + if (m_turns[turn_index].discarded) + { + return is_start + ? traverse_error_dead_end_at_start + : traverse_error_dead_end; + } + + if (is_start) + { + // Register the start + previous_op.visited.set_started(); + m_visitor.visit_traverse(m_turns, previous_turn, previous_op, "Start"); + } + + bool is_touching = false; + if (! m_trav.select_turn(start_turn_index, turn_index, op_index, + is_touching, + previous_op_index, previous_turn_index, previous_seg_id, + is_start)) + { + return is_start + ? traverse_error_no_next_ip_at_start + : traverse_error_no_next_ip; + } + + { + // Check operation (TODO: this might be redundant or should be catched before) + const turn_type& current_turn = m_turns[turn_index]; + const turn_operation_type& op = current_turn.operations[op_index]; + if (op.visited.finalized() + || m_trav.is_visited(current_turn, op, turn_index, op_index)) + { + return traverse_error_visit_again; + } + } + + // Update registration and append point + turn_type& current_turn = m_turns[turn_index]; + turn_operation_type& op = current_turn.operations[op_index]; + detail::overlay::append_no_dups_or_spikes(current_ring, current_turn.point, + m_robust_policy); + + // Register the visit + m_trav.set_visited(current_turn, op); + m_visitor.visit_traverse(m_turns, current_turn, op, "Visit"); + + return traverse_error_none; + } + + template + inline traverse_error_type traverse(Ring& ring, + signed_size_type start_turn_index, int start_op_index) + { + turn_type const& start_turn = m_turns[start_turn_index]; + turn_operation_type& start_op = m_turns[start_turn_index].operations[start_op_index]; + + detail::overlay::append_no_dups_or_spikes(ring, start_turn.point, + m_robust_policy); + + signed_size_type current_turn_index = start_turn_index; + int current_op_index = start_op_index; + + traverse_error_type error = travel_to_next_turn(start_turn_index, + start_op_index, + current_turn_index, current_op_index, + ring, true); + + if (error != traverse_error_none) + { + // This is not necessarily a problem, it happens for clustered turns + // which are "build in" or otherwise point inwards + return error; + } + + if (current_turn_index == start_turn_index) + { + start_op.visited.set_finished(); + m_visitor.visit_traverse(m_turns, m_turns[current_turn_index], start_op, "Early finish"); + return traverse_error_none; + } + + std::size_t const max_iterations = 2 + 2 * m_turns.size(); + for (std::size_t i = 0; i <= max_iterations; i++) + { + // We assume clockwise polygons only, non self-intersecting, closed. + // However, the input might be different, and checking validity + // is up to the library user. + + // Therefore we make here some sanity checks. If the input + // violates the assumptions, the output polygon will not be correct + // but the routine will stop and output the current polygon, and + // will continue with the next one. + + // Below three reasons to stop. + error = travel_to_next_turn(start_turn_index, start_op_index, + current_turn_index, current_op_index, + ring, false); + + if (error != traverse_error_none) + { + return error; + } + + if (current_turn_index == start_turn_index + && current_op_index == start_op_index) + { + start_op.visited.set_finished(); + m_visitor.visit_traverse(m_turns, start_turn, start_op, "Finish"); + return traverse_error_none; + } + } + + return traverse_error_endless_loop; + } + + template + void traverse_with_operation(turn_type const& start_turn, + std::size_t turn_index, int op_index, + Rings& rings, std::size_t& finalized_ring_size, + typename Backtrack::state_type& state) + { + typedef typename boost::range_value::type ring_type; + + turn_operation_type const& start_op = start_turn.operations[op_index]; + + if (! start_op.visited.none() + || ! start_op.enriched.startable + || start_op.visited.rejected() + || ! (start_op.operation == target_operation + || start_op.operation == detail::overlay::operation_continue)) + { + return; + } + + ring_type ring; + traverse_error_type traverse_error = traverse(ring, turn_index, op_index); + + if (traverse_error == traverse_error_none) + { + std::size_t const min_num_points + = core_detail::closure::minimum_ring_size + < + geometry::closure::value + >::value; + + if (geometry::num_points(ring) >= min_num_points) + { + clean_closing_dups_and_spikes(ring, m_robust_policy); + rings.push_back(ring); + + m_trav.finalize_visit_info(); + finalized_ring_size++; + } + } + else + { + Backtrack::apply( + finalized_ring_size, + rings, ring, m_turns, start_turn, + m_turns[turn_index].operations[op_index], + traverse_error, + m_geometry1, m_geometry2, m_robust_policy, + state, m_visitor); + } + } + + template + void iterate(Rings& rings, std::size_t& finalized_ring_size, + typename Backtrack::state_type& state, + int pass) + { + if (pass == 1) + { + if (target_operation == operation_intersection) + { + // Second pass currently only used for uu + return; + } + if (! m_has_uu) + { + // There is no uu found in first pass + return; + } + } + + // Iterate through all unvisited points + for (std::size_t turn_index = 0; turn_index < m_turns.size(); ++turn_index) + { + turn_type const& start_turn = m_turns[turn_index]; + + if (start_turn.discarded || start_turn.blocked()) + { + // Skip discarded and blocked turns + continue; + } + if (target_operation == operation_union) + { + if (start_turn.both(operation_union)) + { + // Start with a uu-turn only in the second pass + m_has_uu = true; + if (pass == 0) + { + continue; + } + } + } + + for (int op_index = 0; op_index < 2; op_index++) + { + traverse_with_operation(start_turn, turn_index, op_index, + rings, finalized_ring_size, state); + } + } + } + +private: + traversal_type m_trav; + + Geometry1 const& m_geometry1; + Geometry2 const& m_geometry2; + Turns& m_turns; + Clusters const& m_clusters; + RobustPolicy const& m_robust_policy; + Visitor& m_visitor; + + // Next member is only used for operation union + bool m_has_uu; + +}; + +}} // namespace detail::overlay +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_RING_CREATOR_HPP diff --git a/include/boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp b/include/boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp new file mode 100644 index 000000000..e37c8657c --- /dev/null +++ b/include/boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp @@ -0,0 +1,291 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2015-2016 Barend Gehrels, 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_OVERLAY_TRAVERSAL_SWITCH_DETECTOR_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_SWITCH_DETECTOR_HPP + +#include + +#include + +#include +#include +#include +#include +#include +#include + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace overlay +{ + +// Generic function (is this used somewhere else too?) +inline ring_identifier ring_id_by_seg_id(segment_identifier const& seg_id) +{ + return ring_identifier(seg_id.source_index, seg_id.multi_index, seg_id.ring_index); +} + +template +< + bool Reverse1, + bool Reverse2, + overlay_type OverlayType, + typename Geometry1, + typename Geometry2, + typename Turns, + typename Clusters, + typename RobustPolicy, + typename Visitor +> +struct traversal_switch_detector +{ + typedef typename boost::range_value::type turn_type; + typedef typename turn_type::turn_operation_type turn_operation_type; + + // For convenience + typedef std::set::const_iterator set_iterator; + + inline traversal_switch_detector(Geometry1 const& geometry1, Geometry2 const& geometry2, + Turns& turns, Clusters& clusters, + RobustPolicy const& robust_policy, Visitor& visitor) + : m_geometry1(geometry1) + , m_geometry2(geometry2) + , m_turns(turns) + , m_clusters(clusters) + , m_robust_policy(robust_policy) + , m_visitor(visitor) + , m_region_id(0) + { + + } + + static inline bool connects_same_zone(turn_type const& turn) + { + if (turn.cluster_id == -1) + { + // If it is a uu-turn (non clustered), it is never same zone + return ! turn.both(operation_union); + } + + // It is a cluster, check zones of both operations + return turn.operations[0].enriched.zone + == turn.operations[1].enriched.zone; + } + + inline int get_region_id(turn_operation_type const& op) const + { + std::map::const_iterator it + = m_regions.find(ring_id_by_seg_id(op.seg_id)); + return it == m_regions.end() ? -1 : it->second; + } + + void create_region(ring_identifier const& ring_id, std::set const& ring_turn_indices, int region_id = -1) + { + std::map::const_iterator it = m_regions.find(ring_id); + if (it != m_regions.end()) + { + // The ring is already gathered in a region, quit + return; + } + if (region_id == -1) + { + region_id = m_region_id++; + } + + // Assign this ring to specified region + m_regions[ring_id] = region_id; +#if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR) + std::cout << " ADD " << ring_id << " TO REGION " << region_id << std::endl; +#endif + + // Find connecting rings, recursively + for (set_iterator sit = ring_turn_indices.begin(); + sit != ring_turn_indices.end(); ++sit) + { + signed_size_type const turn_index = *sit; + turn_type const& turn = m_turns[turn_index]; + if (! connects_same_zone(turn)) + { + // This is a non clustered uu-turn, or a cluster connecting different 'zones' + continue; + } + + // This turn connects two rings (interior connected), create the + // same region + for (int op_index = 0; op_index < 2; op_index++) + { + turn_operation_type const& op = turn.operations[op_index]; + ring_identifier connected_ring_id = ring_id_by_seg_id(op.seg_id); + if (connected_ring_id != ring_id) + { + propagate_region(connected_ring_id, region_id); + } + } + } + } + + void propagate_region(ring_identifier const& ring_id, int region_id) + { + std::map >::const_iterator it = m_turns_per_ring.find(ring_id); + if (it != m_turns_per_ring.end()) + { + create_region(ring_id, it->second, region_id); + } + } + + void iterate() + { +#if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR) + std::cout << "SWITCH BEGIN ITERATION" << std::endl; +#endif + + // Collect turns per ring + m_turns_per_ring.clear(); + m_regions.clear(); + m_region_id = 1; + + for (std::size_t turn_index = 0; turn_index < m_turns.size(); ++turn_index) + { + turn_type const& turn = m_turns[turn_index]; + + for (int op_index = 0; op_index < 2; op_index++) + { + turn_operation_type const& op = turn.operations[op_index]; + m_turns_per_ring[ring_id_by_seg_id(op.seg_id)].insert(turn_index); + } + } + + // All rings having turns are in the map. Now iterate them + for (std::map >::const_iterator it + = m_turns_per_ring.begin(); it != m_turns_per_ring.end(); ++it) + { + create_region(it->first, it->second); + } + + // Now that all regions are filled, assign switch_source property + // Iterate through all clusters + for (typename Clusters::iterator it = m_clusters.begin(); it != m_clusters.end(); ++it) + { + cluster_info& cinfo = it->second; + if (cinfo.open_count <= 1) + { + // Not a touching cluster + continue; + } + + // A touching cluster, gather regions + std::set regions; + + std::set const& ids = cinfo.turn_indices; + +#if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR) + std::cout << "SWITCH EXAMINE CLUSTER " << it->first << std::endl; +#endif + + for (set_iterator sit = ids.begin(); sit != ids.end(); ++sit) + { + signed_size_type turn_index = *sit; + turn_type const& turn = m_turns[turn_index]; + for (int oi = 0; oi < 2; oi++) + { + int const region = get_region_id(turn.operations[oi]); + regions.insert(region); + } + } + // Switch source if this cluster connects the same region + cinfo.switch_source = regions.size() == 1; + } + + // Iterate through all uu turns (non-clustered) + for (std::size_t turn_index = 0; turn_index < m_turns.size(); ++turn_index) + { + turn_type& turn = m_turns[turn_index]; + + if (turn.discarded + || turn.blocked() + || turn.cluster_id >= 0 + || ! turn.both(operation_union)) + { + // Skip discarded, blocked, non-uu and clustered turns + continue; + } + + if (OverlayType == overlay_buffer) + { + // For deflate, the region approach does not work because many + // pieces are outside the real polygons + // TODO: implement this in another way for buffer + // (because now buffer might output invalid geometries) + continue; + } + + int const region0 = get_region_id(turn.operations[0]); + int const region1 = get_region_id(turn.operations[1]); + + // Switch sources for same region + turn.switch_source = region0 == region1; + } + + +#if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR) + std::cout << "SWITCH END ITERATION" << std::endl; + + for (std::size_t turn_index = 0; turn_index < m_turns.size(); ++turn_index) + { + turn_type const& turn = m_turns[turn_index]; + + if (turn.both(operation_union) && turn.cluster_id < 0) + { + std::cout << "UU SWITCH RESULT " + << turn_index << " -> " + << turn.switch_source << std::endl; + } + } + + for (typename Clusters::const_iterator it = m_clusters.begin(); it != m_clusters.end(); ++it) + { + cluster_info const& cinfo = it->second; + if (cinfo.open_count > 1) + { + std::cout << "CL SWITCH RESULT " << it->first + << " -> " << cinfo.switch_source << std::endl; + } + else + { + std::cout << "CL SWITCH RESULT " << it->first + << " is not registered as open" << std::endl; + } + } +#endif + + } + +private: + + Geometry1 const& m_geometry1; + Geometry2 const& m_geometry2; + Turns& m_turns; + Clusters& m_clusters; + RobustPolicy const& m_robust_policy; + Visitor& m_visitor; + + std::map m_regions; + std::map > m_turns_per_ring; + int m_region_id; + +}; + +}} // namespace detail::overlay +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_SWITCH_DETECTOR_HPP diff --git a/include/boost/geometry/algorithms/detail/overlay/traverse.hpp b/include/boost/geometry/algorithms/detail/overlay/traverse.hpp index a8f423212..2d2933ebd 100644 --- a/include/boost/geometry/algorithms/detail/overlay/traverse.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/traverse.hpp @@ -11,26 +11,10 @@ #include -#include - #include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include -#if defined(BOOST_GEOMETRY_DEBUG_INTERSECTION) \ - || defined(BOOST_GEOMETRY_OVERLAY_REPORT_WKT) \ - || defined(BOOST_GEOMETRY_DEBUG_TRAVERSE) -# include -# include -# include -#endif namespace boost { namespace geometry { @@ -39,768 +23,6 @@ namespace boost { namespace geometry namespace detail { namespace overlay { -template -#ifdef BOOST_GEOMETRY_DEBUG_TRAVERSE -inline void debug_traverse(Turn const& turn, Operation op, - std::string const& header) -{ - std::cout << header - << " at " << op.seg_id - << " meth: " << method_char(turn.method) - << " op: " << operation_char(op.operation) - << " vis: " << visited_char(op.visited) - << " of: " << operation_char(turn.operations[0].operation) - << operation_char(turn.operations[1].operation) - << " " << geometry::wkt(turn.point) - << std::endl; - - if (boost::contains(header, "Finished")) - { - std::cout << std::endl; - } -} -#else -inline void debug_traverse(Turn const& , Operation, const char*) -{ -} -#endif - - -//! Metafunction to define side_order (clockwise, ccw) by operation_type -template -struct side_compare {}; - -template <> -struct side_compare -{ - typedef std::greater type; -}; - -template <> -struct side_compare -{ - typedef std::less type; -}; - - -template -< - bool Reverse1, - bool Reverse2, - operation_type OperationType, - typename Geometry1, - typename Geometry2, - typename Turns, - typename Clusters, - typename RobustPolicy, - typename Visitor, - typename Backtrack -> -struct traversal -{ - typedef typename side_compare::type side_compare_type; - typedef typename boost::range_value::type turn_type; - typedef typename turn_type::turn_operation_type turn_operation_type; - - typedef typename geometry::point_type::type point_type; - typedef sort_by_side::side_sorter - < - Reverse1, Reverse2, - point_type, side_compare_type - > sbs_type; - - inline traversal(Geometry1 const& geometry1, Geometry2 const& geometry2, - Turns& turns, Clusters const& clusters, - RobustPolicy const& robust_policy, Visitor& visitor) - : m_geometry1(geometry1) - , m_geometry2(geometry2) - , m_turns(turns) - , m_clusters(clusters) - , m_robust_policy(robust_policy) - , m_visitor(visitor) - , m_has_uu(false) - , m_has_only_uu(true) - , m_switch_at_uu(true) - {} - - - inline bool select_source(signed_size_type turn_index, - segment_identifier const& seg_id1, - segment_identifier const& seg_id2) - { - if (OperationType == operation_intersection) - { - // For intersections always switch sources - return seg_id1.source_index != seg_id2.source_index; - } - else if (OperationType == operation_union) - { - // For uu, only switch sources if indicated - turn_type const& turn = m_turns[turn_index]; - - // TODO: pass this information - bool const is_buffer - = turn.operations[0].seg_id.source_index - == turn.operations[1].seg_id.source_index; - - if (is_buffer) - { - // Buffer does not use source_index (always 0) - return turn.switch_source - ? seg_id1.multi_index != seg_id2.multi_index - : seg_id1.multi_index == seg_id2.multi_index; - } - - // Temporarily use m_switch_at_uu, which does not solve all cases, - // but the majority of the more simple cases, making the interior - // rings valid - return m_switch_at_uu // turn.switch_source - ? seg_id1.source_index != seg_id2.source_index - : seg_id1.source_index == seg_id2.source_index; - } - return false; - } - - inline - signed_size_type get_next_turn_index(turn_operation_type const& op) const - { - return op.enriched.next_ip_index == -1 - ? op.enriched.travels_to_ip_index - : op.enriched.next_ip_index; - } - - inline bool traverse_possible(signed_size_type turn_index) const - { - if (turn_index == -1) - { - return false; - } - - turn_type const& turn = m_turns[turn_index]; - - // It is not a dead end if there is an operation to continue, or of - // there is a cluster (assuming for now we can get out of the cluster) - return turn.cluster_id >= 0 - || turn.has(OperationType) - || turn.has(operation_continue); - } - - inline bool select_operation(turn_type& turn, - signed_size_type start_turn_index, - segment_identifier const& seg_id, - int& selected_op_index) - { - if (turn.discarded) - { - return false; - } - - bool result = false; - - typename turn_operation_type::comparable_distance_type - max_remaining_distance = 0; - - selected_op_index = -1; - for (int i = 0; i < 2; i++) - { - turn_operation_type const& op = turn.operations[i]; - if (op.visited.started()) - { - selected_op_index = i; - return true; - } - - signed_size_type const next_turn_index = get_next_turn_index(op); - - // In some cases there are two alternatives. - // For "ii", take the other one (alternate) - // UNLESS the other one is already visited - // For "uu", take the same one (see above); - // For "cc", take either one, but if there is a starting one, - // take that one. If next is dead end, skip that one. - if ( (op.operation == operation_continue - && traverse_possible(next_turn_index) - && ! result) - || (op.operation == OperationType - && ! op.visited.finished() - && (! result - || select_source(next_turn_index, op.seg_id, seg_id) - ) - ) - ) - { - if (op.operation == operation_continue) - { - max_remaining_distance = op.remaining_distance; - } - selected_op_index = i; - debug_traverse(turn, op, " Candidate"); - result = true; - } - - if (op.operation == operation_continue && result) - { - if (next_turn_index == start_turn_index) - { - selected_op_index = i; - debug_traverse(turn, op, " Candidate override (start)"); - } - else if (op.remaining_distance > max_remaining_distance) - { - max_remaining_distance = op.remaining_distance; - selected_op_index = i; - debug_traverse(turn, op, " Candidate override (remaining)"); - } - } - } - - if (result) - { - debug_traverse(turn, turn.operations[selected_op_index], " Accepted"); - } - - return result; - } - - inline bool select_from_cluster(signed_size_type& turn_index, - int& op_index, signed_size_type start_turn_index, - sbs_type const& sbs, bool allow_pass_rank) - { - bool const is_union = OperationType == operation_union; - bool const is_intersection = OperationType == operation_intersection; - - std::size_t selected_rank = 0; - std::size_t min_rank = 0; - bool result = false; - for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++) - { - typename sbs_type::rp const& ranked_point = sbs.m_ranked_points[i]; - if (result && ranked_point.main_rank > selected_rank) - { - return result; - } - - turn_type const& ranked_turn = m_turns[ranked_point.turn_index]; - turn_operation_type const& ranked_op = ranked_turn.operations[ranked_point.op_index]; - - if (result && ranked_op.visited.finalized()) - { - // One of the arcs in the same direction as the selected result - // is already traversed. - return false; - } - - if (! allow_pass_rank && ranked_op.visited.finalized()) - { - // Skip this one, go to next - min_rank = ranked_point.main_rank; - continue; - } - - if (ranked_point.index == sort_by_side::index_to - && (ranked_point.main_rank > min_rank - || ranked_turn.both(operation_continue))) - { - if ((is_union - && ranked_op.enriched.count_left == 0 - && ranked_op.enriched.count_right > 0) - || (is_intersection - && ranked_op.enriched.count_right == 2)) - { - if (result && ranked_point.turn_index != start_turn_index) - { - // Don't override - only override if arrive at start - continue; - } - - turn_index = ranked_point.turn_index; - op_index = ranked_point.op_index; - - if (is_intersection - && ranked_turn.both(operation_intersection) - && ranked_op.visited.finalized()) - { - // Override: - // For a ii turn, even though one operation might be selected, - // it should take the other one if the first one is used in a completed ring - op_index = 1 - ranked_point.op_index; - } - - result = true; - selected_rank = ranked_point.main_rank; - } - else if (! allow_pass_rank) - { - return result; - } - } - } - return result; - } - - inline bool select_turn_from_cluster(signed_size_type& turn_index, - int& op_index, signed_size_type start_turn_index, - point_type const& point) - { - bool const is_union = OperationType == operation_union; - - turn_type const& turn = m_turns[turn_index]; - BOOST_ASSERT(turn.cluster_id >= 0); - - typename Clusters::const_iterator mit = m_clusters.find(turn.cluster_id); - BOOST_ASSERT(mit != m_clusters.end()); - - std::set const& ids = mit->second; - - sbs_type sbs; - sbs.set_origin(point); - - for (typename std::set::const_iterator sit = ids.begin(); - sit != ids.end(); ++sit) - { - signed_size_type cluster_turn_index = *sit; - turn_type const& cluster_turn = m_turns[cluster_turn_index]; - if (cluster_turn.discarded) - { - // Defensive check, discarded turns should not be in cluster - continue; - } - - for (int i = 0; i < 2; i++) - { - sbs.add(cluster_turn.operations[i], cluster_turn_index, i, - m_geometry1, m_geometry2, false); - } - } - - sbs.apply(turn.point); - - int open_count = 0; - if (is_union) - { - // Check how many open spaces there are. - // TODO: might be moved to sbs itself, though it also uses turns - - std::size_t last_rank = 0; - for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++) - { - typename sbs_type::rp const& ranked_point = sbs.m_ranked_points[i]; - - if (ranked_point.main_rank > last_rank - && ranked_point.index == sort_by_side::index_to) - { - turn_type const& ranked_turn = m_turns[ranked_point.turn_index]; - turn_operation_type const& ranked_op = ranked_turn.operations[ranked_point.op_index]; - if (ranked_op.enriched.count_left == 0 - && ranked_op.enriched.count_right > 0) - { - open_count++; - last_rank = ranked_point.main_rank; - } - } - } - } - - bool allow = false; - if (open_count > 1) - { - sbs.reverse(); - allow = true; - } - - return select_from_cluster(turn_index, op_index, start_turn_index, sbs, allow); - } - - inline void change_index_for_self_turn(signed_size_type& to_vertex_index, - turn_type const& start_turn, - turn_operation_type const& start_op, - int start_op_index) - { - turn_operation_type const& other_op - = start_turn.operations[1 - start_op_index]; - if (start_op.seg_id.source_index != other_op.seg_id.source_index) - { - // Not a buffer/self-turn - return; - } - - // It travels to itself, can happen. If this is a buffer, it can - // sometimes travel to itself in the following configuration: - // - // +---->--+ - // | | - // | +---*----+ *: one turn, with segment index 2/7 - // | | | | - // | +---C | C: closing point (start/end) - // | | - // +------------+ - // - // If it starts on segment 2 and travels to itself on segment 2, that - // should be corrected to 7 because that is the shortest path - // - // Also a uu turn (touching with another buffered ring) might have this - // apparent configuration, but there it should - // always travel the whole ring - - bool const correct - = ! start_turn.both(operation_union) - && start_op.seg_id.segment_index == to_vertex_index; - -#if defined(BOOST_GEOMETRY_DEBUG_TRAVERSE) - std::cout << " WARNING: self-buffer " - << " correct=" << correct - << " turn=" << operation_char(start_turn.operations[0].operation) - << operation_char(start_turn.operations[1].operation) - << " start=" << start_op.seg_id.segment_index - << " from=" << to_vertex_index - << " to=" << other_op.enriched.travels_to_vertex_index - << std::endl; -#endif - - if (correct) - { - to_vertex_index = other_op.enriched.travels_to_vertex_index; - } - } - - template - inline traverse_error_type travel_to_next_turn(signed_size_type start_turn_index, - int start_op_index, - signed_size_type& turn_index, - int& op_index, - segment_identifier& seg_id, - Ring& current_ring, - bool is_start) - { - int const previous_op_index = op_index; - signed_size_type const previous_turn_index = turn_index; - turn_type& previous_turn = m_turns[turn_index]; - turn_operation_type& previous_op = previous_turn.operations[op_index]; - - // If there is no next IP on this segment - if (previous_op.enriched.next_ip_index < 0) - { - if (previous_op.enriched.travels_to_vertex_index < 0 - || previous_op.enriched.travels_to_ip_index < 0) - { - return is_start - ? traverse_error_no_next_ip_at_start - : traverse_error_no_next_ip; - } - - signed_size_type to_vertex_index = previous_op.enriched.travels_to_vertex_index; - - if (is_start && - previous_op.enriched.travels_to_ip_index == start_turn_index) - { - change_index_for_self_turn(to_vertex_index, previous_turn, - previous_op, start_op_index); - } - - if (previous_op.seg_id.source_index == 0) - { - geometry::copy_segments(m_geometry1, - previous_op.seg_id, to_vertex_index, - m_robust_policy, current_ring); - } - else - { - geometry::copy_segments(m_geometry2, - previous_op.seg_id, to_vertex_index, - m_robust_policy, current_ring); - } - seg_id = previous_op.seg_id; - turn_index = previous_op.enriched.travels_to_ip_index; - } - else - { - turn_index = previous_op.enriched.next_ip_index; - seg_id = previous_op.seg_id; - } - - // turn_index is not yet finally selected, can change for clusters - bool const has_cluster = m_turns[turn_index].cluster_id >= 0; - if (has_cluster) - { - - if (! select_turn_from_cluster(turn_index, op_index, - start_turn_index, current_ring.back())) - { - return is_start - ? traverse_error_no_next_ip_at_start - : traverse_error_no_next_ip; - } - - if (is_start && turn_index == previous_turn_index) - { - op_index = previous_op_index; - } - } - - turn_type& current_turn = m_turns[turn_index]; - detail::overlay::append_no_dups_or_spikes(current_ring, current_turn.point, - m_robust_policy); - - if (is_start) - { - // Register the start - previous_op.visited.set_started(); - m_visitor.visit_traverse(m_turns, previous_turn, previous_op, "Start"); - } - - if (! has_cluster) - { - if (! select_operation(current_turn, - start_turn_index, - seg_id, - op_index)) - { - return is_start - ? traverse_error_dead_end_at_start - : traverse_error_dead_end; - } - } - - turn_operation_type& op = current_turn.operations[op_index]; - if (op.visited.finalized() || op.visited.visited()) - { - return traverse_error_visit_again; - } - - // Register the visit - set_visited(current_turn, op); - m_visitor.visit_traverse(m_turns, current_turn, op, "Visit"); - - return traverse_error_none; - } - - inline void finalize_visit_info() - { - for (typename boost::range_iterator::type - it = boost::begin(m_turns); - it != boost::end(m_turns); - ++it) - { - turn_type& turn = *it; - for (int i = 0; i < 2; i++) - { - turn_operation_type& op = turn.operations[i]; - op.visited.finalize(); - } - } - } - - inline void set_visited(turn_type& turn, turn_operation_type& op) - { - // On "continue", set "visited" for ALL directions in this turn - if (op.operation == detail::overlay::operation_continue) - { - for (int i = 0; i < 2; i++) - { - turn_operation_type& op = turn.operations[i]; - if (op.visited.none()) - { - op.visited.set_visited(); - } - } - } - else - { - op.visited.set_visited(); - } - } - - - template - inline traverse_error_type traverse(Ring& ring, - signed_size_type start_turn_index, int start_op_index) - { - turn_type const& start_turn = m_turns[start_turn_index]; - turn_operation_type& start_op = m_turns[start_turn_index].operations[start_op_index]; - - detail::overlay::append_no_dups_or_spikes(ring, start_turn.point, - m_robust_policy); - - signed_size_type current_turn_index = start_turn_index; - int current_op_index = start_op_index; - segment_identifier current_seg_id; - - traverse_error_type error = travel_to_next_turn(start_turn_index, - start_op_index, - current_turn_index, current_op_index, current_seg_id, - ring, true); - - if (error != traverse_error_none) - { - // This is not necessarily a problem, it happens for clustered turns - // which are "build in" or otherwise point inwards - return error; - } - - if (current_turn_index == start_turn_index) - { - start_op.visited.set_finished(); - m_visitor.visit_traverse(m_turns, m_turns[current_turn_index], start_op, "Early finish"); - return traverse_error_none; - } - - std::size_t const max_iterations = 2 + 2 * m_turns.size(); - for (std::size_t i = 0; i <= max_iterations; i++) - { - // We assume clockwise polygons only, non self-intersecting, closed. - // However, the input might be different, and checking validity - // is up to the library user. - - // Therefore we make here some sanity checks. If the input - // violates the assumptions, the output polygon will not be correct - // but the routine will stop and output the current polygon, and - // will continue with the next one. - - // Below three reasons to stop. - error = travel_to_next_turn(start_turn_index, start_op_index, - current_turn_index, current_op_index, current_seg_id, - ring, false); - - if (error != traverse_error_none) - { - return error; - } - - if (current_turn_index == start_turn_index - && current_op_index == start_op_index) - { - start_op.visited.set_finished(); - m_visitor.visit_traverse(m_turns, start_turn, start_op, "Finish"); - return traverse_error_none; - } - } - - return traverse_error_endless_loop; - } - - template - void traverse_with_operation(turn_type const& start_turn, - std::size_t turn_index, int op_index, - Rings& rings, std::size_t& finalized_ring_size, - typename Backtrack::state_type& state) - { - typedef typename boost::range_value::type ring_type; - - turn_operation_type const& start_op = start_turn.operations[op_index]; - - if (! start_op.visited.none() - || ! start_op.enriched.startable - || start_op.visited.rejected() - || ! (start_op.operation == OperationType - || start_op.operation == detail::overlay::operation_continue)) - { - return; - } - - ring_type ring; - traverse_error_type traverse_error = traverse(ring, turn_index, op_index); - - if (traverse_error == traverse_error_none) - { - std::size_t const min_num_points - = core_detail::closure::minimum_ring_size - < - geometry::closure::value - >::value; - - if (geometry::num_points(ring) >= min_num_points) - { - clean_closing_dups_and_spikes(ring, m_robust_policy); - rings.push_back(ring); - - finalize_visit_info(); - finalized_ring_size++; - } - } - else - { - Backtrack::apply( - finalized_ring_size, - rings, ring, m_turns, start_turn, - m_turns[turn_index].operations[op_index], - traverse_error, - m_geometry1, m_geometry2, m_robust_policy, - state, m_visitor); - } - } - - template - void iterate(Rings& rings, std::size_t& finalized_ring_size, - typename Backtrack::state_type& state, - int pass) - { - if (pass == 1) - { - if (OperationType == operation_intersection) - { - // Second pass currently only used for uu - return; - } - if (! m_has_uu) - { - // There is no uu found in first pass - return; - } - if (m_has_only_uu) - { - m_switch_at_uu = false; - } - } - - // Iterate through all unvisited points - for (std::size_t turn_index = 0; turn_index < m_turns.size(); ++turn_index) - { - turn_type const& start_turn = m_turns[turn_index]; - - if (start_turn.discarded || start_turn.blocked()) - { - // Skip discarded and blocked turns - continue; - } - if (OperationType == operation_union) - { - if (start_turn.both(operation_union)) - { - // Start with a uu-turn only in the second pass - m_has_uu = true; - if (pass == 0) - { - continue; - } - } - else - { - m_has_only_uu = false; - } - } - - for (int op_index = 0; op_index < 2; op_index++) - { - traverse_with_operation(start_turn, turn_index, op_index, - rings, finalized_ring_size, state); - } - } - } - -private : - Geometry1 const& m_geometry1; - Geometry2 const& m_geometry2; - Turns& m_turns; - Clusters const& m_clusters; - RobustPolicy const& m_robust_policy; - Visitor& m_visitor; - - // Next members are only used for operation union - bool m_has_uu; - bool m_has_only_uu; - bool m_switch_at_uu; -}; - /*! \brief Traverses through intersection points / geometries @@ -811,11 +33,28 @@ template bool Reverse1, bool Reverse2, typename Geometry1, typename Geometry2, - operation_type OperationType, + overlay_type OverlayType, typename Backtrack = backtrack_check_self_intersections > class traverse { + + template + static void reset_visits(Turns& turns) + { + for (typename boost::range_iterator::type + it = boost::begin(turns); + it != boost::end(turns); + ++it) + { + for (int i = 0; i < 2; i++) + { + it->operations[i].visited.reset(); + } + } + } + + public : template < @@ -829,12 +68,24 @@ public : Geometry2 const& geometry2, RobustPolicy const& robust_policy, Turns& turns, Rings& rings, - Clusters const& clusters, + Clusters& clusters, Visitor& visitor) { - traversal + traversal_switch_detector < - Reverse1, Reverse2, OperationType, + Reverse1, Reverse2, OverlayType, + Geometry1, Geometry2, + Turns, Clusters, + RobustPolicy, Visitor + > switch_detector(geometry1, geometry2, turns, clusters, + robust_policy, visitor); + + switch_detector.iterate(); + reset_visits(turns); + + traversal_ring_creator + < + Reverse1, Reverse2, OverlayType, Geometry1, Geometry2, Turns, Clusters, RobustPolicy, Visitor, diff --git a/include/boost/geometry/algorithms/detail/overlay/turn_info.hpp b/include/boost/geometry/algorithms/detail/overlay/turn_info.hpp index 699997fc3..d9f5a7d13 100644 --- a/include/boost/geometry/algorithms/detail/overlay/turn_info.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/turn_info.hpp @@ -13,7 +13,9 @@ #include #include +#include #include +#include namespace boost { namespace geometry { @@ -22,18 +24,6 @@ namespace boost { namespace geometry namespace detail { namespace overlay { - -enum operation_type -{ - operation_none, - operation_union, - operation_intersection, - operation_blocked, - operation_continue, - operation_opposite -}; - - enum method_type { method_none, @@ -99,7 +89,7 @@ struct turn_info Point point; method_type method; - int cluster_id; + signed_size_type cluster_id; bool discarded; bool colocated; bool switch_source; // For u/u turns which can either switch or not diff --git a/include/boost/geometry/algorithms/detail/overlay/visit_info.hpp b/include/boost/geometry/algorithms/detail/overlay/visit_info.hpp index 9e1e6b905..e401fbbb4 100644 --- a/include/boost/geometry/algorithms/detail/overlay/visit_info.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/visit_info.hpp @@ -61,6 +61,11 @@ public: } } + inline void reset() + { + *this = visit_info(); + } + inline void finalize() { if (visited() || started() || finished() ) diff --git a/include/boost/geometry/algorithms/detail/point_on_border.hpp b/include/boost/geometry/algorithms/detail/point_on_border.hpp index 24b88a8d1..1c751c23e 100644 --- a/include/boost/geometry/algorithms/detail/point_on_border.hpp +++ b/include/boost/geometry/algorithms/detail/point_on_border.hpp @@ -286,8 +286,8 @@ inline bool point_on_border(Point& point, Geometry const& geometry, bool midpoint = false) { - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); return dispatch::point_on_border < diff --git a/include/boost/geometry/algorithms/detail/recalculate.hpp b/include/boost/geometry/algorithms/detail/recalculate.hpp index fd3ed6b8d..b75dd135e 100644 --- a/include/boost/geometry/algorithms/detail/recalculate.hpp +++ b/include/boost/geometry/algorithms/detail/recalculate.hpp @@ -219,8 +219,8 @@ struct recalculate template inline void recalculate(Geometry1& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); // static assert dimensions (/types) are the same diff --git a/include/boost/geometry/algorithms/detail/relate/interface.hpp b/include/boost/geometry/algorithms/detail/relate/interface.hpp index e2c067b68..95d452931 100644 --- a/include/boost/geometry/algorithms/detail/relate/interface.hpp +++ b/include/boost/geometry/algorithms/detail/relate/interface.hpp @@ -199,8 +199,8 @@ struct relate Geometry2 const& geometry2, Mask const& mask) { - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); assert_dimension_equal(); typename detail::relate::result_handler_type diff --git a/include/boost/geometry/algorithms/detail/relation/interface.hpp b/include/boost/geometry/algorithms/detail/relation/interface.hpp index 73737cf2c..e9a947455 100644 --- a/include/boost/geometry/algorithms/detail/relation/interface.hpp +++ b/include/boost/geometry/algorithms/detail/relation/interface.hpp @@ -46,8 +46,8 @@ struct relation static inline Matrix apply(Geometry1 const& geometry1, Geometry2 const& geometry2) { - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); assert_dimension_equal(); typename detail::relate::result_handler_type diff --git a/include/boost/geometry/algorithms/detail/ring_identifier.hpp b/include/boost/geometry/algorithms/detail/ring_identifier.hpp index 9ba39e4a8..4a7e717cf 100644 --- a/include/boost/geometry/algorithms/detail/ring_identifier.hpp +++ b/include/boost/geometry/algorithms/detail/ring_identifier.hpp @@ -56,6 +56,11 @@ struct ring_identifier ; } + inline bool operator!=(ring_identifier const& other) const + { + return ! operator==(other); + } + #if defined(BOOST_GEOMETRY_DEBUG_IDENTIFIER) friend std::ostream& operator<<(std::ostream &os, ring_identifier const& ring_id) { diff --git a/include/boost/geometry/algorithms/detail/sections/range_by_section.hpp b/include/boost/geometry/algorithms/detail/sections/range_by_section.hpp index 02cec6cb4..611ad172d 100644 --- a/include/boost/geometry/algorithms/detail/sections/range_by_section.hpp +++ b/include/boost/geometry/algorithms/detail/sections/range_by_section.hpp @@ -177,7 +177,7 @@ template inline typename ring_return_type::type range_by_section(Geometry const& geometry, Section const& section) { - concept::check(); + concepts::check(); return dispatch::range_by_section < diff --git a/include/boost/geometry/algorithms/detail/sections/sectionalize.hpp b/include/boost/geometry/algorithms/detail/sections/sectionalize.hpp index 39c7894e2..3ed5b8db0 100644 --- a/include/boost/geometry/algorithms/detail/sections/sectionalize.hpp +++ b/include/boost/geometry/algorithms/detail/sections/sectionalize.hpp @@ -822,7 +822,7 @@ inline void sectionalize(Geometry const& geometry, int source_index = 0, std::size_t max_count = 10) { - concept::check(); + concepts::check(); typedef typename boost::range_value::type section_type; diff --git a/include/boost/geometry/algorithms/detail/within/point_in_geometry.hpp b/include/boost/geometry/algorithms/detail/within/point_in_geometry.hpp index 68e74a8c5..a73364c33 100644 --- a/include/boost/geometry/algorithms/detail/within/point_in_geometry.hpp +++ b/include/boost/geometry/algorithms/detail/within/point_in_geometry.hpp @@ -400,7 +400,7 @@ namespace detail { namespace within { template inline int point_in_geometry(Point const& point, Geometry const& geometry, Strategy const& strategy) { - concept::within::check + concepts::within::check < typename tag::type, typename tag::type, diff --git a/include/boost/geometry/algorithms/difference.hpp b/include/boost/geometry/algorithms/difference.hpp index 8fec85e7c..f7ca48cbe 100644 --- a/include/boost/geometry/algorithms/difference.hpp +++ b/include/boost/geometry/algorithms/difference.hpp @@ -54,9 +54,9 @@ inline OutputIterator difference_insert(Geometry1 const& geometry1, OutputIterator out, Strategy const& strategy) { - concept::check(); - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); + concepts::check(); return geometry::dispatch::intersection_insert < @@ -97,9 +97,9 @@ inline OutputIterator difference_insert(Geometry1 const& geometry1, RobustPolicy const& robust_policy, OutputIterator out) { - concept::check(); - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); + concepts::check(); typedef intersection_strategies < @@ -142,11 +142,11 @@ template inline void difference(Geometry1 const& geometry1, Geometry2 const& geometry2, Collection& output_collection) { - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); typedef typename boost::range_value::type geometry_out; - concept::check(); + concepts::check(); typedef typename geometry::rescale_overlay_policy_type < diff --git a/include/boost/geometry/algorithms/equals.hpp b/include/boost/geometry/algorithms/equals.hpp index 138f3218b..d04d5c7f3 100644 --- a/include/boost/geometry/algorithms/equals.hpp +++ b/include/boost/geometry/algorithms/equals.hpp @@ -352,7 +352,7 @@ struct equals static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2) { - concept::check_concepts_and_equal_dimensions + concepts::check_concepts_and_equal_dimensions < Geometry1 const, Geometry2 const diff --git a/include/boost/geometry/algorithms/for_each.hpp b/include/boost/geometry/algorithms/for_each.hpp index c5c099b1a..741dc359f 100644 --- a/include/boost/geometry/algorithms/for_each.hpp +++ b/include/boost/geometry/algorithms/for_each.hpp @@ -337,7 +337,7 @@ struct for_each_segment template inline Functor for_each_point(Geometry& geometry, Functor f) { - concept::check(); + concepts::check(); dispatch::for_each_point::apply(geometry, f); return f; @@ -360,7 +360,7 @@ inline Functor for_each_point(Geometry& geometry, Functor f) template inline Functor for_each_segment(Geometry& geometry, Functor f) { - concept::check(); + concepts::check(); dispatch::for_each_segment::apply(geometry, f); return f; diff --git a/include/boost/geometry/algorithms/intersects.hpp b/include/boost/geometry/algorithms/intersects.hpp index 1bb85aa3b..5349db76b 100644 --- a/include/boost/geometry/algorithms/intersects.hpp +++ b/include/boost/geometry/algorithms/intersects.hpp @@ -49,7 +49,7 @@ namespace boost { namespace geometry template inline bool intersects(Geometry const& geometry) { - concept::check(); + concepts::check(); typedef typename geometry::point_type::type point_type; typedef detail::no_rescale_policy rescale_policy_type; @@ -93,8 +93,8 @@ inline bool intersects(Geometry const& geometry) template inline bool intersects(Geometry1 const& geometry1, Geometry2 const& geometry2) { - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); return ! geometry::disjoint(geometry1, geometry2); } diff --git a/include/boost/geometry/algorithms/is_empty.hpp b/include/boost/geometry/algorithms/is_empty.hpp index 02c295eab..8dab69c87 100644 --- a/include/boost/geometry/algorithms/is_empty.hpp +++ b/include/boost/geometry/algorithms/is_empty.hpp @@ -157,7 +157,7 @@ struct is_empty { static inline bool apply(Geometry const& geometry) { - concept::check(); + concepts::check(); return dispatch::is_empty::apply(geometry); } diff --git a/include/boost/geometry/algorithms/length.hpp b/include/boost/geometry/algorithms/length.hpp index cf5234da1..39a567a26 100644 --- a/include/boost/geometry/algorithms/length.hpp +++ b/include/boost/geometry/algorithms/length.hpp @@ -251,7 +251,7 @@ template inline typename default_length_result::type length(Geometry const& geometry) { - concept::check(); + concepts::check(); // detail::throw_on_empty_input(geometry); @@ -283,7 +283,7 @@ template inline typename default_length_result::type length(Geometry const& geometry, Strategy const& strategy) { - concept::check(); + concepts::check(); // detail::throw_on_empty_input(geometry); diff --git a/include/boost/geometry/algorithms/make.hpp b/include/boost/geometry/algorithms/make.hpp index d0e309249..899d5489b 100644 --- a/include/boost/geometry/algorithms/make.hpp +++ b/include/boost/geometry/algorithms/make.hpp @@ -45,7 +45,7 @@ namespace detail { namespace make template inline Geometry make_points(Range const& range) { - concept::check(); + concepts::check(); Geometry geometry; geometry::append(geometry, range); @@ -78,7 +78,7 @@ inline Geometry make_points(Range const& range) template inline Geometry make(Type const& c1, Type const& c2) { - concept::check(); + concepts::check(); Geometry geometry; dispatch::assign @@ -112,7 +112,7 @@ inline Geometry make(Type const& c1, Type const& c2) template inline Geometry make(Type const& c1, Type const& c2, Type const& c3) { - concept::check(); + concepts::check(); Geometry geometry; dispatch::assign @@ -127,7 +127,7 @@ inline Geometry make(Type const& c1, Type const& c2, Type const& c3) template inline Geometry make(Type const& c1, Type const& c2, Type const& c3, Type const& c4) { - concept::check(); + concepts::check(); Geometry geometry; dispatch::assign @@ -163,7 +163,7 @@ inline Geometry make(Type const& c1, Type const& c2, Type const& c3, Type const& template inline Geometry make_inverse() { - concept::check(); + concepts::check(); Geometry geometry; dispatch::assign_inverse @@ -184,7 +184,7 @@ inline Geometry make_inverse() template inline Geometry make_zero() { - concept::check(); + concepts::check(); Geometry geometry; dispatch::assign_zero diff --git a/include/boost/geometry/algorithms/num_geometries.hpp b/include/boost/geometry/algorithms/num_geometries.hpp index 8144c22ab..e122241fe 100644 --- a/include/boost/geometry/algorithms/num_geometries.hpp +++ b/include/boost/geometry/algorithms/num_geometries.hpp @@ -90,7 +90,7 @@ struct num_geometries { static inline std::size_t apply(Geometry const& geometry) { - concept::check(); + concepts::check(); return dispatch::num_geometries::apply(geometry); } diff --git a/include/boost/geometry/algorithms/num_interior_rings.hpp b/include/boost/geometry/algorithms/num_interior_rings.hpp index 04b4eb2a7..b7531a3dd 100644 --- a/include/boost/geometry/algorithms/num_interior_rings.hpp +++ b/include/boost/geometry/algorithms/num_interior_rings.hpp @@ -88,7 +88,7 @@ struct num_interior_rings { static inline std::size_t apply(Geometry const& geometry) { - concept::check(); + concepts::check(); return dispatch::num_interior_rings::apply(geometry); } diff --git a/include/boost/geometry/algorithms/num_points.hpp b/include/boost/geometry/algorithms/num_points.hpp index 214fe9c8b..9ef77f271 100644 --- a/include/boost/geometry/algorithms/num_points.hpp +++ b/include/boost/geometry/algorithms/num_points.hpp @@ -149,7 +149,7 @@ struct num_points static inline std::size_t apply(Geometry const& geometry, bool add_for_open) { - concept::check(); + concepts::check(); return add_for_open ? dispatch::num_points::apply(geometry) diff --git a/include/boost/geometry/algorithms/num_segments.hpp b/include/boost/geometry/algorithms/num_segments.hpp index 08af226ca..86eb63fad 100644 --- a/include/boost/geometry/algorithms/num_segments.hpp +++ b/include/boost/geometry/algorithms/num_segments.hpp @@ -150,7 +150,7 @@ struct num_segments { static inline std::size_t apply(Geometry const& geometry) { - concept::check(); + concepts::check(); return dispatch::num_segments::apply(geometry); } diff --git a/include/boost/geometry/algorithms/overlaps.hpp b/include/boost/geometry/algorithms/overlaps.hpp index 9b5abdb2a..32738c294 100644 --- a/include/boost/geometry/algorithms/overlaps.hpp +++ b/include/boost/geometry/algorithms/overlaps.hpp @@ -184,8 +184,8 @@ struct overlaps template inline bool overlaps(Geometry1 const& geometry1, Geometry2 const& geometry2) { - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); return dispatch::overlaps < diff --git a/include/boost/geometry/algorithms/perimeter.hpp b/include/boost/geometry/algorithms/perimeter.hpp index 1b5ccacf9..47b064972 100644 --- a/include/boost/geometry/algorithms/perimeter.hpp +++ b/include/boost/geometry/algorithms/perimeter.hpp @@ -142,7 +142,7 @@ struct perimeter static inline typename default_length_result::type apply(Geometry const& geometry, Strategy const& strategy) { - concept::check(); + concepts::check(); return resolve_strategy::perimeter::apply(geometry, strategy); } }; diff --git a/include/boost/geometry/algorithms/point_on_surface.hpp b/include/boost/geometry/algorithms/point_on_surface.hpp index 3fa83bfe6..e9041f937 100644 --- a/include/boost/geometry/algorithms/point_on_surface.hpp +++ b/include/boost/geometry/algorithms/point_on_surface.hpp @@ -295,8 +295,8 @@ inline bool calculate_point_on_surface(Geometry const& geometry, Point& point) template inline void point_on_surface(Geometry const& geometry, Point & point) { - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); // First try in Y-direction (which should always succeed for valid polygons) if (! detail::point_on_surface::calculate_point_on_surface<1>(geometry, point)) diff --git a/include/boost/geometry/algorithms/remove_spikes.hpp b/include/boost/geometry/algorithms/remove_spikes.hpp index 080db92f6..caa7fed9b 100644 --- a/include/boost/geometry/algorithms/remove_spikes.hpp +++ b/include/boost/geometry/algorithms/remove_spikes.hpp @@ -241,7 +241,7 @@ struct remove_spikes { static void apply(Geometry& geometry) { - concept::check(); + concepts::check(); dispatch::remove_spikes::apply(geometry); } }; diff --git a/include/boost/geometry/algorithms/reverse.hpp b/include/boost/geometry/algorithms/reverse.hpp index 578771bfe..dc7d2de42 100644 --- a/include/boost/geometry/algorithms/reverse.hpp +++ b/include/boost/geometry/algorithms/reverse.hpp @@ -137,7 +137,7 @@ struct reverse { static void apply(Geometry& geometry) { - concept::check(); + concepts::check(); dispatch::reverse::apply(geometry); } }; diff --git a/include/boost/geometry/algorithms/simplify.hpp b/include/boost/geometry/algorithms/simplify.hpp index 0b28eb7d1..cfeb54222 100644 --- a/include/boost/geometry/algorithms/simplify.hpp +++ b/include/boost/geometry/algorithms/simplify.hpp @@ -333,7 +333,7 @@ struct simplify > strategy_type; BOOST_CONCEPT_ASSERT( - (concept::SimplifyStrategy) + (concepts::SimplifyStrategy) ); apply(geometry, out, max_distance, strategy_type()); @@ -376,7 +376,7 @@ struct simplify_insert > strategy_type; BOOST_CONCEPT_ASSERT( - (concept::SimplifyStrategy) + (concepts::SimplifyStrategy) ); apply(geometry, out, max_distance, strategy_type()); @@ -461,7 +461,7 @@ template inline void simplify(Geometry const& geometry, Geometry& out, Distance const& max_distance, Strategy const& strategy) { - concept::check(); + concepts::check(); geometry::clear(out); @@ -489,7 +489,7 @@ template inline void simplify(Geometry const& geometry, Geometry& out, Distance const& max_distance) { - concept::check(); + concepts::check(); geometry::simplify(geometry, out, max_distance, default_strategy()); } @@ -519,7 +519,7 @@ template(); + concepts::check(); resolve_strategy::simplify_insert::apply(geometry, out, max_distance, strategy); } @@ -540,8 +540,8 @@ inline void simplify_insert(Geometry const& geometry, OutputIterator out, Distance const& max_distance) { // Concept: output point type = point type of input geometry - concept::check(); - concept::check::type>(); + concepts::check(); + concepts::check::type>(); simplify_insert(geometry, out, max_distance, default_strategy()); } diff --git a/include/boost/geometry/algorithms/sym_difference.hpp b/include/boost/geometry/algorithms/sym_difference.hpp index f56029cc1..33f94c932 100644 --- a/include/boost/geometry/algorithms/sym_difference.hpp +++ b/include/boost/geometry/algorithms/sym_difference.hpp @@ -235,9 +235,9 @@ inline OutputIterator sym_difference_insert(Geometry1 const& geometry1, OutputIterator out, Strategy const& strategy) { - concept::check(); - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); + concepts::check(); return dispatch::sym_difference_insert < @@ -272,9 +272,9 @@ inline OutputIterator sym_difference_insert(Geometry1 const& geometry1, Geometry2 const& geometry2, RobustPolicy const& robust_policy, OutputIterator out) { - concept::check(); - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); + concepts::check(); typedef intersection_strategies < @@ -315,11 +315,11 @@ template inline void sym_difference(Geometry1 const& geometry1, Geometry2 const& geometry2, Collection& output_collection) { - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); typedef typename boost::range_value::type geometry_out; - concept::check(); + concepts::check(); typedef typename geometry::rescale_overlay_policy_type < diff --git a/include/boost/geometry/algorithms/touches.hpp b/include/boost/geometry/algorithms/touches.hpp index 99ddbbd1c..6384cc2a8 100644 --- a/include/boost/geometry/algorithms/touches.hpp +++ b/include/boost/geometry/algorithms/touches.hpp @@ -410,8 +410,8 @@ struct touches { static bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2) { - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); return dispatch::touches ::apply(geometry1, geometry2); @@ -494,7 +494,7 @@ struct self_touches { static bool apply(Geometry const& geometry) { - concept::check(); + concepts::check(); typedef detail::no_rescale_policy rescale_policy_type; typedef typename geometry::point_type::type point_type; diff --git a/include/boost/geometry/algorithms/transform.hpp b/include/boost/geometry/algorithms/transform.hpp index f6748b11e..b514c1dac 100644 --- a/include/boost/geometry/algorithms/transform.hpp +++ b/include/boost/geometry/algorithms/transform.hpp @@ -349,8 +349,8 @@ struct transform Geometry2& geometry2, Strategy const& strategy) { - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); return dispatch::transform::apply( geometry1, diff --git a/include/boost/geometry/algorithms/union.hpp b/include/boost/geometry/algorithms/union.hpp index 29135f5fd..f0e55ec98 100644 --- a/include/boost/geometry/algorithms/union.hpp +++ b/include/boost/geometry/algorithms/union.hpp @@ -204,9 +204,9 @@ inline OutputIterator union_insert(Geometry1 const& geometry1, Geometry2 const& geometry2, OutputIterator out) { - concept::check(); - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); + concepts::check(); typedef typename geometry::rescale_overlay_policy_type < @@ -264,11 +264,11 @@ inline void union_(Geometry1 const& geometry1, Geometry2 const& geometry2, Collection& output_collection) { - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); typedef typename boost::range_value::type geometry_out; - concept::check(); + concepts::check(); detail::union_::union_insert(geometry1, geometry2, range::back_inserter(output_collection)); diff --git a/include/boost/geometry/algorithms/unique.hpp b/include/boost/geometry/algorithms/unique.hpp index fed9f8af4..f57f4505b 100644 --- a/include/boost/geometry/algorithms/unique.hpp +++ b/include/boost/geometry/algorithms/unique.hpp @@ -166,7 +166,7 @@ struct unique template inline void unique(Geometry& geometry) { - concept::check(); + concepts::check(); // Default strategy is the default point-comparison policy typedef geometry::equal_to diff --git a/include/boost/geometry/algorithms/within.hpp b/include/boost/geometry/algorithms/within.hpp index 35f9396ba..a1e6a58f8 100644 --- a/include/boost/geometry/algorithms/within.hpp +++ b/include/boost/geometry/algorithms/within.hpp @@ -284,7 +284,7 @@ struct within Geometry2 const& geometry2, Strategy const& strategy) { - concept::within::check + concepts::within::check < typename tag::type, typename tag::type, @@ -339,8 +339,8 @@ struct within Geometry2 const& geometry2, Strategy const& strategy) { - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); assert_dimension_equal(); return resolve_strategy::within::apply(geometry1, diff --git a/include/boost/geometry/arithmetic/arithmetic.hpp b/include/boost/geometry/arithmetic/arithmetic.hpp index fbc3ca443..3ab66b27f 100644 --- a/include/boost/geometry/arithmetic/arithmetic.hpp +++ b/include/boost/geometry/arithmetic/arithmetic.hpp @@ -139,7 +139,7 @@ struct point_assignment template inline void add_value(Point& p, typename detail::param::type value) { - BOOST_CONCEPT_ASSERT( (concept::Point) ); + BOOST_CONCEPT_ASSERT( (concepts::Point) ); for_each_coordinate(p, detail::value_operation @@ -162,8 +162,8 @@ inline void add_value(Point& p, typename detail::param::type value) template inline void add_point(Point1& p1, Point2 const& p2) { - BOOST_CONCEPT_ASSERT( (concept::Point) ); - BOOST_CONCEPT_ASSERT( (concept::ConstPoint) ); + BOOST_CONCEPT_ASSERT( (concepts::Point) ); + BOOST_CONCEPT_ASSERT( (concepts::ConstPoint) ); for_each_coordinate(p1, detail::point_operation(p2)); } @@ -179,7 +179,7 @@ inline void add_point(Point1& p1, Point2 const& p2) template inline void subtract_value(Point& p, typename detail::param::type value) { - BOOST_CONCEPT_ASSERT( (concept::Point) ); + BOOST_CONCEPT_ASSERT( (concepts::Point) ); for_each_coordinate(p, detail::value_operation @@ -202,8 +202,8 @@ inline void subtract_value(Point& p, typename detail::param::type value) template inline void subtract_point(Point1& p1, Point2 const& p2) { - BOOST_CONCEPT_ASSERT( (concept::Point) ); - BOOST_CONCEPT_ASSERT( (concept::ConstPoint) ); + BOOST_CONCEPT_ASSERT( (concepts::Point) ); + BOOST_CONCEPT_ASSERT( (concepts::ConstPoint) ); for_each_coordinate(p1, detail::point_operation(p2)); } @@ -219,7 +219,7 @@ inline void subtract_point(Point1& p1, Point2 const& p2) template inline void multiply_value(Point& p, typename detail::param::type value) { - BOOST_CONCEPT_ASSERT( (concept::Point) ); + BOOST_CONCEPT_ASSERT( (concepts::Point) ); for_each_coordinate(p, detail::value_operation @@ -243,8 +243,8 @@ inline void multiply_value(Point& p, typename detail::param::type value) template inline void multiply_point(Point1& p1, Point2 const& p2) { - BOOST_CONCEPT_ASSERT( (concept::Point) ); - BOOST_CONCEPT_ASSERT( (concept::ConstPoint) ); + BOOST_CONCEPT_ASSERT( (concepts::Point) ); + BOOST_CONCEPT_ASSERT( (concepts::ConstPoint) ); for_each_coordinate(p1, detail::point_operation(p2)); } @@ -260,7 +260,7 @@ inline void multiply_point(Point1& p1, Point2 const& p2) template inline void divide_value(Point& p, typename detail::param::type value) { - BOOST_CONCEPT_ASSERT( (concept::Point) ); + BOOST_CONCEPT_ASSERT( (concepts::Point) ); for_each_coordinate(p, detail::value_operation @@ -283,8 +283,8 @@ inline void divide_value(Point& p, typename detail::param::type value) template inline void divide_point(Point1& p1, Point2 const& p2) { - BOOST_CONCEPT_ASSERT( (concept::Point) ); - BOOST_CONCEPT_ASSERT( (concept::ConstPoint) ); + BOOST_CONCEPT_ASSERT( (concepts::Point) ); + BOOST_CONCEPT_ASSERT( (concepts::ConstPoint) ); for_each_coordinate(p1, detail::point_operation(p2)); } @@ -300,7 +300,7 @@ inline void divide_point(Point1& p1, Point2 const& p2) template inline void assign_value(Point& p, typename detail::param::type value) { - BOOST_CONCEPT_ASSERT( (concept::Point) ); + BOOST_CONCEPT_ASSERT( (concepts::Point) ); for_each_coordinate(p, detail::value_assignment @@ -322,8 +322,8 @@ inline void assign_value(Point& p, typename detail::param::type value) template inline void assign_point(Point1& p1, Point2 const& p2) { - BOOST_CONCEPT_ASSERT( (concept::Point) ); - BOOST_CONCEPT_ASSERT( (concept::ConstPoint) ); + BOOST_CONCEPT_ASSERT( (concepts::Point) ); + BOOST_CONCEPT_ASSERT( (concepts::ConstPoint) ); for_each_coordinate(p1, detail::point_assignment(p2)); } diff --git a/include/boost/geometry/arithmetic/cross_product.hpp b/include/boost/geometry/arithmetic/cross_product.hpp index ad0a3567f..485c2123b 100644 --- a/include/boost/geometry/arithmetic/cross_product.hpp +++ b/include/boost/geometry/arithmetic/cross_product.hpp @@ -94,9 +94,9 @@ struct cross_product<3> template inline ResultP cross_product(P1 const& p1, P2 const& p2) { - BOOST_CONCEPT_ASSERT( (concept::Point) ); - BOOST_CONCEPT_ASSERT( (concept::ConstPoint) ); - BOOST_CONCEPT_ASSERT( (concept::ConstPoint) ); + BOOST_CONCEPT_ASSERT( (concepts::Point) ); + BOOST_CONCEPT_ASSERT( (concepts::ConstPoint) ); + BOOST_CONCEPT_ASSERT( (concepts::ConstPoint) ); ResultP result; detail::cross_product::value>::apply(p1, p2, result); @@ -114,8 +114,8 @@ inline ResultP cross_product(P1 const& p1, P2 const& p2) template inline P cross_product(P const& p1, P const& p2) { - BOOST_CONCEPT_ASSERT((concept::Point

)); - BOOST_CONCEPT_ASSERT((concept::ConstPoint

)); + BOOST_CONCEPT_ASSERT((concepts::Point

)); + BOOST_CONCEPT_ASSERT((concepts::ConstPoint

)); P result; detail::cross_product::value>::apply(p1, p2, result); diff --git a/include/boost/geometry/arithmetic/determinant.hpp b/include/boost/geometry/arithmetic/determinant.hpp index a8e46ca9a..59c596b12 100644 --- a/include/boost/geometry/arithmetic/determinant.hpp +++ b/include/boost/geometry/arithmetic/determinant.hpp @@ -59,8 +59,8 @@ inline ReturnType determinant(U const& ux, U const& uy template inline ReturnType determinant(U const& u, V const& v) { - BOOST_CONCEPT_ASSERT( (concept::ConstPoint) ); - BOOST_CONCEPT_ASSERT( (concept::ConstPoint) ); + BOOST_CONCEPT_ASSERT( (concepts::ConstPoint) ); + BOOST_CONCEPT_ASSERT( (concepts::ConstPoint) ); return calculate_determinant < diff --git a/include/boost/geometry/arithmetic/dot_product.hpp b/include/boost/geometry/arithmetic/dot_product.hpp index fc2b3844e..747bd01ab 100644 --- a/include/boost/geometry/arithmetic/dot_product.hpp +++ b/include/boost/geometry/arithmetic/dot_product.hpp @@ -69,8 +69,8 @@ template inline typename select_coordinate_type::type dot_product( Point1 const& p1, Point2 const& p2) { - BOOST_CONCEPT_ASSERT( (concept::ConstPoint) ); - BOOST_CONCEPT_ASSERT( (concept::ConstPoint) ); + BOOST_CONCEPT_ASSERT( (concepts::ConstPoint) ); + BOOST_CONCEPT_ASSERT( (concepts::ConstPoint) ); return detail::dot_product_maker < diff --git a/include/boost/geometry/extensions/algebra/algorithms/assign.hpp b/include/boost/geometry/extensions/algebra/algorithms/assign.hpp index d25785de7..ee8486da0 100644 --- a/include/boost/geometry/extensions/algebra/algorithms/assign.hpp +++ b/include/boost/geometry/extensions/algebra/algorithms/assign.hpp @@ -82,7 +82,7 @@ struct assign_identity template inline void assign_identity(Rotation & rotation) { - concept::check(); + concepts::check(); dispatch::assign_identity< typename tag::type, diff --git a/include/boost/geometry/extensions/algebra/algorithms/rotation.hpp b/include/boost/geometry/extensions/algebra/algorithms/rotation.hpp index 2de45254a..dc9e2db2f 100644 --- a/include/boost/geometry/extensions/algebra/algorithms/rotation.hpp +++ b/include/boost/geometry/extensions/algebra/algorithms/rotation.hpp @@ -248,9 +248,9 @@ struct rotation template inline void rotation(V1 const& v1, V2 const& v2, Rotation & r) { - concept::check_concepts_and_equal_dimensions(); + concepts::check_concepts_and_equal_dimensions(); // TODO - replace the following by check_equal_dimensions - concept::check_concepts_and_equal_dimensions(); + concepts::check_concepts_and_equal_dimensions(); dispatch::rotation::apply(v1, v2, r); } diff --git a/include/boost/geometry/extensions/algebra/algorithms/transform_geometrically.hpp b/include/boost/geometry/extensions/algebra/algorithms/transform_geometrically.hpp index 501cdde79..a5fdb86af 100644 --- a/include/boost/geometry/extensions/algebra/algorithms/transform_geometrically.hpp +++ b/include/boost/geometry/extensions/algebra/algorithms/transform_geometrically.hpp @@ -58,8 +58,8 @@ struct transform_geometrically template struct transform_geometrically { - BOOST_CONCEPT_ASSERT( (concept::Point) ); - BOOST_CONCEPT_ASSERT( (concept::Vector) ); + BOOST_CONCEPT_ASSERT( (concepts::Point) ); + BOOST_CONCEPT_ASSERT( (concepts::Vector) ); static inline void apply(Point & point, Vector const& vector) { @@ -90,8 +90,8 @@ struct transform_geometrically { typedef typename traits::point_type::type point_type; - BOOST_CONCEPT_ASSERT( (concept::Point) ); - BOOST_CONCEPT_ASSERT( (concept::Vector) ); + BOOST_CONCEPT_ASSERT( (concepts::Point) ); + BOOST_CONCEPT_ASSERT( (concepts::Vector) ); static inline void apply(Box & box, Vector const& vector) { @@ -124,7 +124,7 @@ struct transform_geometrically(); + concepts::check_concepts_and_equal_dimensions(); detail::algebra::quaternion_rotate(v, r); } @@ -136,7 +136,7 @@ struct transform_geometrically(); + concepts::check_concepts_and_equal_dimensions(); // TODO vector_type and convert from Vector Vector tmp(v); diff --git a/include/boost/geometry/extensions/algebra/algorithms/translation.hpp b/include/boost/geometry/extensions/algebra/algorithms/translation.hpp index feeb3a70c..282616b52 100644 --- a/include/boost/geometry/extensions/algebra/algorithms/translation.hpp +++ b/include/boost/geometry/extensions/algebra/algorithms/translation.hpp @@ -23,9 +23,9 @@ namespace boost { namespace geometry template inline void translation(Point1 const& p1, Point2 const& p2, Vector & v) { - concept::check_concepts_and_equal_dimensions(); + concepts::check_concepts_and_equal_dimensions(); // TODO - replace the following by check_equal_dimensions - concept::check_concepts_and_equal_dimensions(); + concepts::check_concepts_and_equal_dimensions(); for_each_coordinate(v, detail::point_assignment(p2)); for_each_coordinate(v, detail::point_operation(p1)); diff --git a/include/boost/geometry/extensions/algebra/geometries/concepts/check.hpp b/include/boost/geometry/extensions/algebra/geometries/concepts/check.hpp index 606095f11..df0bcb2a6 100644 --- a/include/boost/geometry/extensions/algebra/geometries/concepts/check.hpp +++ b/include/boost/geometry/extensions/algebra/geometries/concepts/check.hpp @@ -30,32 +30,32 @@ namespace dispatch template struct check - : detail::concept_check::check > + : detail::concept_check::check > {}; template struct check - : detail::concept_check::check > + : detail::concept_check::check > {}; template struct check - : detail::concept_check::check > + : detail::concept_check::check > {}; template struct check - : detail::concept_check::check > + : detail::concept_check::check > {}; template struct check - : detail::concept_check::check > + : detail::concept_check::check > {}; template struct check - : detail::concept_check::check > + : detail::concept_check::check > {}; } // namespace dispatch diff --git a/include/boost/geometry/extensions/algebra/geometries/concepts/matrix_concept.hpp b/include/boost/geometry/extensions/algebra/geometries/concepts/matrix_concept.hpp index 0bb880a7e..2203f719c 100644 --- a/include/boost/geometry/extensions/algebra/geometries/concepts/matrix_concept.hpp +++ b/include/boost/geometry/extensions/algebra/geometries/concepts/matrix_concept.hpp @@ -20,7 +20,7 @@ #include #include -namespace boost { namespace geometry { namespace concept { +namespace boost { namespace geometry { namespace concepts { template class Matrix @@ -136,6 +136,6 @@ public: #endif }; -}}} // namespace boost::geometry::concept +}}} // namespace boost::geometry::concepts #endif // BOOST_GEOMETRY_EXTENSIONS_ALGEBRA_GEOMETRIES_CONCEPTS_MATRIX_CONCEPT_HPP diff --git a/include/boost/geometry/extensions/algebra/geometries/concepts/quaternion_concept.hpp b/include/boost/geometry/extensions/algebra/geometries/concepts/quaternion_concept.hpp index 376d83800..91c3ad2b1 100644 --- a/include/boost/geometry/extensions/algebra/geometries/concepts/quaternion_concept.hpp +++ b/include/boost/geometry/extensions/algebra/geometries/concepts/quaternion_concept.hpp @@ -20,7 +20,7 @@ #include #include -namespace boost { namespace geometry { namespace concept { +namespace boost { namespace geometry { namespace concepts { template class Quaternion @@ -106,6 +106,6 @@ public: #endif }; -}}} // namespace boost::geometry::concept +}}} // namespace boost::geometry::concepts #endif // BOOST_GEOMETRY_EXTENSIONS_ALGEBRA_GEOMETRIES_CONCEPTS_QUATERNION_CONCEPT_HPP diff --git a/include/boost/geometry/extensions/algebra/geometries/concepts/rotation_matrix_concept.hpp b/include/boost/geometry/extensions/algebra/geometries/concepts/rotation_matrix_concept.hpp index 8f54f3dd6..89d24e5c4 100644 --- a/include/boost/geometry/extensions/algebra/geometries/concepts/rotation_matrix_concept.hpp +++ b/include/boost/geometry/extensions/algebra/geometries/concepts/rotation_matrix_concept.hpp @@ -20,7 +20,7 @@ #include #include -namespace boost { namespace geometry { namespace concept { +namespace boost { namespace geometry { namespace concepts { template class RotationMatrix @@ -136,6 +136,6 @@ public: #endif }; -}}} // namespace boost::geometry::concept +}}} // namespace boost::geometry::concepts #endif // BOOST_GEOMETRY_EXTENSIONS_ALGEBRA_GEOMETRIES_CONCEPTS_ROTATION_MATRIX_CONCEPT_HPP diff --git a/include/boost/geometry/extensions/algebra/geometries/concepts/rotation_quaternion_concept.hpp b/include/boost/geometry/extensions/algebra/geometries/concepts/rotation_quaternion_concept.hpp index cd0c0661b..ab6425f21 100644 --- a/include/boost/geometry/extensions/algebra/geometries/concepts/rotation_quaternion_concept.hpp +++ b/include/boost/geometry/extensions/algebra/geometries/concepts/rotation_quaternion_concept.hpp @@ -20,7 +20,7 @@ #include #include -namespace boost { namespace geometry { namespace concept { +namespace boost { namespace geometry { namespace concepts { template class RotationQuaternion @@ -106,6 +106,6 @@ public: #endif }; -}}} // namespace boost::geometry::concept +}}} // namespace boost::geometry::concepts #endif // BOOST_GEOMETRY_EXTENSIONS_ALGEBRA_GEOMETRIES_CONCEPTS_ROTATION_QUATERNION_CONCEPT_HPP diff --git a/include/boost/geometry/extensions/algebra/geometries/concepts/vector_concept.hpp b/include/boost/geometry/extensions/algebra/geometries/concepts/vector_concept.hpp index b13753a49..c515baff4 100644 --- a/include/boost/geometry/extensions/algebra/geometries/concepts/vector_concept.hpp +++ b/include/boost/geometry/extensions/algebra/geometries/concepts/vector_concept.hpp @@ -20,7 +20,7 @@ #include #include -namespace boost { namespace geometry { namespace concept { +namespace boost { namespace geometry { namespace concepts { template class Vector @@ -107,6 +107,6 @@ public: #endif }; -}}} // namespace boost::geometry::concept +}}} // namespace boost::geometry::concepts #endif // BOOST_GEOMETRY_EXTENSIONS_ALGEBRA_GEOMETRIES_CONCEPTS_VECTOR_CONCEPT_HPP diff --git a/include/boost/geometry/extensions/algebra/geometries/matrix.hpp b/include/boost/geometry/extensions/algebra/geometries/matrix.hpp index 61b988403..1e5356bba 100644 --- a/include/boost/geometry/extensions/algebra/geometries/matrix.hpp +++ b/include/boost/geometry/extensions/algebra/geometries/matrix.hpp @@ -27,7 +27,7 @@ namespace model { template class matrix { - BOOST_CONCEPT_ASSERT( (concept::Matrix) ); + BOOST_CONCEPT_ASSERT( (concepts::Matrix) ); public: diff --git a/include/boost/geometry/extensions/algebra/geometries/quaternion.hpp b/include/boost/geometry/extensions/algebra/geometries/quaternion.hpp index f252285bd..d41569f66 100644 --- a/include/boost/geometry/extensions/algebra/geometries/quaternion.hpp +++ b/include/boost/geometry/extensions/algebra/geometries/quaternion.hpp @@ -33,7 +33,7 @@ namespace model template class quaternion { - BOOST_CONCEPT_ASSERT( (concept::Quaternion) ); + BOOST_CONCEPT_ASSERT( (concepts::Quaternion) ); public: diff --git a/include/boost/geometry/extensions/algebra/geometries/rotation_matrix.hpp b/include/boost/geometry/extensions/algebra/geometries/rotation_matrix.hpp index 2a4d30ed8..be426a0ac 100644 --- a/include/boost/geometry/extensions/algebra/geometries/rotation_matrix.hpp +++ b/include/boost/geometry/extensions/algebra/geometries/rotation_matrix.hpp @@ -27,7 +27,7 @@ namespace model { template class rotation_matrix { - BOOST_CONCEPT_ASSERT( (concept::RotationMatrix) ); + BOOST_CONCEPT_ASSERT( (concepts::RotationMatrix) ); public: diff --git a/include/boost/geometry/extensions/algebra/geometries/rotation_quaternion.hpp b/include/boost/geometry/extensions/algebra/geometries/rotation_quaternion.hpp index ebc99ffb6..05482858a 100644 --- a/include/boost/geometry/extensions/algebra/geometries/rotation_quaternion.hpp +++ b/include/boost/geometry/extensions/algebra/geometries/rotation_quaternion.hpp @@ -33,7 +33,7 @@ namespace model template class rotation_quaternion { - BOOST_CONCEPT_ASSERT( (concept::RotationQuaternion) ); + BOOST_CONCEPT_ASSERT( (concepts::RotationQuaternion) ); public: diff --git a/include/boost/geometry/extensions/algebra/geometries/vector.hpp b/include/boost/geometry/extensions/algebra/geometries/vector.hpp index 679fe547f..733b07bbd 100644 --- a/include/boost/geometry/extensions/algebra/geometries/vector.hpp +++ b/include/boost/geometry/extensions/algebra/geometries/vector.hpp @@ -32,7 +32,7 @@ namespace model template class vector { - BOOST_CONCEPT_ASSERT( (concept::Vector) ); + BOOST_CONCEPT_ASSERT( (concepts::Vector) ); public: diff --git a/include/boost/geometry/extensions/algorithms/connect.hpp b/include/boost/geometry/extensions/algorithms/connect.hpp index 7c5439b97..a969ef4c7 100644 --- a/include/boost/geometry/extensions/algorithms/connect.hpp +++ b/include/boost/geometry/extensions/algorithms/connect.hpp @@ -521,8 +521,8 @@ inline void connect(Geometry const& geometry, Collection& output_collection) { typedef typename boost::range_value::type geometry_out; - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); typedef detail::connect::map_policy < @@ -553,8 +553,8 @@ inline void connect(Geometry const& geometry, Collection& output_collection, { typedef typename boost::range_value::type geometry_out; - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); typedef detail::connect::fuzzy_policy < diff --git a/include/boost/geometry/extensions/algorithms/detail/overlay/dissolver.hpp b/include/boost/geometry/extensions/algorithms/detail/overlay/dissolver.hpp index f54dfecd2..68738af8f 100644 --- a/include/boost/geometry/extensions/algorithms/detail/overlay/dissolver.hpp +++ b/include/boost/geometry/extensions/algorithms/detail/overlay/dissolver.hpp @@ -639,8 +639,8 @@ inline void dissolver(InputRange const& input_range, { typedef typename boost::range_value::type geometry_in; typedef typename boost::range_value::type geometry_out; - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); dispatch::dissolver < diff --git a/include/boost/geometry/extensions/algorithms/detail/overlay/split_rings.hpp b/include/boost/geometry/extensions/algorithms/detail/overlay/split_rings.hpp index bd6e96ea2..bcea70549 100644 --- a/include/boost/geometry/extensions/algorithms/detail/overlay/split_rings.hpp +++ b/include/boost/geometry/extensions/algorithms/detail/overlay/split_rings.hpp @@ -542,8 +542,8 @@ template > inline void split_rings(Geometry const& geometry, RingCollection& out) { - concept::check(); - concept::check::type>(); + concepts::check(); + concepts::check::type>(); dispatch::split_rings < diff --git a/include/boost/geometry/extensions/algorithms/dissolve.hpp b/include/boost/geometry/extensions/algorithms/dissolve.hpp index 451298c6a..da03c1fb3 100644 --- a/include/boost/geometry/extensions/algorithms/dissolve.hpp +++ b/include/boost/geometry/extensions/algorithms/dissolve.hpp @@ -65,15 +65,26 @@ class backtrack_for_dissolve public : typedef detail::overlay::backtrack_state state_type; - template + template + < + typename Operation, + typename Rings, + typename Turns, + typename RobustPolicy, + typename Visitor + > static inline void apply(std::size_t size_at_start, - Rings& rings, typename boost::range_value::type& ring, - Turns& turns, Operation& operation, - std::string const& , + Rings& rings, + typename boost::range_value::type& ring, + Turns& turns, + typename boost::range_value::type const& turn, + Operation& operation, + detail::overlay::traverse_error_type, Geometry const& , Geometry const& , - RescalePolicy const& , - state_type& state + RobustPolicy const& , + state_type& state, + Visitor const& visitor ) { state.m_good = false; @@ -90,6 +101,41 @@ public : } }; +struct dissolve_overlay_visitor +{ +public : + void print(char const* /*header*/) + { + } + + template + void print(char const* /*header*/, Turns const& /*turns*/, int /*turn_index*/) + { + } + + template + void print(char const* /*header*/, Turns const& /*turns*/, int /*turn_index*/, int /*op_index*/) + { + } + + template + void visit_turns(int , Turns const& ) {} + + template + void visit_clusters(Clusters const& , Turns const& ) {} + + template + void visit_traverse(Turns const& /*turns*/, Turn const& /*turn*/, Operation const& /*op*/, const char* /*header*/) + { + } + + template + void visit_traverse_reject(Turns const& , Turn const& , Operation const& , + detail::overlay::traverse_error_type ) + {} +}; + + template struct dissolve_ring_or_polygon @@ -123,43 +169,49 @@ struct dissolve_ring_or_polygon typedef std::vector out_vector; out_vector rings; - // Enrich the turns + typedef std::map + < + signed_size_type, + detail::overlay::cluster_info + > cluster_type; + + cluster_type clusters; + dissolve_overlay_visitor visitor; + + // Enrich/traverse the polygons twice: once for union... typedef typename strategy::side::services::default_strategy < typename cs_tag::type >::type side_strategy_type; enrich_intersection_points(turns, - detail::overlay::operation_union, - geometry, geometry, rescale_policy, + clusters, geometry, geometry, rescale_policy, side_strategy_type()); - typedef detail::overlay::traverse + detail::overlay::traverse < false, false, Geometry, Geometry, + overlay_dissolve, backtrack_for_dissolve - > traverser; - - - // Traverse the polygons twice for union... - traverser::apply(geometry, geometry, - detail::overlay::operation_union, - rescale_policy, - turns, rings); + >::apply(geometry, geometry, rescale_policy, + turns, rings, clusters, visitor); clear_visit_info(turns); - enrich_intersection_points(turns, - detail::overlay::operation_intersection, - geometry, geometry, rescale_policy, + // ... and for intersection + enrich_intersection_points(turns, + clusters, geometry, geometry, rescale_policy, side_strategy_type()); - // ... and for intersection - traverser::apply(geometry, geometry, - detail::overlay::operation_intersection, - rescale_policy, - turns, rings); + detail::overlay::traverse + < + false, false, + Geometry, Geometry, + overlay_intersection, + backtrack_for_dissolve + >::apply(geometry, geometry, rescale_policy, + turns, rings, clusters, visitor); std::map map; get_ring_turn_info(map, turns); @@ -168,7 +220,7 @@ struct dissolve_ring_or_polygon std::map selected; - detail::overlay::select_rings(geometry, map, selected); + detail::overlay::select_rings(geometry, map, selected); // Add intersected rings { @@ -257,8 +309,8 @@ template > inline OutputIterator dissolve_inserter(Geometry const& geometry, OutputIterator out) { - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); typedef typename geometry::rescale_policy_type < @@ -285,11 +337,11 @@ template > inline void dissolve(Geometry const& geometry, Collection& output_collection) { - concept::check(); + concepts::check(); typedef typename boost::range_value::type geometry_out; - concept::check(); + concepts::check(); dispatch::dissolve < diff --git a/include/boost/geometry/extensions/algorithms/distance_info.hpp b/include/boost/geometry/extensions/algorithms/distance_info.hpp index 2a0879cdf..e792798b2 100644 --- a/include/boost/geometry/extensions/algorithms/distance_info.hpp +++ b/include/boost/geometry/extensions/algorithms/distance_info.hpp @@ -206,9 +206,9 @@ struct distance_info template inline void distance_info(Geometry1 const& geometry1, Geometry2 const& geometry2, Result& result) { - concept::check(); - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); + concepts::check(); assert_dimension_equal(); assert_dimension_equal(); diff --git a/include/boost/geometry/extensions/algorithms/midpoints.hpp b/include/boost/geometry/extensions/algorithms/midpoints.hpp index 6c669d7d1..15ec0d536 100644 --- a/include/boost/geometry/extensions/algorithms/midpoints.hpp +++ b/include/boost/geometry/extensions/algorithms/midpoints.hpp @@ -116,7 +116,7 @@ template inline void midpoints(Geometry const& geometry, bool start_and_end, Iterator out) { - concept::check(); + concepts::check(); dispatch::midpoints < diff --git a/include/boost/geometry/extensions/algorithms/offset.hpp b/include/boost/geometry/extensions/algorithms/offset.hpp index 525b7c44c..18b319532 100644 --- a/include/boost/geometry/extensions/algorithms/offset.hpp +++ b/include/boost/geometry/extensions/algorithms/offset.hpp @@ -140,8 +140,8 @@ inline void offset(Geometry const& geometry, GeometryOut& out, JoinStrategy const& join_strategy, Distance const& distance) { - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); typedef typename geometry::point_type::type point_type; diff --git a/include/boost/geometry/extensions/algorithms/parse.hpp b/include/boost/geometry/extensions/algorithms/parse.hpp index db2d75caa..4edba604d 100644 --- a/include/boost/geometry/extensions/algorithms/parse.hpp +++ b/include/boost/geometry/extensions/algorithms/parse.hpp @@ -89,7 +89,7 @@ struct parsing template inline void parse(Geometry& geometry, std::string const& c1, std::string const& c2) { - concept::check(); + concepts::check(); dispatch::parsing::type, Geometry>::parse(geometry, c1, c2); } @@ -102,7 +102,7 @@ template inline void parse(Geometry& geometry, std::string const& c1, std::string const& c2, S const& strategy) { - concept::check(); + concepts::check(); dispatch::parsing::type, Geometry>::parse(geometry, c1, c2, strategy); } @@ -111,7 +111,7 @@ inline void parse(Geometry& geometry, std::string const& c1, template inline Geometry parse(std::string const& c1, std::string const& c2) { - concept::check(); + concepts::check(); Geometry geometry; dispatch::parsing::type, Geometry>::parse(geometry, c1, c2); diff --git a/include/boost/geometry/extensions/algorithms/remove_holes_if.hpp b/include/boost/geometry/extensions/algorithms/remove_holes_if.hpp index 5d11d3404..bdc6dcda2 100644 --- a/include/boost/geometry/extensions/algorithms/remove_holes_if.hpp +++ b/include/boost/geometry/extensions/algorithms/remove_holes_if.hpp @@ -98,7 +98,7 @@ struct remove_holes_if template inline void remove_holes_if(Geometry& geometry, Predicate const& predicate) { - concept::check(); + concepts::check(); dispatch::remove_holes_if < diff --git a/include/boost/geometry/extensions/algorithms/remove_marked.hpp b/include/boost/geometry/extensions/algorithms/remove_marked.hpp index 2ab8c3184..9a91e4d82 100644 --- a/include/boost/geometry/extensions/algorithms/remove_marked.hpp +++ b/include/boost/geometry/extensions/algorithms/remove_marked.hpp @@ -203,7 +203,7 @@ template inline void remove_marked(Geometry const& geometry_in, Geometry& geometry_out, MarkMap const& mark_map) { - concept::check(); + concepts::check(); ring_identifier id; dispatch::remove_marked diff --git a/include/boost/geometry/extensions/algorithms/selected.hpp b/include/boost/geometry/extensions/algorithms/selected.hpp index 8890d6ab0..bf699c9f2 100644 --- a/include/boost/geometry/extensions/algorithms/selected.hpp +++ b/include/boost/geometry/extensions/algorithms/selected.hpp @@ -258,8 +258,8 @@ inline bool selected(Geometry const& geometry, Point const& selection_point, RadiusType const& search_radius) { - concept::check(); - concept::check(); + concepts::check(); + concepts::check(); typedef dispatch::selected < diff --git a/include/boost/geometry/extensions/gis/io/veshape/write_veshape.hpp b/include/boost/geometry/extensions/gis/io/veshape/write_veshape.hpp index 4b4caffc0..98d4507c4 100644 --- a/include/boost/geometry/extensions/gis/io/veshape/write_veshape.hpp +++ b/include/boost/geometry/extensions/gis/io/veshape/write_veshape.hpp @@ -120,7 +120,7 @@ struct veshape_point } private: - BOOST_CONCEPT_ASSERT( (concept::ConstPoint

) ); + BOOST_CONCEPT_ASSERT( (concepts::ConstPoint

) ); }; /*! @@ -151,7 +151,7 @@ struct veshape_range private: typedef typename boost::range_value::type point; - BOOST_CONCEPT_ASSERT( (concept::ConstPoint) ); + BOOST_CONCEPT_ASSERT( (concepts::ConstPoint) ); }; @@ -179,7 +179,7 @@ struct veshape_poly } private: - BOOST_CONCEPT_ASSERT( (concept::ConstPoint::type>) ); + BOOST_CONCEPT_ASSERT( (concepts::ConstPoint::type>) ); }; diff --git a/include/boost/geometry/extensions/nsphere/geometries/concepts/check.hpp b/include/boost/geometry/extensions/nsphere/geometries/concepts/check.hpp index c8d2fb7c4..ecab04eff 100644 --- a/include/boost/geometry/extensions/nsphere/geometries/concepts/check.hpp +++ b/include/boost/geometry/extensions/nsphere/geometries/concepts/check.hpp @@ -30,12 +30,12 @@ namespace dispatch template struct check - : detail::concept_check::check > + : detail::concept_check::check > {}; template struct check - : detail::concept_check::check > + : detail::concept_check::check > {}; } // namespace dispatch diff --git a/include/boost/geometry/extensions/nsphere/geometries/concepts/nsphere_concept.hpp b/include/boost/geometry/extensions/nsphere/geometries/concepts/nsphere_concept.hpp index 03decb40d..e493ad412 100644 --- a/include/boost/geometry/extensions/nsphere/geometries/concepts/nsphere_concept.hpp +++ b/include/boost/geometry/extensions/nsphere/geometries/concepts/nsphere_concept.hpp @@ -21,7 +21,7 @@ #include #include -namespace boost { namespace geometry { namespace concept { +namespace boost { namespace geometry { namespace concepts { /*! \brief Checks Nsphere concept (const version) @@ -78,7 +78,7 @@ public : template class Nsphere { - BOOST_CONCEPT_ASSERT( (concept::ConstNsphere) ); + BOOST_CONCEPT_ASSERT( (concepts::ConstNsphere) ); typedef typename point_type::type point_type; typedef typename radius_type::type radius_type; @@ -117,6 +117,6 @@ public : -}}} // namespace boost::geometry::concept +}}} // namespace boost::geometry::concepts #endif // BOOST_GEOMETRY_EXTENSIONS_NSPHERE_GEOMETRIES_CONCEPTS_NSPHERE_CONCEPT_HPP diff --git a/include/boost/geometry/extensions/nsphere/geometries/nsphere.hpp b/include/boost/geometry/extensions/nsphere/geometries/nsphere.hpp index 4f7cb72b3..5e1443cbf 100644 --- a/include/boost/geometry/extensions/nsphere/geometries/nsphere.hpp +++ b/include/boost/geometry/extensions/nsphere/geometries/nsphere.hpp @@ -47,7 +47,7 @@ namespace model template class nsphere { - BOOST_CONCEPT_ASSERT( (concept::Point

) ); + BOOST_CONCEPT_ASSERT( (concepts::Point

) ); public: diff --git a/include/boost/geometry/formulas/andoyer_inverse.hpp b/include/boost/geometry/formulas/andoyer_inverse.hpp index a419d0489..04a43995b 100644 --- a/include/boost/geometry/formulas/andoyer_inverse.hpp +++ b/include/boost/geometry/formulas/andoyer_inverse.hpp @@ -130,10 +130,7 @@ public: // T = inf // dA = inf // azimuth = -inf - if (lat1 <= lat2) - result.azimuth = c0; - else - result.azimuth = pi; + result.azimuth = lat1 <= lat2 ? c0 : pi; } else { @@ -188,19 +185,16 @@ public: } } - if (BOOST_GEOMETRY_CONDITION(CalcQuantities)) { - typedef differential_quantities quantities; + typedef differential_quantities quantities; quantities::apply(dlon, sin_lat1, cos_lat1, sin_lat2, cos_lat2, result.azimuth, result.reverse_azimuth, get_radius<2>(spheroid), f, - result.reduced_length, result.geodesic_scale, - quantities::J12_calc_f1); + result.reduced_length, result.geodesic_scale); } return result; - } private: @@ -213,13 +207,17 @@ private: if (dA >= c0) // A altered towards 0 { if (azimuth < c0) + { azimuth = c0; + } } else // dA < 0, A altered towards pi { CT const pi = math::pi(); if (azimuth > pi) + { azimuth = pi; + } } } else // A indicates Western hemisphere @@ -227,13 +225,17 @@ private: if (dA <= c0) // A altered towards 0 { if (azimuth > c0) + { azimuth = c0; + } } else // dA > 0, A altered towards -pi { CT const minus_pi = -math::pi(); if (azimuth < minus_pi) + { azimuth = minus_pi; + } } } } diff --git a/include/boost/geometry/formulas/differential_quantities.hpp b/include/boost/geometry/formulas/differential_quantities.hpp index 5fb69fd3a..9a92f14e1 100644 --- a/include/boost/geometry/formulas/differential_quantities.hpp +++ b/include/boost/geometry/formulas/differential_quantities.hpp @@ -28,18 +28,18 @@ https://arxiv.org/pdf/1109.4448.pdf template < typename CT, bool EnableReducedLength, - bool EnableGeodesicScale + bool EnableGeodesicScale, + unsigned int Order = 2, + bool ApproxF = true > class differential_quantities { public: - template static inline void apply(CT const& lon1, CT const& lat1, CT const& lon2, CT const& lat2, CT const& azimuth, CT const& reverse_azimuth, CT const& b, CT const& f, - CT & reduced_length, CT & geodesic_scale, - J12Calc J12_calc) + CT & reduced_length, CT & geodesic_scale) { CT const dlon = lon2 - lon1; CT const sin_lat1 = sin(lat1); @@ -50,48 +50,52 @@ public: apply(dlon, sin_lat1, cos_lat1, sin_lat2, cos_lat2, azimuth, reverse_azimuth, b, f, - reduced_length, geodesic_scale, - J12_calc); + reduced_length, geodesic_scale); } - template static inline void apply(CT const& dlon, CT const& sin_lat1, CT const& cos_lat1, CT const& sin_lat2, CT const& cos_lat2, CT const& azimuth, CT const& reverse_azimuth, CT const& b, CT const& f, - CT & reduced_length, CT & geodesic_scale, - J12Calc J12_calc) + CT & reduced_length, CT & geodesic_scale) { - CT one_minus_f = CT(1) - f; - CT sin_bet1 = one_minus_f * sin_lat1; - CT sin_bet2 = one_minus_f * sin_lat2; + CT const c0 = 0; + CT const c1 = 1; + CT const one_minus_f = c1 - f; + + CT const sin_bet1 = one_minus_f * sin_lat1; + CT const sin_bet2 = one_minus_f * sin_lat2; // equator - if (math::equals(sin_bet1, CT(0)) && math::equals(sin_bet2, CT(0))) + if (math::equals(sin_bet1, c0) && math::equals(sin_bet2, c0)) { - CT sig12 = math::abs(dlon) / one_minus_f; + CT const sig_12 = math::abs(dlon) / one_minus_f; if (BOOST_GEOMETRY_CONDITION(EnableReducedLength)) { - CT m12 = sin(sig12) * b; + CT m12 = sin(sig_12) * b; reduced_length = m12; } if (BOOST_GEOMETRY_CONDITION(EnableGeodesicScale)) { - CT M12 = cos(sig12); + CT M12 = cos(sig_12); geodesic_scale = M12; } } else { - CT cos_bet1 = cos_lat1; - CT cos_bet2 = cos_lat2; + CT const c2 = 2; + CT const e2 = f * (c2 - f); + CT const ep2 = e2 / math::sqr(one_minus_f); - CT sin_alp1 = sin(azimuth); - CT cos_alp1 = cos(azimuth); - CT sin_alp2 = sin(reverse_azimuth); - CT cos_alp2 = cos(reverse_azimuth); + CT const cos_bet1 = cos_lat1; + CT const cos_bet2 = cos_lat2; + + CT const sin_alp1 = sin(azimuth); + CT const cos_alp1 = cos(azimuth); + //CT const sin_alp2 = sin(reverse_azimuth); + CT const cos_alp2 = cos(reverse_azimuth); CT sin_sig1 = sin_bet1; CT cos_sig1 = cos_alp1 * cos_bet1; @@ -101,14 +105,15 @@ public: normalize(sin_sig1, cos_sig1); normalize(sin_sig2, cos_sig2); - CT sin_alp0 = sin_alp1 * cos_bet1; - CT cos_alp0_sqr = CT(1) - math::sqr(sin_alp0); + CT const sin_alp0 = sin_alp1 * cos_bet1; + CT const cos_alp0_sqr = c1 - math::sqr(sin_alp0); - CT const J12 = J12_calc(sin_sig1, cos_sig1, sin_sig2, cos_sig2, cos_alp0_sqr, f); + CT const J12 = BOOST_GEOMETRY_CONDITION(ApproxF) ? + J12_f(sin_sig1, cos_sig1, sin_sig2, cos_sig2, cos_alp0_sqr, f) : + J12_ep_sqr(sin_sig1, cos_sig1, sin_sig2, cos_sig2, cos_alp0_sqr, ep2) ; - CT const e2 = f * (CT(2) - f); - CT const dn1 = math::sqrt(CT(1) + e2 * math::sqr(sin_lat1)); - CT const dn2 = math::sqrt(CT(1) + e2 * math::sqr(sin_lat2)); + CT const dn1 = math::sqrt(c1 + e2 * math::sqr(sin_lat1)); + CT const dn2 = math::sqrt(c1 + e2 * math::sqr(sin_lat2)); if (BOOST_GEOMETRY_CONDITION(EnableReducedLength)) { @@ -122,7 +127,6 @@ public: if (BOOST_GEOMETRY_CONDITION(EnableGeodesicScale)) { - CT const ep2 = e2 / math::sqr(one_minus_f); CT const cos_sig12 = cos_sig1 * cos_sig2 + sin_sig1 * sin_sig2; CT const t = ep2 * (cos_bet1 - cos_bet2) * (cos_bet1 + cos_bet2) / (dn1 + dn2); CT const M12 = cos_sig12 + (t * sin_sig2 - cos_sig2 * J12) * sin_sig1 / dn1; @@ -132,49 +136,161 @@ public: } } - static inline CT J12_calc_f1(CT const& sin_sig1, CT const& cos_sig1, - CT const& sin_sig2, CT const& cos_sig2, - CT const& cos_alp0_sqr, CT const& f) - { - CT const sig12 = atan2(cos_sig1 * sin_sig2 - sin_sig1 * cos_sig2, - cos_sig1 * cos_sig2 + sin_sig1 * sin_sig2); - CT const sin_2sig1 = 2 * cos_sig1 * sin_sig1; // sin(2sig1) - CT const sin_2sig2 = 2 * cos_sig2 * sin_sig2; // sin(2sig2) - CT const sin_2sig12 = sin_2sig2 - sin_2sig1; - - CT const J12 = (sig12 - sin_2sig12 / 2) * cos_alp0_sqr * f; - - return J12; - } - - static inline CT J12_calc_f2(CT const& sin_sig1, CT const& cos_sig1, - CT const& sin_sig2, CT const& cos_sig2, - CT const& cos_alp0_sqr, CT const& f) - { - CT const sig12 = atan2(cos_sig1 * sin_sig2 - sin_sig1 * cos_sig2, - cos_sig1 * cos_sig2 + sin_sig1 * sin_sig2); - CT const sin_2sig1 = CT(2) * cos_sig1 * sin_sig1; // sin(2sig1) - CT const sin_2sig2 = CT(2) * cos_sig2 * sin_sig2; // sin(2sig2) - CT const sin_2sig12 = sin_2sig2 - sin_2sig1; - CT const sin_4sig1 = CT(2) * sin_2sig1 * (math::sqr(cos_sig1) - math::sqr(sin_sig1)); // sin(4sig1) - CT const sin_4sig2 = CT(2) * sin_2sig2 * (math::sqr(cos_sig2) - math::sqr(sin_sig2)); // sin(4sig2) - CT const sin_4sig12 = sin_4sig2 - sin_4sig1; - - CT const t1 = CT(2) * sig12 - sin_2sig12; - CT const t2 = cos_alp0_sqr * sin_4sig12 - + (-CT(8) * cos_alp0_sqr + CT(12)) * sin_2sig12 - + (CT(12) * cos_alp0_sqr - CT(24)) * sig12; - CT const J12 = cos_alp0_sqr * f * (t1 / 2 - f * t2 / 16); - - return J12; - } - private: + /*! Approximation of J12, expanded into taylor series in f + Maxima script: + ep2: f * (2-f) / ((1-f)^2); + k2: ca02 * ep2; + assume(f < 1); + assume(sig > 0); + I1(sig):= integrate(sqrt(1 + k2 * sin(s)^2), s, 0, sig); + I2(sig):= integrate(1/sqrt(1 + k2 * sin(s)^2), s, 0, sig); + J(sig):= I1(sig) - I2(sig); + S: taylor(J(sig), f, 0, 3); + S1: factor( 2*integrate(sin(s)^2,s,0,sig)*ca02*f ); + S2: factor( ((integrate(-6*ca02^2*sin(s)^4+6*ca02*sin(s)^2,s,0,sig)+integrate(-2*ca02^2*sin(s)^4+6*ca02*sin(s)^2,s,0,sig))*f^2)/4 ); + S3: factor( ((integrate(30*ca02^3*sin(s)^6-54*ca02^2*sin(s)^4+24*ca02*sin(s)^2,s,0,sig)+integrate(6*ca02^3*sin(s)^6-18*ca02^2*sin(s)^4+24*ca02*sin(s)^2,s,0,sig))*f^3)/12 ); + */ + static inline CT J12_f(CT const& sin_sig1, CT const& cos_sig1, + CT const& sin_sig2, CT const& cos_sig2, + CT const& cos_alp0_sqr, CT const& f) + { + if (Order == 0) + { + return 0; + } + + CT const c2 = 2; + + CT const sig_12 = atan2(cos_sig1 * sin_sig2 - sin_sig1 * cos_sig2, + cos_sig1 * cos_sig2 + sin_sig1 * sin_sig2); + CT const sin_2sig1 = c2 * cos_sig1 * sin_sig1; // sin(2sig1) + CT const sin_2sig2 = c2 * cos_sig2 * sin_sig2; // sin(2sig2) + CT const sin_2sig_12 = sin_2sig2 - sin_2sig1; + CT const L1 = sig_12 - sin_2sig_12 / c2; + + if (Order == 1) + { + return cos_alp0_sqr * f * L1; + } + + CT const sin_4sig1 = c2 * sin_2sig1 * (math::sqr(cos_sig1) - math::sqr(sin_sig1)); // sin(4sig1) + CT const sin_4sig2 = c2 * sin_2sig2 * (math::sqr(cos_sig2) - math::sqr(sin_sig2)); // sin(4sig2) + CT const sin_4sig_12 = sin_4sig2 - sin_4sig1; + + CT const c8 = 8; + CT const c12 = 12; + CT const c16 = 16; + CT const c24 = 24; + + CT const L2 = -( cos_alp0_sqr * sin_4sig_12 + + (-c8 * cos_alp0_sqr + c12) * sin_2sig_12 + + (c12 * cos_alp0_sqr - c24) * sig_12) + / c16; + + if (Order == 2) + { + return cos_alp0_sqr * f * (L1 + f * L2); + } + + CT const c4 = 4; + CT const c9 = 9; + CT const c48 = 48; + CT const c60 = 60; + CT const c64 = 64; + CT const c96 = 96; + CT const c128 = 128; + CT const c144 = 144; + + CT const cos_alp0_quad = math::sqr(cos_alp0_sqr); + CT const sin3_2sig1 = math::sqr(sin_2sig1) * sin_2sig1; + CT const sin3_2sig2 = math::sqr(sin_2sig2) * sin_2sig2; + CT const sin3_2sig_12 = sin3_2sig2 - sin3_2sig1; + + CT const A = (c9 * cos_alp0_quad - c12 * cos_alp0_sqr) * sin_4sig_12; + CT const B = c4 * cos_alp0_quad * sin3_2sig_12; + CT const C = (-c48 * cos_alp0_quad + c96 * cos_alp0_sqr - c64) * sin_2sig_12; + CT const D = (c60 * cos_alp0_quad - c144 * cos_alp0_sqr + c128) * sig_12; + + CT const L3 = (A + B + C + D) / c64; + + // Order 3 and higher + return cos_alp0_sqr * f * (L1 + f * (L2 + f * L3)); + } + + /*! Approximation of J12, expanded into taylor series in e'^2 + Maxima script: + k2: ca02 * ep2; + assume(sig > 0); + I1(sig):= integrate(sqrt(1 + k2 * sin(s)^2), s, 0, sig); + I2(sig):= integrate(1/sqrt(1 + k2 * sin(s)^2), s, 0, sig); + J(sig):= I1(sig) - I2(sig); + S: taylor(J(sig), ep2, 0, 3); + S1: factor( integrate(sin(s)^2,s,0,sig)*ca02*ep2 ); + S2: factor( (integrate(sin(s)^4,s,0,sig)*ca02^2*ep2^2)/2 ); + S3: factor( (3*integrate(sin(s)^6,s,0,sig)*ca02^3*ep2^3)/8 ); + */ + static inline CT J12_ep_sqr(CT const& sin_sig1, CT const& cos_sig1, + CT const& sin_sig2, CT const& cos_sig2, + CT const& cos_alp0_sqr, CT const& ep_sqr) + { + if (Order == 0) + { + return 0; + } + + CT const c2 = 2; + CT const c4 = 4; + + CT const c2a0ep2 = cos_alp0_sqr * ep_sqr; + + CT const sig_12 = atan2(cos_sig1 * sin_sig2 - sin_sig1 * cos_sig2, + cos_sig1 * cos_sig2 + sin_sig1 * sin_sig2); // sig2 - sig1 + CT const sin_2sig1 = c2 * cos_sig1 * sin_sig1; // sin(2sig1) + CT const sin_2sig2 = c2 * cos_sig2 * sin_sig2; // sin(2sig2) + CT const sin_2sig_12 = sin_2sig2 - sin_2sig1; + + CT const L1 = (c2 * sig_12 - sin_2sig_12) / c4; + + if (Order == 1) + { + return c2a0ep2 * L1; + } + + CT const c8 = 8; + CT const c64 = 64; + + CT const sin_4sig1 = c2 * sin_2sig1 * (math::sqr(cos_sig1) - math::sqr(sin_sig1)); // sin(4sig1) + CT const sin_4sig2 = c2 * sin_2sig2 * (math::sqr(cos_sig2) - math::sqr(sin_sig2)); // sin(4sig2) + CT const sin_4sig_12 = sin_4sig2 - sin_4sig1; + + CT const L2 = (sin_4sig_12 - c8 * sin_2sig_12 + 12 * sig_12) / c64; + + if (Order == 2) + { + return c2a0ep2 * (L1 + c2a0ep2 * L2); + } + + CT const sin3_2sig1 = math::sqr(sin_2sig1) * sin_2sig1; + CT const sin3_2sig2 = math::sqr(sin_2sig2) * sin_2sig2; + CT const sin3_2sig_12 = sin3_2sig2 - sin3_2sig1; + + CT const c9 = 9; + CT const c48 = 48; + CT const c60 = 60; + CT const c512 = 512; + + CT const L3 = (c9 * sin_4sig_12 + c4 * sin3_2sig_12 - c48 * sin_2sig_12 + c60 * sig_12) / c512; + + // Order 3 and higher + return c2a0ep2 * (L1 + c2a0ep2 * (L2 + c2a0ep2 * L3)); + } + static inline void normalize(CT & x, CT & y) { - CT const l = math::sqrt(math::sqr(x) + math::sqr(y)); - x /= l; - y /= l; + CT const len = math::sqrt(math::sqr(x) + math::sqr(y)); + x /= len; + y /= len; } }; diff --git a/include/boost/geometry/formulas/gnomonic_intersection.hpp b/include/boost/geometry/formulas/gnomonic_intersection.hpp new file mode 100644 index 000000000..7e1b7bcda --- /dev/null +++ b/include/boost/geometry/formulas/gnomonic_intersection.hpp @@ -0,0 +1,148 @@ +// Boost.Geometry + +// Copyright (c) 2016 Oracle and/or its affiliates. + +// 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_FORMULAS_GNOMONIC_INTERSECTION_HPP +#define BOOST_GEOMETRY_FORMULAS_GNOMONIC_INTERSECTION_HPP + +#include +#include + +#include +#include +#include +#include + + +namespace boost { namespace geometry { namespace formula +{ + +/*! +\brief The intersection of two geodesics using spheroidal gnomonic projection + as proposed by Karney. +\author See + - Charles F.F Karney, Algorithms for geodesics, 2011 + https://arxiv.org/pdf/1109.4448.pdf + - GeographicLib forum thread: Intersection between two geodesic lines + https://sourceforge.net/p/geographiclib/discussion/1026621/thread/21aaff9f/ +*/ +template +< + typename CT, + template class Inverse, + template class Direct +> +class gnomonic_intersection +{ +public: + template + static inline bool apply(T1 const& lona1, T1 const& lata1, + T1 const& lona2, T1 const& lata2, + T2 const& lonb1, T2 const& latb1, + T2 const& lonb2, T2 const& latb2, + CT & lon, CT & lat, + Spheroid const& spheroid) + { + CT const lon_a1 = lona1; + CT const lat_a1 = lata1; + CT const lon_a2 = lona2; + CT const lat_a2 = lata2; + CT const lon_b1 = lonb1; + CT const lat_b1 = latb1; + CT const lon_b2 = lonb2; + CT const lat_b2 = latb2; + + return apply(lon_a1, lat_a1, lon_a2, lat_a2, lon_b1, lat_b1, lon_b2, lat_b2, lon, lat, spheroid); + } + + template + static inline bool apply(CT const& lona1, CT const& lata1, + CT const& lona2, CT const& lata2, + CT const& lonb1, CT const& latb1, + CT const& lonb2, CT const& latb2, + CT & lon, CT & lat, + Spheroid const& spheroid) + { + typedef gnomonic_spheroid gnom_t; + + lon = (lona1 + lona2 + lonb1 + lonb2) / 4; + lat = (lata1 + lata2 + latb1 + latb2) / 4; + // TODO: consider normalizing lon + + for (int i = 0; i < 10; ++i) + { + CT xa1, ya1, xa2, ya2; + CT xb1, yb1, xb2, yb2; + CT x, y; + double lat1, lon1; + + bool ok = gnom_t::forward(lon, lat, lona1, lata1, xa1, ya1, spheroid) + && gnom_t::forward(lon, lat, lona2, lata2, xa2, ya2, spheroid) + && gnom_t::forward(lon, lat, lonb1, latb1, xb1, yb1, spheroid) + && gnom_t::forward(lon, lat, lonb2, latb2, xb2, yb2, spheroid) + && intersect(xa1, ya1, xa2, ya2, xb1, yb1, xb2, yb2, x, y) + && gnom_t::inverse(lon, lat, x, y, lon1, lat1, spheroid); + + if (! ok) + { + return false; + } + + if (math::equals(lat1, lat) && math::equals(lon1, lon)) + { + break; + } + + lat = lat1; + lon = lon1; + } + + // NOTE: true is also returned if the number of iterations is too great + // which means that the accuracy of the result is low + return true; + } + +private: + static inline bool intersect(CT const& xa1, CT const& ya1, CT const& xa2, CT const& ya2, + CT const& xb1, CT const& yb1, CT const& xb2, CT const& yb2, + CT & x, CT & y) + { + typedef model::point v3d_t; + + CT const c0 = 0; + CT const c1 = 1; + + v3d_t const va1(xa1, ya1, c1); + v3d_t const va2(xa2, ya2, c1); + v3d_t const vb1(xb1, yb1, c1); + v3d_t const vb2(xb2, yb2, c1); + + v3d_t const la = cross_product(va1, va2); + v3d_t const lb = cross_product(vb1, vb2); + v3d_t const p = cross_product(la, lb); + + CT const z = get<2>(p); + + if (math::equals(z, c0)) + { + // degenerated or collinear segments + return false; + } + + x = get<0>(p) / z; + y = get<1>(p) / z; + + return true; + } +}; + +}}} // namespace boost::geometry::formula + + +#endif // BOOST_GEOMETRY_FORMULAS_GNOMONIC_INTERSECTION_HPP diff --git a/include/boost/geometry/formulas/gnomonic_spheroid.hpp b/include/boost/geometry/formulas/gnomonic_spheroid.hpp index fcb6e7165..3457397b0 100644 --- a/include/boost/geometry/formulas/gnomonic_spheroid.hpp +++ b/include/boost/geometry/formulas/gnomonic_spheroid.hpp @@ -56,13 +56,15 @@ public: Spheroid const& spheroid) { inverse_result i_res = inverse_type::apply(lon0, lat0, lon, lat, spheroid); + CT const& m = i_res.reduced_length; + CT const& M = i_res.geodesic_scale; - if (math::smaller_or_equals(i_res.geodesic_scale, CT(0))) + if (math::smaller_or_equals(M, CT(0))) { return false; } - CT rho = i_res.reduced_length / i_res.geodesic_scale; + CT rho = m / M; x = sin(i_res.azimuth) * rho; y = cos(i_res.azimuth) * rho; @@ -76,8 +78,6 @@ public: Spheroid const& spheroid) { CT const a = get_radius<0>(spheroid); - CT const b = get_radius<2>(spheroid); - CT const f = detail::flattening(spheroid); CT const ds_threshold = a * std::numeric_limits::epsilon(); // TODO: 0 for non-fundamental type CT const azimuth = atan2(x, y); @@ -90,6 +90,12 @@ public: direct_result d_res = direct_quantities_type::apply(lon0, lat0, distance, azimuth, spheroid); CT const& m = d_res.reduced_length; CT const& M = d_res.geodesic_scale; + + if (math::smaller_or_equals(M, CT(0))) + { + // found = false; + return found; + } CT const drho = m / M - rho; // rho = m / M CT const ds = drho * math::sqr(M); // drho/ds = 1/M^2 diff --git a/include/boost/geometry/formulas/sjoberg_intersection.hpp b/include/boost/geometry/formulas/sjoberg_intersection.hpp new file mode 100644 index 000000000..03bd4bc97 --- /dev/null +++ b/include/boost/geometry/formulas/sjoberg_intersection.hpp @@ -0,0 +1,385 @@ +// Boost.Geometry + +// Copyright (c) 2016 Oracle and/or its affiliates. + +// 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_FORMULAS_SJOBERG_INTERSECTION_HPP +#define BOOST_GEOMETRY_FORMULAS_SJOBERG_INTERSECTION_HPP + + +#include + +#include +#include + +#include +#include + +#include + + +namespace boost { namespace geometry { namespace formula +{ + +/*! +\brief The intersection of two geodesics as proposed by Sjoberg. +\author See + - [Sjoberg02] Lars E. Sjoberg, Intersections on the sphere and ellipsoid, 2002 + http://link.springer.com/article/10.1007/s00190-001-0230-9 + - [Sjoberg07] Lars E. Sjoberg, Geodetic intersection on the ellipsoid, 2007 + http://link.springer.com/article/10.1007/s00190-007-0204-7 +*/ +template +< + typename CT, + template class Inverse, + unsigned int Order = 4 +> +class sjoberg_intersection +{ + typedef Inverse inverse_type; + typedef typename inverse_type::result_type inverse_result; + +public: + template + static inline bool apply(T1 const& lona1, T1 const& lata1, + T1 const& lona2, T1 const& lata2, + T2 const& lonb1, T2 const& latb1, + T2 const& lonb2, T2 const& latb2, + CT & lon, CT & lat, + Spheroid const& spheroid) + { + CT const lon_a1 = lona1; + CT const lat_a1 = lata1; + CT const lon_a2 = lona2; + CT const lat_a2 = lata2; + CT const lon_b1 = lonb1; + CT const lat_b1 = latb1; + CT const lon_b2 = lonb2; + CT const lat_b2 = latb2; + + CT const alpha1 = inverse_type::apply(lon_a1, lat_a1, lon_a2, lat_a2, spheroid).azimuth; + CT const alpha2 = inverse_type::apply(lon_b1, lat_b1, lon_b2, lat_b2, spheroid).azimuth; + + return apply(lon_a1, lat_a1, alpha1, lon_b1, lat_b1, alpha2, lon, lat, spheroid); + } + + template + static inline bool apply(CT const& lon1, CT const& lat1, CT const& alpha1, + CT const& lon2, CT const& lat2, CT const& alpha2, + CT & lon, CT & lat, + Spheroid const& spheroid) + { + // coordinates in radians + + // TODO - handle special cases like degenerated segments, equator, poles, etc. + + CT const c0 = 0; + CT const c1 = 1; + CT const c2 = 2; + + CT const pi = math::pi(); + CT const pi_half = pi / c2; + CT const f = detail::flattening(spheroid); + CT const one_minus_f = c1 - f; + CT const e_sqr = f * (c2 - f); + + CT const sin_alpha1 = sin(alpha1); + CT const sin_alpha2 = sin(alpha2); + + CT const tan_beta1 = one_minus_f * tan(lat1); + CT const tan_beta2 = one_minus_f * tan(lat2); + CT const beta1 = atan(tan_beta1); + CT const beta2 = atan(tan_beta2); + CT const cos_beta1 = cos(beta1); + CT const cos_beta2 = cos(beta2); + CT const sin_beta1 = sin(beta1); + CT const sin_beta2 = sin(beta2); + + // Clairaut constants (lower-case in the paper) + int const sign_C1 = math::abs(alpha1) <= pi_half ? 1 : -1; + int const sign_C2 = math::abs(alpha2) <= pi_half ? 1 : -1; + // Cj = 1 if on equator + CT const C1 = sign_C1 * cos_beta1 * sin_alpha1; + CT const C2 = sign_C2 * cos_beta2 * sin_alpha2; + + CT const sqrt_1_C1_sqr = math::sqrt(c1 - math::sqr(C1)); + CT const sqrt_1_C2_sqr = math::sqrt(c1 - math::sqr(C2)); + + // handle special case: segments on the equator + bool const on_equator1 = math::equals(sqrt_1_C1_sqr, c0); + bool const on_equator2 = math::equals(sqrt_1_C2_sqr, c0); + if (on_equator1 && on_equator2) + { + return false; + } + else if (on_equator1) + { + CT const dL2 = d_lambda_e_sqr(sin_beta2, c0, C2, sqrt_1_C2_sqr, e_sqr); + CT const asin_t2_t02 = asin(C2 * tan_beta2 / sqrt_1_C2_sqr); + lat = c0; + lon = lon2 - asin_t2_t02 + dL2; + return true; + } + else if (on_equator2) + { + CT const dL1 = d_lambda_e_sqr(sin_beta1, c0, C1, sqrt_1_C1_sqr, e_sqr); + CT const asin_t1_t01 = asin(C1 * tan_beta1 / sqrt_1_C1_sqr); + lat = c0; + lon = lon1 - asin_t1_t01 + dL1; + return true; + } + + CT const t01 = sqrt_1_C1_sqr / C1; + CT const t02 = sqrt_1_C2_sqr / C2; + + CT const asin_t1_t01 = asin(tan_beta1 / t01); + CT const asin_t2_t02 = asin(tan_beta2 / t02); + CT const t01_t02 = t01 * t02; + CT const t01_t02_2 = c2 * t01_t02; + CT const sqr_t01_sqr_t02 = math::sqr(t01) + math::sqr(t02); + + CT t = tan_beta1; + int t_id = 0; + + // find the initial t using simplified spherical solution + // though not entirely since the reduced latitudes and azimuths are spheroidal + // [Sjoberg07] + CT const k_base = lon1 - lon2 + asin_t2_t02 - asin_t1_t01; + + { + CT const K = sin(k_base); + CT const d1 = sqr_t01_sqr_t02; + //CT const d2 = t01_t02_2 * math::sqrt(c1 - math::sqr(K)); + CT const d2 = t01_t02_2 * cos(k_base); + CT const D1 = math::sqrt(d1 - d2); + CT const D2 = math::sqrt(d1 + d2); + CT const K_t01_t02 = K * t01_t02; + + CT const T1 = K_t01_t02 / D1; + CT const T2 = K_t01_t02 / D2; + CT asin_T1_t01 = 0; + CT asin_T1_t02 = 0; + CT asin_T2_t01 = 0; + CT asin_T2_t02 = 0; + + // test 4 possible results + CT l1 = 0, l2 = 0, dl = 0; + bool found = check_t<0>( T1, + lon1, asin_T1_t01 = asin(T1 / t01), asin_t1_t01, + lon2, asin_T1_t02 = asin(T1 / t02), asin_t2_t02, + t, l1, l2, dl, t_id) + || check_t<1>(-T1, + lon1, -asin_T1_t01 , asin_t1_t01, + lon2, -asin_T1_t02 , asin_t2_t02, + t, l1, l2, dl, t_id) + || check_t<2>( T2, + lon1, asin_T2_t01 = asin(T2 / t01), asin_t1_t01, + lon2, asin_T2_t02 = asin(T2 / t02), asin_t2_t02, + t, l1, l2, dl, t_id) + || check_t<3>(-T2, + lon1, -asin_T2_t01 , asin_t1_t01, + lon2, -asin_T2_t02 , asin_t2_t02, + t, l1, l2, dl, t_id); + + boost::ignore_unused(found); + } + + // [Sjoberg07] + //int const d2_sign = t_id < 2 ? -1 : 1; + int const t_sign = (t_id % 2) ? -1 : 1; + // [Sjoberg02] + CT const C1_sqr = math::sqr(C1); + CT const C2_sqr = math::sqr(C2); + + CT beta = atan(t); + CT dL1 = 0, dL2 = 0; + CT asin_t_t01 = 0; + CT asin_t_t02 = 0; + + for (int i = 0; i < 10; ++i) + { + CT const sin_beta = sin(beta); + + // integrals approximation + dL1 = d_lambda_e_sqr(sin_beta1, sin_beta, C1, sqrt_1_C1_sqr, e_sqr); + dL2 = d_lambda_e_sqr(sin_beta2, sin_beta, C2, sqrt_1_C2_sqr, e_sqr); + + // [Sjoberg07] + /*CT const k = k_base + dL1 - dL2; + CT const K = sin(k); + CT const d1 = sqr_t01_sqr_t02; + //CT const d2 = t01_t02_2 * math::sqrt(c1 - math::sqr(K)); + CT const d2 = t01_t02_2 * cos(k); + CT const D = math::sqrt(d1 + d2_sign * d2); + CT const t_new = t_sign * K * t01_t02 / D; + CT const dt = math::abs(t_new - t); + t = t_new; + CT const new_beta = atan(t); + CT const dbeta = math::abs(new_beta - beta); + beta = new_beta;*/ + + // [Sjoberg02] - it converges faster + // Newton–Raphson method + asin_t_t01 = asin(t / t01); + asin_t_t02 = asin(t / t02); + CT const R1 = asin_t_t01 + dL1; + CT const R2 = asin_t_t02 + dL2; + CT const cos_beta = cos(beta); + CT const cos_beta_sqr = math::sqr(cos_beta); + CT const G = c1 - e_sqr * cos_beta_sqr; + CT const f1 = C1 / cos_beta * math::sqrt(G / (cos_beta_sqr - C1_sqr)); + CT const f2 = C2 / cos_beta * math::sqrt(G / (cos_beta_sqr - C2_sqr)); + CT const abs_f1 = math::abs(f1); + CT const abs_f2 = math::abs(f2); + CT const dbeta = t_sign * (k_base - R2 + R1) / (abs_f1 + abs_f2); + + if (math::equals(dbeta, CT(0))) + { + break; + } + + beta = beta - dbeta; + t = tan(beta); + } + + // t = tan(beta) = (1-f)tan(lat) + lat = atan(t / one_minus_f); + + CT const l1 = lon1 + asin_t_t01 - asin_t1_t01 + dL1; + //CT const l2 = lon2 + asin_t_t02 - asin_t2_t02 + dL2; + lon = l1; + + return true; + } + +private: + /*! Approximation of dLambda_j [Sjoberg07], expanded into taylor series in e^2 + Maxima script: + dLI_j(c_j, sinB_j, sinB) := integrate(1 / (sqrt(1 - c_j ^ 2 - x ^ 2)*(1 + sqrt(1 - e2*(1 - x ^ 2)))), x, sinB_j, sinB); + dL_j(c_j, B_j, B) := -e2 * c_j * dLI_j(c_j, B_j, B); + S: taylor(dLI_j(c_j, sinB_j, sinB), e2, 0, 3); + assume(c_j < 1); + assume(c_j > 0); + L1: factor(integrate(sqrt(-x ^ 2 - c_j ^ 2 + 1) / (x ^ 2 + c_j ^ 2 - 1), x)); + L2: factor(integrate(((x ^ 2 - 1)*sqrt(-x ^ 2 - c_j ^ 2 + 1)) / (x ^ 2 + c_j ^ 2 - 1), x)); + L3: factor(integrate(((x ^ 4 - 2 * x ^ 2 + 1)*sqrt(-x ^ 2 - c_j ^ 2 + 1)) / (x ^ 2 + c_j ^ 2 - 1), x)); + L4: factor(integrate(((x ^ 6 - 3 * x ^ 4 + 3 * x ^ 2 - 1)*sqrt(-x ^ 2 - c_j ^ 2 + 1)) / (x ^ 2 + c_j ^ 2 - 1), x)); + */ + static inline CT d_lambda_e_sqr(CT const& sin_betaj, CT const& sin_beta, + CT const& Cj, CT const& sqrt_1_Cj_sqr, + CT const& e_sqr) + { + if (Order == 0) + { + return 0; + } + + CT const c2 = 2; + + CT const asin_B = asin(sin_beta / sqrt_1_Cj_sqr); + CT const asin_Bj = asin(sin_betaj / sqrt_1_Cj_sqr); + CT const L0 = (asin_B - asin_Bj) / c2; + + if (Order == 1) + { + return -Cj * e_sqr * L0; + } + + CT const c1 = 1; + CT const c16 = 16; + + CT const X = sin_beta; + CT const Xj = sin_betaj; + CT const Cj_sqr = math::sqr(Cj); + CT const Cj_sqr_plus_one = Cj_sqr + c1; + CT const one_minus_Cj_sqr = c1 - Cj_sqr; + CT const sqrt_Y = math::sqrt(-math::sqr(X) + one_minus_Cj_sqr); + CT const sqrt_Yj = math::sqrt(-math::sqr(Xj) + one_minus_Cj_sqr); + CT const L1 = (Cj_sqr_plus_one * (asin_B - asin_Bj) + X * sqrt_Y - Xj * sqrt_Yj) / c16; + + if (Order == 2) + { + return -Cj * e_sqr * (L0 + e_sqr * L1); + } + + CT const c3 = 3; + CT const c5 = 5; + CT const c128 = 128; + + CT const E = Cj_sqr * (c3 * Cj_sqr + c2) + c3; + CT const X_sqr = math::sqr(X); + CT const Xj_sqr = math::sqr(Xj); + CT const F = X * (-c2 * X_sqr + c3 * Cj_sqr + c5); + CT const Fj = Xj * (-c2 * Xj_sqr + c3 * Cj_sqr + c5); + CT const L2 = (E * (asin_B - asin_Bj) + F * sqrt_Y - Fj * sqrt_Yj) / c128; + + if (Order == 3) + { + return -Cj * e_sqr * (L0 + e_sqr * (L1 + e_sqr * L2)); + } + + CT const c8 = 8; + CT const c9 = 9; + CT const c10 = 10; + CT const c15 = 15; + CT const c24 = 24; + CT const c26 = 26; + CT const c33 = 33; + CT const c6144 = 6144; + + CT const G = Cj_sqr * (Cj_sqr * (Cj_sqr * c15 + c9) + c9) + c15; + CT const H = -c10 * Cj_sqr - c26; + CT const I = Cj_sqr * (Cj_sqr * c15 + c24) + c33; + CT const J = X_sqr * (X * (c8 * X_sqr + H)) + X * I; + CT const Jj = Xj_sqr * (Xj * (c8 * Xj_sqr + H)) + Xj * I; + CT const L3 = (G * (asin_B - asin_Bj) + J * sqrt_Y - Jj * sqrt_Yj) / c6144; + + // Order 4 and higher + return -Cj * e_sqr * (L0 + e_sqr * (L1 + e_sqr * (L2 + e_sqr * L3))); + } + + static inline CT fj(CT const& cos_beta, CT const& cos2_beta, CT const& Cj, CT const& e_sqr) + { + CT const c1 = 1; + CT const Cj_sqr = math::sqr(Cj); + return Cj / cos_beta * math::sqrt((c1 - e_sqr * cos2_beta) / (cos2_beta - Cj_sqr)); + } + + template + static inline bool check_t(CT const& t, + CT const& lon_a1, CT const& asin_t_t01, CT const& asin_t1_t01, + CT const& lon_b1, CT const& asin_t_t02, CT const& asin_t2_t02, + CT & current_t, CT & current_lon1, CT & current_lon2, CT & current_dlon, + int & t_id) + { + CT const lon1 = lon_a1 + asin_t_t01 - asin_t1_t01; + CT const lon2 = lon_b1 + asin_t_t02 - asin_t2_t02; + + // TODO - true angle difference + CT const dlon = math::abs(lon2 - lon1); + + bool are_equal = math::equals(dlon, CT(0)); + + if ((TId == 0) || are_equal || dlon < current_dlon) + { + current_t = t; + current_lon1 = lon1; + current_lon2 = lon2; + current_dlon = dlon; + t_id = TId; + } + + return are_equal; + } +}; + +}}} // namespace boost::geometry::formula + + +#endif // BOOST_GEOMETRY_FORMULAS_SJOBERG_INTERSECTION_HPP diff --git a/include/boost/geometry/formulas/thomas_direct.hpp b/include/boost/geometry/formulas/thomas_direct.hpp index 0ae4ab218..f8a7f8394 100644 --- a/include/boost/geometry/formulas/thomas_direct.hpp +++ b/include/boost/geometry/formulas/thomas_direct.hpp @@ -85,16 +85,23 @@ public: CT const f = detail::flattening(spheroid); CT const one_minus_f = c1 - f; - CT const pi_half = math::pi() / c2; + CT const pi = math::pi(); + CT const pi_half = pi / c2; - CT const theta1 = math::equals(lat1, pi_half) ? lat1 : - math::equals(lat1, -pi_half) ? lat1 : - atan(one_minus_f * tan(lat1)); + // keep azimuth small - experiments show low accuracy + // if the azimuth is closer to (+-)180 deg. + CT azi12_alt = azimuth12; + CT lat1_alt = lat1; + bool alter_result = vflip_if_south(lat1, azimuth12, lat1_alt, azi12_alt); + + CT const theta1 = math::equals(lat1_alt, pi_half) ? lat1_alt : + math::equals(lat1_alt, -pi_half) ? lat1_alt : + atan(one_minus_f * tan(lat1_alt)); CT const sin_theta1 = sin(theta1); CT const cos_theta1 = cos(theta1); - CT const sin_a12 = sin(azimuth12); - CT const cos_a12 = cos(azimuth12); + CT const sin_a12 = sin(azi12_alt); + CT const cos_a12 = cos(azi12_alt); CT const M = cos_theta1 * sin_a12; // cos_theta0 CT const theta0 = acos(M); @@ -106,11 +113,20 @@ public: CT const D = (c1 - C2) * (c1 - C2 - C1 * M); CT const P = C2 * (c1 + C1 * M / c2) / D; - CT const cos_sigma1 = sin_theta1 / sin_theta0; + // special case for equator: + // sin_theta0 = 0 <=> lat1 = 0 ^ |azimuth12| = pi/2 + // NOTE: in this case it doesn't matter what's the value of cos_sigma1 because + // theta1=0, theta0=0, M=1|-1, C2=0 so X=0 and Y=0 so d_sigma=d + // cos_a12=0 so N=0, therefore + // lat2=0, azi21=pi/2|-pi/2 + // d_eta = atan2(sin_d_sigma, cos_d_sigma) + // H = C1 * d_sigma + CT const cos_sigma1 = math::equals(sin_theta0, c0) + ? c1 + : normalized1_1(sin_theta1 / sin_theta0); CT const sigma1 = acos(cos_sigma1); CT const d = distance / (a * D); CT const u = 2 * (sigma1 - d); - CT const sin_sigma1 = sin(sigma1); CT const cos_d = cos(d); CT const sin_d = sin(d); CT const cos_u = cos(u); @@ -127,17 +143,15 @@ public: if (BOOST_GEOMETRY_CONDITION(CalcRevAzimuth)) { result.reverse_azimuth = atan2(M, N * cos_d_sigma - sin_theta1 * sin_d_sigma); + + if (alter_result) + { + vflip_rev_azi(result.reverse_azimuth, azimuth12); + } } if (BOOST_GEOMETRY_CONDITION(CalcCoordinates)) { - CT const sin_a21 = sin(result.reverse_azimuth); - CT const cos_a21 = cos(result.reverse_azimuth); - - CT const tan_lat2 = (sin_theta1 * cos_d_sigma + N * sin_d_sigma) * sin_a21 / (one_minus_f * M); - - result.lat2 = atan(tan_lat2); - CT const S_sigma = c2 * sigma1 - d_sigma; CT const cos_S_sigma = cos(S_sigma); CT const d_eta = atan2(sin_d_sigma * sin_a12, cos_theta1 * cos_d_sigma - sin_theta1 * sin_d_sigma * cos_a12); @@ -145,21 +159,88 @@ public: CT const d_lambda = d_eta - H; result.lon2 = lon1 + d_lambda; + + if (! math::equals(M, c0)) + { + CT const sin_a21 = sin(result.reverse_azimuth); + CT const tan_theta2 = (sin_theta1 * cos_d_sigma + N * sin_d_sigma) * sin_a21 / M; + result.lat2 = atan(tan_theta2 / one_minus_f); + } + else + { + CT const sigma2 = S_sigma - sigma1; + //theta2 = asin(cos(sigma2)) <=> sin_theta0 = 1 + CT const tan_theta2 = cos(sigma2) / sin(sigma2); + result.lat2 = atan(tan_theta2 / one_minus_f); + } + + if (alter_result) + { + result.lat2 = -result.lat2; + } } if (BOOST_GEOMETRY_CONDITION(CalcQuantities)) { - typedef differential_quantities quantities; + typedef differential_quantities quantities; quantities::apply(lon1, lat1, result.lon2, result.lat2, azimuth12, result.reverse_azimuth, b, f, - result.reduced_length, result.geodesic_scale, - quantities::J12_calc_f2); + result.reduced_length, result.geodesic_scale); } return result; } +private: + static inline bool vflip_if_south(CT const& lat1, CT const& azi12, CT & lat1_alt, CT & azi12_alt) + { + CT const c2 = 2; + CT const pi = math::pi(); + CT const pi_half = pi / c2; + + if (azi12 > pi_half) + { + azi12_alt = pi - azi12; + lat1_alt = -lat1; + return true; + } + else if (azi12 < -pi_half) + { + azi12_alt = -pi - azi12; + lat1_alt = -lat1; + return true; + } + + return false; + } + + static inline void vflip_rev_azi(CT & rev_azi, CT const& azimuth12) + { + CT const c0 = 0; + CT const pi = math::pi(); + + if (rev_azi == c0) + { + rev_azi = azimuth12 >= 0 ? pi : -pi; + } + else if (rev_azi > c0) + { + rev_azi = pi - rev_azi; + } + else + { + rev_azi = -pi - rev_azi; + } + } + + static inline CT normalized1_1(CT const& value) + { + CT const c1 = 1; + return value > c1 ? c1 : + value < -c1 ? -c1 : + value; + } }; }}} // namespace boost::geometry::formula diff --git a/include/boost/geometry/formulas/thomas_inverse.hpp b/include/boost/geometry/formulas/thomas_inverse.hpp index 9ca2f331c..d68c9de05 100644 --- a/include/boost/geometry/formulas/thomas_inverse.hpp +++ b/include/boost/geometry/formulas/thomas_inverse.hpp @@ -163,9 +163,14 @@ public: CT const F = c2*Y-E*(c4-X); CT const M = CT(32)*T-(CT(20)*T-A)*X-(B+c4)*Y; CT const G = f*T/c2 + f_sqr_per_64 * M; + + // TODO: + // If d_lambda is close to 90 or -90 deg then tan(d_lambda) is big + // and F is small. The result is not accurate. + // In the edge case the result may be 2 orders of magnitude less + // accurate than Andoyer's. CT const tan_d_lambda = tan(d_lambda); CT const Q = -(F*G*tan_d_lambda) / c4; - CT const d_lambda_m_p = (d_lambda + Q) / c2; CT const tan_d_lambda_m_p = tan(d_lambda_m_p); @@ -199,12 +204,11 @@ public: if (BOOST_GEOMETRY_CONDITION(CalcQuantities)) { - typedef differential_quantities quantities; + typedef differential_quantities quantities; quantities::apply(lon1, lat1, lon2, lat2, result.azimuth, result.reverse_azimuth, get_radius<2>(spheroid), f, - result.reduced_length, result.geodesic_scale, - quantities::J12_calc_f2); + result.reduced_length, result.geodesic_scale); } return result; diff --git a/include/boost/geometry/formulas/vincenty_direct.hpp b/include/boost/geometry/formulas/vincenty_direct.hpp index 5e9464632..f3647ff4e 100644 --- a/include/boost/geometry/formulas/vincenty_direct.hpp +++ b/include/boost/geometry/formulas/vincenty_direct.hpp @@ -167,12 +167,11 @@ public: if (BOOST_GEOMETRY_CONDITION(CalcQuantities)) { - typedef differential_quantities quantities; + typedef differential_quantities quantities; quantities::apply(lon1, lat1, result.lon2, result.lat2, azimuth12, result.reverse_azimuth, radius_b, flattening, - result.reduced_length, result.geodesic_scale, - quantities::J12_calc_f2); // TODO use more accurate J12 + result.reduced_length, result.geodesic_scale); } return result; diff --git a/include/boost/geometry/formulas/vincenty_inverse.hpp b/include/boost/geometry/formulas/vincenty_inverse.hpp index 94097cb86..bbda00036 100644 --- a/include/boost/geometry/formulas/vincenty_inverse.hpp +++ b/include/boost/geometry/formulas/vincenty_inverse.hpp @@ -203,12 +203,11 @@ public: if (BOOST_GEOMETRY_CONDITION(CalcQuantities)) { - typedef differential_quantities quantities; + typedef differential_quantities quantities; quantities::apply(lon1, lat1, lon2, lat2, result.azimuth, result.reverse_azimuth, radius_b, flattening, - result.reduced_length, result.geodesic_scale, - quantities::J12_calc_f2); // TODO use more accurate J12 + result.reduced_length, result.geodesic_scale); } return result; diff --git a/include/boost/geometry/geometries/box.hpp b/include/boost/geometry/geometries/box.hpp index 97a4ba06d..23fd098f6 100644 --- a/include/boost/geometry/geometries/box.hpp +++ b/include/boost/geometry/geometries/box.hpp @@ -53,7 +53,7 @@ The box can also take a latlong point type as template parameter. template class box { - BOOST_CONCEPT_ASSERT( (concept::Point) ); + BOOST_CONCEPT_ASSERT( (concepts::Point) ); public: diff --git a/include/boost/geometry/geometries/concepts/box_concept.hpp b/include/boost/geometry/geometries/concepts/box_concept.hpp index ea0d84cf3..816a90f63 100644 --- a/include/boost/geometry/geometries/concepts/box_concept.hpp +++ b/include/boost/geometry/geometries/concepts/box_concept.hpp @@ -26,7 +26,7 @@ #include -namespace boost { namespace geometry { namespace concept +namespace boost { namespace geometry { namespace concepts { @@ -130,7 +130,7 @@ public : #endif }; -}}} // namespace boost::geometry::concept +}}} // namespace boost::geometry::concepts #endif // BOOST_GEOMETRY_GEOMETRIES_CONCEPTS_BOX_CONCEPT_HPP diff --git a/include/boost/geometry/geometries/concepts/check.hpp b/include/boost/geometry/geometries/concepts/check.hpp index 07ef84f4a..f609d5f13 100644 --- a/include/boost/geometry/geometries/concepts/check.hpp +++ b/include/boost/geometry/geometries/concepts/check.hpp @@ -71,108 +71,108 @@ struct check : not_implemented template struct check - : detail::concept_check::check > + : detail::concept_check::check > {}; template struct check - : detail::concept_check::check > + : detail::concept_check::check > {}; template struct check - : detail::concept_check::check > + : detail::concept_check::check > {}; template struct check - : detail::concept_check::check > + : detail::concept_check::check > {}; template struct check - : detail::concept_check::check > + : detail::concept_check::check > {}; template struct check - : detail::concept_check::check > + : detail::concept_check::check > {}; template struct check - : detail::concept_check::check > + : detail::concept_check::check > {}; template struct check - : detail::concept_check::check > + : detail::concept_check::check > {}; template struct check - : detail::concept_check::check > + : detail::concept_check::check > {}; template struct check - : detail::concept_check::check > + : detail::concept_check::check > {}; template struct check - : detail::concept_check::check > + : detail::concept_check::check > {}; template struct check - : detail::concept_check::check > + : detail::concept_check::check > {}; template struct check - : detail::concept_check::check > + : detail::concept_check::check > {}; template struct check - : detail::concept_check::check > + : detail::concept_check::check > {}; template struct check - : detail::concept_check::check > + : detail::concept_check::check > {}; template struct check - : detail::concept_check::check > + : detail::concept_check::check > {}; template struct check - : detail::concept_check::check > + : detail::concept_check::check > {}; template struct check - : detail::concept_check::check > + : detail::concept_check::check > {}; @@ -182,7 +182,7 @@ struct check -namespace concept +namespace concepts { @@ -234,7 +234,7 @@ inline void check_concepts_and_equal_dimensions() } -} // namespace concept +} // namespace concepts }} // namespace boost::geometry diff --git a/include/boost/geometry/geometries/concepts/linestring_concept.hpp b/include/boost/geometry/geometries/concepts/linestring_concept.hpp index 091336fe3..6775239d0 100644 --- a/include/boost/geometry/geometries/concepts/linestring_concept.hpp +++ b/include/boost/geometry/geometries/concepts/linestring_concept.hpp @@ -28,7 +28,7 @@ -namespace boost { namespace geometry { namespace concept +namespace boost { namespace geometry { namespace concepts { @@ -76,7 +76,7 @@ class Linestring #ifndef DOXYGEN_NO_CONCEPT_MEMBERS typedef typename point_type::type point_type; - BOOST_CONCEPT_ASSERT( (concept::Point) ); + BOOST_CONCEPT_ASSERT( (concepts::Point) ); BOOST_CONCEPT_ASSERT( (boost::RandomAccessRangeConcept) ); public : @@ -105,7 +105,7 @@ class ConstLinestring #ifndef DOXYGEN_NO_CONCEPT_MEMBERS typedef typename point_type::type point_type; - BOOST_CONCEPT_ASSERT( (concept::ConstPoint) ); + BOOST_CONCEPT_ASSERT( (concepts::ConstPoint) ); //BOOST_CONCEPT_ASSERT( (boost::RandomAccessRangeConcept) ); // Relaxed the concept. BOOST_CONCEPT_ASSERT( (boost::ForwardRangeConcept) ); @@ -119,7 +119,7 @@ public : #endif }; -}}} // namespace boost::geometry::concept +}}} // namespace boost::geometry::concepts #endif // BOOST_GEOMETRY_GEOMETRIES_CONCEPTS_LINESTRING_CONCEPT_HPP diff --git a/include/boost/geometry/geometries/concepts/multi_linestring_concept.hpp b/include/boost/geometry/geometries/concepts/multi_linestring_concept.hpp index f13f7ac7e..793167090 100644 --- a/include/boost/geometry/geometries/concepts/multi_linestring_concept.hpp +++ b/include/boost/geometry/geometries/concepts/multi_linestring_concept.hpp @@ -24,7 +24,7 @@ #include -namespace boost { namespace geometry { namespace concept +namespace boost { namespace geometry { namespace concepts { @@ -45,7 +45,7 @@ class MultiLinestring #ifndef DOXYGEN_NO_CONCEPT_MEMBERS typedef typename boost::range_value::type linestring_type; - BOOST_CONCEPT_ASSERT( (concept::Linestring) ); + BOOST_CONCEPT_ASSERT( (concepts::Linestring) ); BOOST_CONCEPT_ASSERT( (boost::RandomAccessRangeConcept) ); @@ -73,7 +73,7 @@ class ConstMultiLinestring #ifndef DOXYGEN_NO_CONCEPT_MEMBERS typedef typename boost::range_value::type linestring_type; - BOOST_CONCEPT_ASSERT( (concept::ConstLinestring) ); + BOOST_CONCEPT_ASSERT( (concepts::ConstLinestring) ); BOOST_CONCEPT_ASSERT( (boost::RandomAccessRangeConcept) ); @@ -85,7 +85,7 @@ public : #endif }; -}}} // namespace boost::geometry::concept +}}} // namespace boost::geometry::concepts #endif // BOOST_GEOMETRY_GEOMETRIES_CONCEPTS_MULTI_LINESTRING_CONCEPT_HPP diff --git a/include/boost/geometry/geometries/concepts/multi_point_concept.hpp b/include/boost/geometry/geometries/concepts/multi_point_concept.hpp index 81c087166..9e205f163 100644 --- a/include/boost/geometry/geometries/concepts/multi_point_concept.hpp +++ b/include/boost/geometry/geometries/concepts/multi_point_concept.hpp @@ -24,7 +24,7 @@ #include -namespace boost { namespace geometry { namespace concept +namespace boost { namespace geometry { namespace concepts { @@ -44,7 +44,7 @@ class MultiPoint #ifndef DOXYGEN_NO_CONCEPT_MEMBERS typedef typename boost::range_value::type point_type; - BOOST_CONCEPT_ASSERT( (concept::Point) ); + BOOST_CONCEPT_ASSERT( (concepts::Point) ); BOOST_CONCEPT_ASSERT( (boost::RandomAccessRangeConcept) ); @@ -72,7 +72,7 @@ class ConstMultiPoint #ifndef DOXYGEN_NO_CONCEPT_MEMBERS typedef typename boost::range_value::type point_type; - BOOST_CONCEPT_ASSERT( (concept::ConstPoint) ); + BOOST_CONCEPT_ASSERT( (concepts::ConstPoint) ); BOOST_CONCEPT_ASSERT( (boost::RandomAccessRangeConcept) ); @@ -84,7 +84,7 @@ public : #endif }; -}}} // namespace boost::geometry::concept +}}} // namespace boost::geometry::concepts #endif // BOOST_GEOMETRY_GEOMETRIES_CONCEPTS_MULTI_POINT_CONCEPT_HPP diff --git a/include/boost/geometry/geometries/concepts/multi_polygon_concept.hpp b/include/boost/geometry/geometries/concepts/multi_polygon_concept.hpp index b13d330f3..63de6e5bf 100644 --- a/include/boost/geometry/geometries/concepts/multi_polygon_concept.hpp +++ b/include/boost/geometry/geometries/concepts/multi_polygon_concept.hpp @@ -23,7 +23,7 @@ #include -namespace boost { namespace geometry { namespace concept +namespace boost { namespace geometry { namespace concepts { @@ -44,7 +44,7 @@ class MultiPolygon #ifndef DOXYGEN_NO_CONCEPT_MEMBERS typedef typename boost::range_value::type polygon_type; - BOOST_CONCEPT_ASSERT( (concept::Polygon) ); + BOOST_CONCEPT_ASSERT( (concepts::Polygon) ); BOOST_CONCEPT_ASSERT( (boost::RandomAccessRangeConcept) ); @@ -72,7 +72,7 @@ class ConstMultiPolygon #ifndef DOXYGEN_NO_CONCEPT_MEMBERS typedef typename boost::range_value::type polygon_type; - BOOST_CONCEPT_ASSERT( (concept::ConstPolygon) ); + BOOST_CONCEPT_ASSERT( (concepts::ConstPolygon) ); BOOST_CONCEPT_ASSERT( (boost::RandomAccessRangeConcept) ); @@ -85,7 +85,7 @@ public : }; -}}} // namespace boost::geometry::concept +}}} // namespace boost::geometry::concepts #endif // BOOST_GEOMETRY_GEOMETRIES_CONCEPTS_MULTI_POLYGON_CONCEPT_HPP diff --git a/include/boost/geometry/geometries/concepts/point_concept.hpp b/include/boost/geometry/geometries/concepts/point_concept.hpp index 52f8d038e..4001f4e06 100644 --- a/include/boost/geometry/geometries/concepts/point_concept.hpp +++ b/include/boost/geometry/geometries/concepts/point_concept.hpp @@ -30,7 +30,7 @@ -namespace boost { namespace geometry { namespace concept +namespace boost { namespace geometry { namespace concepts { /*! @@ -187,6 +187,6 @@ public: #endif }; -}}} // namespace boost::geometry::concept +}}} // namespace boost::geometry::concepts #endif // BOOST_GEOMETRY_GEOMETRIES_CONCEPTS_POINT_CONCEPT_HPP diff --git a/include/boost/geometry/geometries/concepts/polygon_concept.hpp b/include/boost/geometry/geometries/concepts/polygon_concept.hpp index b478a2274..58b780009 100644 --- a/include/boost/geometry/geometries/concepts/polygon_concept.hpp +++ b/include/boost/geometry/geometries/concepts/polygon_concept.hpp @@ -27,7 +27,7 @@ #include -namespace boost { namespace geometry { namespace concept +namespace boost { namespace geometry { namespace concepts { /*! @@ -48,8 +48,8 @@ class Polygon typedef typename point_type::type point_type; typedef typename ring_type::type ring_type; - BOOST_CONCEPT_ASSERT( (concept::Point) ); - BOOST_CONCEPT_ASSERT( (concept::Ring) ); + BOOST_CONCEPT_ASSERT( (concepts::Point) ); + BOOST_CONCEPT_ASSERT( (concepts::Ring) ); //BOOST_CONCEPT_ASSERT( (boost::RandomAccessRangeConcept) ); @@ -101,8 +101,8 @@ class ConstPolygon typedef typename point_type::type point_type; typedef typename ring_type::type ring_type; - BOOST_CONCEPT_ASSERT( (concept::ConstPoint) ); - BOOST_CONCEPT_ASSERT( (concept::ConstRing) ); + BOOST_CONCEPT_ASSERT( (concepts::ConstPoint) ); + BOOST_CONCEPT_ASSERT( (concepts::ConstRing) ); ////BOOST_CONCEPT_ASSERT( (boost::RandomAccessRangeConcept) ); @@ -130,6 +130,6 @@ public: #endif }; -}}} // namespace boost::geometry::concept +}}} // namespace boost::geometry::concepts #endif // BOOST_GEOMETRY_GEOMETRIES_CONCEPTS_POLYGON_CONCEPT_HPP diff --git a/include/boost/geometry/geometries/concepts/ring_concept.hpp b/include/boost/geometry/geometries/concepts/ring_concept.hpp index 02a36c96f..d75d42843 100644 --- a/include/boost/geometry/geometries/concepts/ring_concept.hpp +++ b/include/boost/geometry/geometries/concepts/ring_concept.hpp @@ -27,7 +27,7 @@ #include -namespace boost { namespace geometry { namespace concept +namespace boost { namespace geometry { namespace concepts { @@ -52,7 +52,7 @@ class Ring #ifndef DOXYGEN_NO_CONCEPT_MEMBERS typedef typename point_type::type point_type; - BOOST_CONCEPT_ASSERT( (concept::Point) ); + BOOST_CONCEPT_ASSERT( (concepts::Point) ); BOOST_CONCEPT_ASSERT( (boost::RandomAccessRangeConcept) ); public : @@ -81,7 +81,7 @@ class ConstRing #ifndef DOXYGEN_NO_CONCEPT_MEMBERS typedef typename point_type::type point_type; - BOOST_CONCEPT_ASSERT( (concept::ConstPoint) ); + BOOST_CONCEPT_ASSERT( (concepts::ConstPoint) ); BOOST_CONCEPT_ASSERT( (boost::RandomAccessRangeConcept) ); @@ -93,7 +93,7 @@ public : #endif }; -}}} // namespace boost::geometry::concept +}}} // namespace boost::geometry::concepts #endif // BOOST_GEOMETRY_GEOMETRIES_CONCEPTS_RING_CONCEPT_HPP diff --git a/include/boost/geometry/geometries/concepts/segment_concept.hpp b/include/boost/geometry/geometries/concepts/segment_concept.hpp index 8d2d30015..6a1c80486 100644 --- a/include/boost/geometry/geometries/concepts/segment_concept.hpp +++ b/include/boost/geometry/geometries/concepts/segment_concept.hpp @@ -23,7 +23,7 @@ #include -namespace boost { namespace geometry { namespace concept +namespace boost { namespace geometry { namespace concepts { @@ -51,7 +51,7 @@ class Segment #ifndef DOXYGEN_NO_CONCEPT_MEMBERS typedef typename point_type::type point_type; - BOOST_CONCEPT_ASSERT( (concept::Point) ); + BOOST_CONCEPT_ASSERT( (concepts::Point) ); template @@ -96,7 +96,7 @@ class ConstSegment typedef typename point_type::type point_type; typedef typename coordinate_type::type coordinate_type; - BOOST_CONCEPT_ASSERT( (concept::ConstPoint) ); + BOOST_CONCEPT_ASSERT( (concepts::ConstPoint) ); template @@ -129,7 +129,7 @@ public : }; -}}} // namespace boost::geometry::concept +}}} // namespace boost::geometry::concepts #endif // BOOST_GEOMETRY_GEOMETRIES_CONCEPTS_SEGMENT_CONCEPT_HPP diff --git a/include/boost/geometry/geometries/linestring.hpp b/include/boost/geometry/geometries/linestring.hpp index 22c9c99de..280c4be7a 100644 --- a/include/boost/geometry/geometries/linestring.hpp +++ b/include/boost/geometry/geometries/linestring.hpp @@ -59,7 +59,7 @@ template > class linestring : public Container > { - BOOST_CONCEPT_ASSERT( (concept::Point) ); + BOOST_CONCEPT_ASSERT( (concepts::Point) ); typedef Container > base_type; diff --git a/include/boost/geometry/geometries/multi_linestring.hpp b/include/boost/geometry/geometries/multi_linestring.hpp index cd08fdbe1..67003522b 100644 --- a/include/boost/geometry/geometries/multi_linestring.hpp +++ b/include/boost/geometry/geometries/multi_linestring.hpp @@ -55,7 +55,7 @@ template > class multi_linestring : public Container > { - BOOST_CONCEPT_ASSERT( (concept::Linestring) ); + BOOST_CONCEPT_ASSERT( (concepts::Linestring) ); #ifndef BOOST_NO_CXX11_HDR_INITIALIZER_LIST diff --git a/include/boost/geometry/geometries/multi_point.hpp b/include/boost/geometry/geometries/multi_point.hpp index ab4cd8817..9579f4f60 100644 --- a/include/boost/geometry/geometries/multi_point.hpp +++ b/include/boost/geometry/geometries/multi_point.hpp @@ -58,7 +58,7 @@ template > class multi_point : public Container > { - BOOST_CONCEPT_ASSERT( (concept::Point) ); + BOOST_CONCEPT_ASSERT( (concepts::Point) ); typedef Container > base_type; diff --git a/include/boost/geometry/geometries/multi_polygon.hpp b/include/boost/geometry/geometries/multi_polygon.hpp index 9db74b4ec..94cd92271 100644 --- a/include/boost/geometry/geometries/multi_polygon.hpp +++ b/include/boost/geometry/geometries/multi_polygon.hpp @@ -54,7 +54,7 @@ template > class multi_polygon : public Container > { - BOOST_CONCEPT_ASSERT( (concept::Polygon) ); + BOOST_CONCEPT_ASSERT( (concepts::Polygon) ); #ifndef BOOST_NO_CXX11_HDR_INITIALIZER_LIST diff --git a/include/boost/geometry/geometries/pointing_segment.hpp b/include/boost/geometry/geometries/pointing_segment.hpp index 2c4284d10..f865a8a8c 100644 --- a/include/boost/geometry/geometries/pointing_segment.hpp +++ b/include/boost/geometry/geometries/pointing_segment.hpp @@ -44,8 +44,8 @@ class pointing_segment typename boost::mpl::if_ < boost::is_const, - concept::Point, - concept::ConstPoint + concepts::Point, + concepts::ConstPoint > ) ); diff --git a/include/boost/geometry/geometries/polygon.hpp b/include/boost/geometry/geometries/polygon.hpp index 5e6064e89..5d8a0f21f 100644 --- a/include/boost/geometry/geometries/polygon.hpp +++ b/include/boost/geometry/geometries/polygon.hpp @@ -75,7 +75,7 @@ template > class polygon { - BOOST_CONCEPT_ASSERT( (concept::Point) ); + BOOST_CONCEPT_ASSERT( (concepts::Point) ); public: diff --git a/include/boost/geometry/geometries/ring.hpp b/include/boost/geometry/geometries/ring.hpp index 01bcf58cf..fda0be40b 100644 --- a/include/boost/geometry/geometries/ring.hpp +++ b/include/boost/geometry/geometries/ring.hpp @@ -63,7 +63,7 @@ template > class ring : public Container > { - BOOST_CONCEPT_ASSERT( (concept::Point) ); + BOOST_CONCEPT_ASSERT( (concepts::Point) ); typedef Container > base_type; diff --git a/include/boost/geometry/geometries/segment.hpp b/include/boost/geometry/geometries/segment.hpp index af406aa09..aeb275b85 100644 --- a/include/boost/geometry/geometries/segment.hpp +++ b/include/boost/geometry/geometries/segment.hpp @@ -45,7 +45,7 @@ namespace model template class segment : public std::pair { - BOOST_CONCEPT_ASSERT( (concept::Point) ); + BOOST_CONCEPT_ASSERT( (concepts::Point) ); public : @@ -89,8 +89,8 @@ class referring_segment typename boost::mpl::if_ < boost::is_const, - concept::Point, - concept::ConstPoint + concepts::Point, + concepts::ConstPoint > ) ); diff --git a/include/boost/geometry/index/detail/algorithms/bounds.hpp b/include/boost/geometry/index/detail/algorithms/bounds.hpp index 4d2416e98..a62fda070 100644 --- a/include/boost/geometry/index/detail/algorithms/bounds.hpp +++ b/include/boost/geometry/index/detail/algorithms/bounds.hpp @@ -44,7 +44,7 @@ struct bounds template inline void bounds(Geometry const& g, Bounds & b) { - concept::check_concepts_and_equal_dimensions(); + concepts::check_concepts_and_equal_dimensions(); dispatch::bounds::apply(g, b); } diff --git a/include/boost/geometry/io/dsv/write.hpp b/include/boost/geometry/io/dsv/write.hpp index f39a2489a..f74ae7f95 100644 --- a/include/boost/geometry/io/dsv/write.hpp +++ b/include/boost/geometry/io/dsv/write.hpp @@ -418,7 +418,7 @@ inline detail::dsv::dsv_manipulator dsv(Geometry const& geometry , std::string const& list_separator = ", " ) { - concept::check(); + concepts::check(); return detail::dsv::dsv_manipulator(geometry, detail::dsv::dsv_settings(coordinate_separator, diff --git a/include/boost/geometry/io/io.hpp b/include/boost/geometry/io/io.hpp index 934006077..caafccf2b 100644 --- a/include/boost/geometry/io/io.hpp +++ b/include/boost/geometry/io/io.hpp @@ -47,7 +47,7 @@ struct read template inline void read(Geometry& geometry, std::string const& wkt) { - geometry::concept::check(); + geometry::concepts::check(); dispatch::read::apply(geometry, wkt); } diff --git a/include/boost/geometry/io/svg/svg_mapper.hpp b/include/boost/geometry/io/svg/svg_mapper.hpp index f492f07cb..6302fd43b 100644 --- a/include/boost/geometry/io/svg/svg_mapper.hpp +++ b/include/boost/geometry/io/svg/svg_mapper.hpp @@ -45,28 +45,20 @@ #include -// Helper geometries (all points are transformed to integer-points) +// Helper geometries (all points are transformed to svg-points) #include namespace boost { namespace geometry { -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace svg -{ - typedef model::point svg_point_type; -}} -#endif - #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { - -template +template struct svg_map { BOOST_MPL_ASSERT_MSG @@ -77,26 +69,26 @@ struct svg_map }; -template -struct svg_map +template +struct svg_map { template static inline void apply(std::ostream& stream, - std::string const& style, int size, + std::string const& style, double size, Point const& point, TransformStrategy const& strategy) { - detail::svg::svg_point_type ipoint; + SvgPoint ipoint; geometry::transform(point, ipoint, strategy); stream << geometry::svg(ipoint, style, size) << std::endl; } }; -template +template struct svg_map_box_seg { template static inline void apply(std::ostream& stream, - std::string const& style, int size, + std::string const& style, double size, BoxSeg1 const& box_seg, TransformStrategy const& strategy) { BoxSeg2 ibox_seg; @@ -111,23 +103,23 @@ struct svg_map_box_seg } }; -template -struct svg_map - : svg_map_box_seg > +template +struct svg_map + : svg_map_box_seg, SvgPoint> {}; -template -struct svg_map - : svg_map_box_seg > +template +struct svg_map + : svg_map_box_seg, SvgPoint> {}; -template +template struct svg_map_range { template static inline void apply(std::ostream& stream, - std::string const& style, int size, + std::string const& style, double size, Range1 const& range, TransformStrategy const& strategy) { Range2 irange; @@ -136,35 +128,35 @@ struct svg_map_range } }; -template -struct svg_map - : svg_map_range > +template +struct svg_map + : svg_map_range, SvgPoint> {}; -template -struct svg_map - : svg_map_range > +template +struct svg_map + : svg_map_range, SvgPoint> {}; -template -struct svg_map +template +struct svg_map { template static inline void apply(std::ostream& stream, - std::string const& style, int size, + std::string const& style, double size, Polygon const& polygon, TransformStrategy const& strategy) { - model::polygon ipoly; + model::polygon ipoly; geometry::transform(polygon, ipoly, strategy); stream << geometry::svg(ipoly, style, size) << std::endl; } }; -template -struct svg_map +template +struct svg_map { typedef typename single_tag_of < @@ -173,7 +165,7 @@ struct svg_map template static inline void apply(std::ostream& stream, - std::string const& style, int size, + std::string const& style, double size, Multi const& multi, TransformStrategy const& strategy) { for (typename boost::range_iterator::type it @@ -184,20 +176,21 @@ struct svg_map svg_map < stag, - typename boost::range_value::type + typename boost::range_value::type, + SvgPoint >::apply(stream, style, size, *it, strategy); } } }; -template +template struct devarianted_svg_map { template static inline void apply(std::ostream& stream, std::string const& style, - int size, + double size, Geometry const& geometry, TransformStrategy const& strategy) { @@ -208,25 +201,26 @@ struct devarianted_svg_map typename tag::type, multi_tag >::type, - typename boost::remove_const::type + typename boost::remove_const::type, + SvgPoint >::apply(stream, style, size, geometry, strategy); } }; -template -struct devarianted_svg_map > +template +struct devarianted_svg_map > { template struct visitor: static_visitor { std::ostream& m_os; std::string const& m_style; - int m_size; + double m_size; TransformStrategy const& m_strategy; visitor(std::ostream& os, std::string const& style, - int size, + double size, TransformStrategy const& strategy) : m_os(os) , m_style(style) @@ -237,14 +231,14 @@ struct devarianted_svg_map > template inline void operator()(Geometry const& geometry) const { - devarianted_svg_map::apply(m_os, m_style, m_size, geometry, m_strategy); + devarianted_svg_map::apply(m_os, m_style, m_size, geometry, m_strategy); } }; template static inline void apply(std::ostream& stream, std::string const& style, - int size, + double size, variant const& geometry, TransformStrategy const& strategy) { @@ -257,13 +251,13 @@ struct devarianted_svg_map > #endif -template +template inline void svg_map(std::ostream& stream, - std::string const& style, int size, + std::string const& style, double size, Geometry const& geometry, TransformStrategy const& strategy) { - dispatch::devarianted_svg_map::apply(stream, style, size, - geometry, strategy); + dispatch::devarianted_svg_map::apply(stream, + style, size, geometry, strategy); } @@ -272,13 +266,22 @@ inline void svg_map(std::ostream& stream, \tparam Point Point type, for input geometries. \tparam SameScale Boolean flag indicating if horizontal and vertical scale should be the same. The default value is true +\tparam SvgCoordinateType Coordinate type of SVG points. SVG is capable to + use floating point coordinates. Therefore the default value is double \ingroup svg \qbk{[include reference/io/svg.qbk]} */ -template +template +< + typename Point, + bool SameScale = true, + typename SvgCoordinateType = double +> class svg_mapper : boost::noncopyable { + typedef model::point svg_point_type; + typedef typename geometry::select_most_precise < typename coordinate_type::type, @@ -297,7 +300,7 @@ class svg_mapper : boost::noncopyable model::box m_bounding_box; boost::scoped_ptr m_matrix; std::ostream& m_stream; - int m_width, m_height; + SvgCoordinateType m_width, m_height; std::string m_width_height; // for tag only, defaults to 2x 100% void init_matrix() @@ -334,7 +337,9 @@ public : \param height Height of the SVG map (in SVG pixels) \param width_height Optional information to increase width and/or height */ - explicit svg_mapper(std::ostream& stream, int width, int height + svg_mapper(std::ostream& stream + , SvgCoordinateType width + , SvgCoordinateType height , std::string const& width_height = "width=\"100%\" height=\"100%\"") : m_stream(stream) , m_width(width) @@ -381,10 +386,10 @@ public : */ template void map(Geometry const& geometry, std::string const& style, - int size = -1) + double size = -1.0) { init_matrix(); - svg_map(m_stream, style, size, geometry, *m_matrix); + svg_map(m_stream, style, size, geometry, *m_matrix); } /*! @@ -400,10 +405,11 @@ public : template void text(TextPoint const& point, std::string const& s, std::string const& style, - int offset_x = 0, int offset_y = 0, int lineheight = 10) + double offset_x = 0.0, double offset_y = 0.0, + double lineheight = 10.0) { init_matrix(); - detail::svg::svg_point_type map_point; + svg_point_type map_point; transform(point, map_point, *m_matrix); m_stream << " static inline void apply(std::basic_ostream& os, - Point const& p, std::string const& style, int size) + Point const& p, std::string const& style, double size) { os << "(p) << "\" cy=\"" << geometry::get<1>(p) @@ -67,7 +67,7 @@ struct svg_box { template static inline void apply(std::basic_ostream& os, - Box const& box, std::string const& style, int ) + Box const& box, std::string const& style, double) { // Prevent invisible boxes, making them >=1, using "max" BOOST_USING_STD_MAX(); @@ -91,7 +91,7 @@ struct svg_segment { template static inline void apply(std::basic_ostream& os, - Segment const& segment, std::string const& style, int) + Segment const& segment, std::string const& style, double) { typedef typename coordinate_type::type ct; ct x1 = geometry::get<0, 0>(segment); @@ -114,7 +114,7 @@ struct svg_range { template static inline void apply(std::basic_ostream& os, - Range const& range, std::string const& style, int ) + Range const& range, std::string const& style, double) { typedef typename boost::range_iterator::type iterator; @@ -142,7 +142,7 @@ struct svg_poly { template static inline void apply(std::basic_ostream& os, - Polygon const& polygon, std::string const& style, int ) + Polygon const& polygon, std::string const& style, double) { typedef typename geometry::ring_type::type ring_type; typedef typename boost::range_iterator::type iterator_type; @@ -206,7 +206,7 @@ struct svg_multi { template static inline void apply(std::basic_ostream& os, - MultiGeometry const& multi, std::string const& style, int size) + MultiGeometry const& multi, std::string const& style, double size) { for (typename boost::range_iterator::type it = boost::begin(multi); @@ -316,7 +316,7 @@ struct devarianted_svg static inline void apply(OutputStream& os, Geometry const& geometry, std::string const& style, - int size) + double size) { svg::apply(os, geometry, style, size); } @@ -330,9 +330,9 @@ struct devarianted_svg > { OutputStream& m_os; std::string const& m_style; - int m_size; + double m_size; - visitor(OutputStream& os, std::string const& style, int size) + visitor(OutputStream& os, std::string const& style, double size) : m_os(os) , m_style(style) , m_size(size) @@ -350,7 +350,7 @@ struct devarianted_svg > OutputStream& os, variant const& geometry, std::string const& style, - int size + double size ) { boost::apply_visitor(visitor(os, style, size), geometry); @@ -371,7 +371,7 @@ class svg_manipulator { public: - inline svg_manipulator(Geometry const& g, std::string const& style, int size) + inline svg_manipulator(Geometry const& g, std::string const& style, double size) : m_geometry(g) , m_style(style) , m_size(size) @@ -392,7 +392,7 @@ public: private: Geometry const& m_geometry; std::string const& m_style; - int m_size; + double m_size; }; /*! @@ -405,9 +405,10 @@ private: \ingroup svg */ template -inline svg_manipulator svg(Geometry const& geometry, std::string const& style, int size = -1) +inline svg_manipulator svg(Geometry const& geometry, + std::string const& style, double size = -1.0) { - concept::check(); + concepts::check(); return svg_manipulator(geometry, style, size); } diff --git a/include/boost/geometry/io/wkt/read.hpp b/include/boost/geometry/io/wkt/read.hpp index 7924b7028..148a5769d 100644 --- a/include/boost/geometry/io/wkt/read.hpp +++ b/include/boost/geometry/io/wkt/read.hpp @@ -894,7 +894,7 @@ struct read_wkt template inline void read_wkt(std::string const& wkt, Geometry& geometry) { - geometry::concept::check(); + geometry::concepts::check(); dispatch::read_wkt::type, Geometry>::apply(wkt, geometry); } diff --git a/include/boost/geometry/io/wkt/write.hpp b/include/boost/geometry/io/wkt/write.hpp index a556aa440..b98c894b3 100644 --- a/include/boost/geometry/io/wkt/write.hpp +++ b/include/boost/geometry/io/wkt/write.hpp @@ -501,7 +501,7 @@ private: template inline wkt_manipulator wkt(Geometry const& geometry) { - concept::check(); + concepts::check(); return wkt_manipulator(geometry); } diff --git a/include/boost/geometry/strategies/cartesian/cart_intersect.hpp b/include/boost/geometry/strategies/cartesian/cart_intersect.hpp index 9bd7475e2..0cb5d7545 100644 --- a/include/boost/geometry/strategies/cartesian/cart_intersect.hpp +++ b/include/boost/geometry/strategies/cartesian/cart_intersect.hpp @@ -182,8 +182,8 @@ struct relate_cartesian_segments RobustPoint1 const& robust_a1, RobustPoint1 const& robust_a2, RobustPoint2 const& robust_b1, RobustPoint2 const& robust_b2) { - BOOST_CONCEPT_ASSERT( (concept::ConstSegment) ); - BOOST_CONCEPT_ASSERT( (concept::ConstSegment) ); + BOOST_CONCEPT_ASSERT( (concepts::ConstSegment) ); + BOOST_CONCEPT_ASSERT( (concepts::ConstSegment) ); using geometry::detail::equals::equals_point_point; bool const a_is_point = equals_point_point(robust_a1, robust_a2); diff --git a/include/boost/geometry/strategies/cartesian/distance_pythagoras.hpp b/include/boost/geometry/strategies/cartesian/distance_pythagoras.hpp index 665426ecb..8a8889dc9 100644 --- a/include/boost/geometry/strategies/cartesian/distance_pythagoras.hpp +++ b/include/boost/geometry/strategies/cartesian/distance_pythagoras.hpp @@ -91,8 +91,8 @@ public : static inline typename calculation_type::type apply(Point1 const& p1, Point2 const& p2) { - BOOST_CONCEPT_ASSERT( (concept::ConstPoint) ); - BOOST_CONCEPT_ASSERT( (concept::ConstPoint) ); + BOOST_CONCEPT_ASSERT( (concepts::ConstPoint) ); + BOOST_CONCEPT_ASSERT( (concepts::ConstPoint) ); // Calculate distance using Pythagoras // (Leave comment above for Doxygen) diff --git a/include/boost/geometry/strategies/cartesian/distance_pythagoras_box_box.hpp b/include/boost/geometry/strategies/cartesian/distance_pythagoras_box_box.hpp index 8a4234282..4c1b6539b 100644 --- a/include/boost/geometry/strategies/cartesian/distance_pythagoras_box_box.hpp +++ b/include/boost/geometry/strategies/cartesian/distance_pythagoras_box_box.hpp @@ -115,9 +115,9 @@ public : apply(Box1 const& box1, Box2 const& box2) { BOOST_CONCEPT_ASSERT - ( (concept::ConstPoint::type>) ); + ( (concepts::ConstPoint::type>) ); BOOST_CONCEPT_ASSERT - ( (concept::ConstPoint::type>) ); + ( (concepts::ConstPoint::type>) ); // Calculate distance using Pythagoras // (Leave comment above for Doxygen) diff --git a/include/boost/geometry/strategies/cartesian/distance_pythagoras_point_box.hpp b/include/boost/geometry/strategies/cartesian/distance_pythagoras_point_box.hpp index 0ce1d422e..8423d16a6 100644 --- a/include/boost/geometry/strategies/cartesian/distance_pythagoras_point_box.hpp +++ b/include/boost/geometry/strategies/cartesian/distance_pythagoras_point_box.hpp @@ -109,9 +109,9 @@ public : static inline typename calculation_type::type apply(Point const& point, Box const& box) { - BOOST_CONCEPT_ASSERT( (concept::ConstPoint) ); + BOOST_CONCEPT_ASSERT( (concepts::ConstPoint) ); BOOST_CONCEPT_ASSERT - ( (concept::ConstPoint::type>) ); + ( (concepts::ConstPoint::type>) ); // Calculate distance using Pythagoras // (Leave comment above for Doxygen) diff --git a/include/boost/geometry/strategies/concepts/area_concept.hpp b/include/boost/geometry/strategies/concepts/area_concept.hpp index 75821b52a..4eec6d1fc 100644 --- a/include/boost/geometry/strategies/concepts/area_concept.hpp +++ b/include/boost/geometry/strategies/concepts/area_concept.hpp @@ -18,7 +18,7 @@ #include -namespace boost { namespace geometry { namespace concept +namespace boost { namespace geometry { namespace concepts { @@ -69,7 +69,7 @@ public : }; -}}} // namespace boost::geometry::concept +}}} // namespace boost::geometry::concepts #endif // BOOST_GEOMETRY_STRATEGIES_CONCEPTS_AREA_CONCEPT_HPP diff --git a/include/boost/geometry/strategies/concepts/centroid_concept.hpp b/include/boost/geometry/strategies/concepts/centroid_concept.hpp index f493ef681..0bbe94ba7 100644 --- a/include/boost/geometry/strategies/concepts/centroid_concept.hpp +++ b/include/boost/geometry/strategies/concepts/centroid_concept.hpp @@ -19,7 +19,7 @@ #include -namespace boost { namespace geometry { namespace concept +namespace boost { namespace geometry { namespace concepts { @@ -72,7 +72,7 @@ public : }; -}}} // namespace boost::geometry::concept +}}} // namespace boost::geometry::concepts #endif // BOOST_GEOMETRY_STRATEGIES_CONCEPTS_CENTROID_CONCEPT_HPP diff --git a/include/boost/geometry/strategies/concepts/convex_hull_concept.hpp b/include/boost/geometry/strategies/concepts/convex_hull_concept.hpp index d6e42e95a..d4295ce47 100644 --- a/include/boost/geometry/strategies/concepts/convex_hull_concept.hpp +++ b/include/boost/geometry/strategies/concepts/convex_hull_concept.hpp @@ -25,7 +25,7 @@ #include -namespace boost { namespace geometry { namespace concept +namespace boost { namespace geometry { namespace concepts { @@ -74,7 +74,7 @@ public : }; -}}} // namespace boost::geometry::concept +}}} // namespace boost::geometry::concepts #endif // BOOST_GEOMETRY_STRATEGIES_CONCEPTS_CONVEX_HULL_CONCEPT_HPP diff --git a/include/boost/geometry/strategies/concepts/distance_concept.hpp b/include/boost/geometry/strategies/concepts/distance_concept.hpp index 6e75fa95a..0064d438d 100644 --- a/include/boost/geometry/strategies/concepts/distance_concept.hpp +++ b/include/boost/geometry/strategies/concepts/distance_concept.hpp @@ -36,7 +36,7 @@ #include -namespace boost { namespace geometry { namespace concept +namespace boost { namespace geometry { namespace concepts { @@ -206,7 +206,7 @@ public : }; -}}} // namespace boost::geometry::concept +}}} // namespace boost::geometry::concepts #endif // BOOST_GEOMETRY_STRATEGIES_CONCEPTS_DISTANCE_CONCEPT_HPP diff --git a/include/boost/geometry/strategies/concepts/segment_intersect_concept.hpp b/include/boost/geometry/strategies/concepts/segment_intersect_concept.hpp index 43bcccf37..87d901eb9 100644 --- a/include/boost/geometry/strategies/concepts/segment_intersect_concept.hpp +++ b/include/boost/geometry/strategies/concepts/segment_intersect_concept.hpp @@ -20,7 +20,7 @@ #include -namespace boost { namespace geometry { namespace concept +namespace boost { namespace geometry { namespace concepts { @@ -73,6 +73,6 @@ public : -}}} // namespace boost::geometry::concept +}}} // namespace boost::geometry::concepts #endif // BOOST_GEOMETRY_STRATEGIES_CONCEPTS_SEGMENT_INTERSECT_CONCEPT_HPP diff --git a/include/boost/geometry/strategies/concepts/simplify_concept.hpp b/include/boost/geometry/strategies/concepts/simplify_concept.hpp index d7f596cfe..06600bafc 100644 --- a/include/boost/geometry/strategies/concepts/simplify_concept.hpp +++ b/include/boost/geometry/strategies/concepts/simplify_concept.hpp @@ -24,7 +24,7 @@ #include -namespace boost { namespace geometry { namespace concept +namespace boost { namespace geometry { namespace concepts { @@ -63,7 +63,7 @@ private : BOOST_CONCEPT_ASSERT ( - (concept::PointSegmentDistanceStrategy) + (concepts::PointSegmentDistanceStrategy) ); Strategy *str = 0; @@ -91,6 +91,6 @@ public : -}}} // namespace boost::geometry::concept +}}} // namespace boost::geometry::concepts #endif // BOOST_GEOMETRY_STRATEGIES_CONCEPTS_SIMPLIFY_CONCEPT_HPP diff --git a/include/boost/geometry/strategies/concepts/within_concept.hpp b/include/boost/geometry/strategies/concepts/within_concept.hpp index 878640371..ab712ccd5 100644 --- a/include/boost/geometry/strategies/concepts/within_concept.hpp +++ b/include/boost/geometry/strategies/concepts/within_concept.hpp @@ -22,7 +22,7 @@ #include -namespace boost { namespace geometry { namespace concept +namespace boost { namespace geometry { namespace concepts { @@ -55,12 +55,12 @@ class WithinStrategyPolygonal // CHECK: apply-arguments should both fulfill point concept BOOST_CONCEPT_ASSERT ( - (concept::ConstPoint) + (concepts::ConstPoint) ); BOOST_CONCEPT_ASSERT ( - (concept::ConstPoint) + (concepts::ConstPoint) ); // CHECK: return types (result: int, apply: bool) @@ -130,12 +130,12 @@ class WithinStrategyPointBox // CHECK: apply-arguments should fulfill point/box concept BOOST_CONCEPT_ASSERT ( - (concept::ConstPoint) + (concepts::ConstPoint) ); BOOST_CONCEPT_ASSERT ( - (concept::ConstBox) + (concepts::ConstBox) ); // CHECK: return types (apply: bool) @@ -194,12 +194,12 @@ class WithinStrategyBoxBox // CHECK: apply-arguments should both fulfill box concept BOOST_CONCEPT_ASSERT ( - (concept::ConstBox) + (concepts::ConstBox) ); BOOST_CONCEPT_ASSERT ( - (concept::ConstBox) + (concepts::ConstBox) ); // CHECK: return types (apply: bool) @@ -236,7 +236,7 @@ public : #endif }; -// So now: boost::geometry::concept::within +// So now: boost::geometry::concepts::within namespace within { @@ -285,7 +285,7 @@ inline void check() } -}}}} // namespace boost::geometry::concept::within +}}}} // namespace boost::geometry::concepts::within #endif // BOOST_GEOMETRY_STRATEGIES_CONCEPTS_WITHIN_CONCEPT_HPP diff --git a/include/boost/geometry/strategies/spherical/distance_cross_track.hpp b/include/boost/geometry/strategies/spherical/distance_cross_track.hpp index 31b59e77f..7daafa4a1 100644 --- a/include/boost/geometry/strategies/spherical/distance_cross_track.hpp +++ b/include/boost/geometry/strategies/spherical/distance_cross_track.hpp @@ -367,7 +367,7 @@ public : #if !defined(BOOST_MSVC) BOOST_CONCEPT_ASSERT ( - (concept::PointDistanceStrategy) + (concepts::PointDistanceStrategy) ); #endif @@ -521,7 +521,7 @@ public : #if !defined(BOOST_MSVC) BOOST_CONCEPT_ASSERT ( - (concept::PointDistanceStrategy) + (concepts::PointDistanceStrategy) ); #endif typedef typename return_type::type return_type; diff --git a/include/boost/geometry/strategies/spherical/distance_cross_track_point_box.hpp b/include/boost/geometry/strategies/spherical/distance_cross_track_point_box.hpp index 59be3645f..ee805c36d 100644 --- a/include/boost/geometry/strategies/spherical/distance_cross_track_point_box.hpp +++ b/include/boost/geometry/strategies/spherical/distance_cross_track_point_box.hpp @@ -96,7 +96,7 @@ public: #if !defined(BOOST_MSVC) BOOST_CONCEPT_ASSERT ( - (concept::PointSegmentDistanceStrategy + (concepts::PointSegmentDistanceStrategy < Strategy, Point, typename point_type::type >) diff --git a/include/boost/geometry/strategies/spherical/intersection.hpp b/include/boost/geometry/strategies/spherical/intersection.hpp index 2e113384b..4ffc853aa 100644 --- a/include/boost/geometry/strategies/spherical/intersection.hpp +++ b/include/boost/geometry/strategies/spherical/intersection.hpp @@ -161,8 +161,8 @@ struct relate_spherical_segments RobustPolicy const&, Point1 const& a1, Point1 const& a2, Point2 const& b1, Point2 const& b2) { - BOOST_CONCEPT_ASSERT( (concept::ConstSegment) ); - BOOST_CONCEPT_ASSERT( (concept::ConstSegment) ); + BOOST_CONCEPT_ASSERT( (concepts::ConstSegment) ); + BOOST_CONCEPT_ASSERT( (concepts::ConstSegment) ); // TODO: check only 2 first coordinates here? using geometry::detail::equals::equals_point_point; diff --git a/include/boost/geometry/util/for_each_coordinate.hpp b/include/boost/geometry/util/for_each_coordinate.hpp index 7a1f55b00..fb1e31856 100644 --- a/include/boost/geometry/util/for_each_coordinate.hpp +++ b/include/boost/geometry/util/for_each_coordinate.hpp @@ -66,7 +66,7 @@ struct coordinates_scanner template inline void for_each_coordinate(Point& point, Op operation) { - BOOST_CONCEPT_ASSERT( (concept::Point) ); + BOOST_CONCEPT_ASSERT( (concepts::Point) ); typedef typename detail::coordinates_scanner < @@ -79,7 +79,7 @@ inline void for_each_coordinate(Point& point, Op operation) template inline Op for_each_coordinate(Point const& point, Op operation) { - BOOST_CONCEPT_ASSERT( (concept::ConstPoint) ); + BOOST_CONCEPT_ASSERT( (concepts::ConstPoint) ); typedef typename detail::coordinates_scanner < diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index f8c1eac84..173284fa3 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -27,6 +27,7 @@ build-project concepts ; build-project geometries ; build-project arithmetic ; build-project algorithms ; +build-project formulas ; build-project iterators ; build-project strategies ; build-project policies ; diff --git a/test/algorithms/buffer/buffer_linestring.cpp b/test/algorithms/buffer/buffer_linestring.cpp index 395167490..3b27d1af1 100644 --- a/test/algorithms/buffer/buffer_linestring.cpp +++ b/test/algorithms/buffer/buffer_linestring.cpp @@ -285,10 +285,10 @@ void test_all() test_one("mysql_report_2015_09_08a", mysql_report_2015_09_08a, join_round32, end_round32, 0.0, 1.0); test_one("mysql_report_2015_09_08b", mysql_report_2015_09_08b, join_round32, end_round32, 0.0, 1099511627778.0); test_one("mysql_report_2015_09_08c", mysql_report_2015_09_08c, join_round32, end_round32, 0.0, 0xbe); +#endif test_one("mysql_23023665_1", mysql_23023665, join_round32, end_flat, 459.1051, 10); - test_one("mysql_23023665_2", mysql_23023665, join_round32, end_flat, 6877.6941, 50); -#endif + test_one("mysql_23023665_2", mysql_23023665, join_round32, end_flat, 6877.7097, 50); } template diff --git a/test/algorithms/buffer/buffer_multi_polygon.cpp b/test/algorithms/buffer/buffer_multi_polygon.cpp index 91a806258..b473c4601 100644 --- a/test/algorithms/buffer/buffer_multi_polygon.cpp +++ b/test/algorithms/buffer/buffer_multi_polygon.cpp @@ -473,9 +473,12 @@ void test_all() test_one("rt_u8", rt_u8, join_miter, end_flat, 70.9142, 1.0); test_one("rt_u9", rt_u9, join_miter, end_flat, 59.3063, 1.0); - test_one("rt_u10", rt_u10, join_miter, end_flat, 144.0858, 1.0); - test_one("rt_u10_50", rt_u10, join_miter, end_flat, 0.2145, -0.50); - test_one("rt_u10_25", rt_u10, join_miter, end_flat, 9.6682, -0.25); + test_one("rt_u10", rt_u10, join_miter, end_flat, 144.0858, 1.0); // PG: 144.085786772487 + test_one("rt_u10_51", rt_u10, join_miter, end_flat, 0.1674, -0.51); // PG: 0.167380307629637 + // TODO: now one small triangle missing due to clusters/uu turns + test_one("rt_u10_50", rt_u10, join_miter, end_flat, 0.2145, -0.50); // PG: 0.214466094067263 + test_one("rt_u10_45", rt_u10, join_miter, end_flat, 1.3000, -0.45); // PG: 1.30004221251301 + test_one("rt_u10_25", rt_u10, join_miter, end_flat, 9.6682, -0.25); // PG: 9.66820888343117 test_one("rt_u11", rt_u11, join_miter, end_flat, 131.3995, 1.0); test_one("rt_u11_50", rt_u11, join_miter, end_flat, 0.04289, -0.50); diff --git a/test/algorithms/buffer/buffer_polygon.cpp b/test/algorithms/buffer/buffer_polygon.cpp index 4769cd951..3bb61f192 100644 --- a/test/algorithms/buffer/buffer_polygon.cpp +++ b/test/algorithms/buffer/buffer_polygon.cpp @@ -510,7 +510,7 @@ void test_all() // Tickets test_one("ticket_10398_1_5", ticket_10398_1, join_miter, end_flat, 494.7192, 0.5, -999, false); test_one("ticket_10398_1_25", ticket_10398_1, join_miter, end_flat, 697.7798, 2.5, -999, false); - test_one("ticket_10398_1_84", ticket_10398_1, join_miter, end_flat, 1470.8096, 8.4, -999, false); + test_one("ticket_10398_1_84", ticket_10398_1, join_miter, end_flat, 1470.8096, 8.4, -999, false, 0.02); // qcc-arm reports 1470.79863681712281 test_one("ticket_10398_2_45", ticket_10398_2, join_miter, end_flat, 535.4780, 4.5, -999, false); test_one("ticket_10398_2_62", ticket_10398_2, join_miter, end_flat, 705.2046, 6.2, -999, false); diff --git a/test/algorithms/distance/distance.cpp b/test/algorithms/distance/distance.cpp index 2f9c74c39..76471557f 100644 --- a/test/algorithms/distance/distance.cpp +++ b/test/algorithms/distance/distance.cpp @@ -76,7 +76,7 @@ void test_distance_point() { // Test custom strategy - BOOST_CONCEPT_ASSERT( (bg::concept::PointDistanceStrategy) ); + BOOST_CONCEPT_ASSERT( (bg::concepts::PointDistanceStrategy) ); typedef typename services::return_type::type cab_return_type; BOOST_MPL_ASSERT((boost::is_same::type>)); diff --git a/test/algorithms/overlay/handle_touch.cpp b/test/algorithms/overlay/handle_touch.cpp deleted file mode 100644 index a39b26197..000000000 --- a/test/algorithms/overlay/handle_touch.cpp +++ /dev/null @@ -1,516 +0,0 @@ -// Boost.Geometry (aka GGL, Generic Geometry Library) -// Unit Test - -// Copyright (c) 2015 Barend Gehrels, 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) - -#define BOOST_GEOMETRY_DEBUG_IDENTIFIER -#define BOOST_GEOMETRY_DEBUG_SEGMENT_IDENTIFIER - -//#define BOOST_GEOMETRY_DEBUG_HANDLE_TOUCH - - -#include -#include -#include -#include -#include - - -#include - - -#include -#include -#include - -#include -#include -#include - -#include - -#include - -#include -#include -#include - -#include - -#include - - -#if defined(TEST_WITH_SVG) -# include -#endif - -#include -#include - - -namespace detail -{ - -template -< - typename G1, typename G2, - bg::detail::overlay::operation_type Direction, - bool Reverse1, bool Reverse2 - > -struct test_handle_touch -{ - - static void apply(std::string const& case_id, - std::size_t expected_traverse, - std::size_t expected_skipped, - std::size_t expected_start, - G1 const& g1, G2 const& g2) - { - - typedef typename bg::strategy::side::services::default_strategy - < - typename bg::cs_tag::type - >::type side_strategy_type; - - typedef typename bg::point_type::type point_type; - typedef typename bg::rescale_policy_type::type - rescale_policy_type; - - rescale_policy_type rescale_policy - = bg::get_rescale_policy(g1, g2); - - typedef bg::detail::overlay::traversal_turn_info - < - point_type, - typename bg::segment_ratio_type::type - > turn_info; - std::vector turns; - - bg::detail::get_turns::no_interrupt_policy policy; - bg::get_turns(g1, g2, rescale_policy, turns, policy); - bg::enrich_intersection_points(turns, - Direction == 1 ? bg::detail::overlay::operation_union - : bg::detail::overlay::operation_intersection, - g1, g2, rescale_policy, side_strategy_type()); - - typedef bg::model::ring::type> ring_type; - typedef std::vector out_vector; - -#ifdef BOOST_GEOMETRY_DEBUG_HANDLE_TOUCH - std::cout << "*** Case: " << case_id << std::endl; -#endif - - bg::detail::overlay::handle_touch(Direction, turns); - - // Check number of resulting u/u turns - - std::size_t uu_traverse = 0; - std::size_t uu_skipped = 0; - std::size_t uu_start = 0; - BOOST_FOREACH(turn_info const& turn, turns) - { - if (turn.both(bg::detail::overlay::operation_union)) - { - if (turn.switch_source) - { - uu_traverse++; - } - else - { - uu_skipped++; - } - if (turn.selectable_start) - { - uu_start++; - } - } - } - - BOOST_CHECK_MESSAGE(expected_traverse == uu_traverse, - "handle_touch: " << case_id - << " traverse expected: " << expected_traverse - << " detected: " << uu_traverse - << " type: " << string_from_type - ::type>::name()); - BOOST_CHECK_MESSAGE(expected_skipped == uu_skipped, - "handle_touch: " << case_id - << " skipped expected: " << expected_skipped - << " detected: " << uu_skipped - << " type: " << string_from_type - ::type>::name()); - BOOST_CHECK_MESSAGE(expected_start == uu_start, - "handle_touch: " << case_id - << " start expected: " << expected_start - << " detected: " << uu_skipped - << " type: " << string_from_type - ::type>::name()); - -#if defined(TEST_WITH_SVG) - { - std::ostringstream filename; - filename << "handle_touch" - << "_" << case_id - << "_" << string_from_type::type>::name() - << ".svg"; - - std::ofstream svg(filename.str().c_str()); - - bg::svg_mapper::type> mapper(svg, 500, 500); - mapper.add(g1); - mapper.add(g2); - - // Input shapes in green/blue - mapper.map(g1, "fill-opacity:0.5;fill:rgb(153,204,0);" - "stroke:rgb(153,204,0);stroke-width:3"); - mapper.map(g2, "fill-opacity:0.3;fill:rgb(51,51,153);" - "stroke:rgb(51,51,153);stroke-width:3"); - - - // turn points in orange, + enrichment/traversal info - typedef typename bg::coordinate_type::type coordinate_type; - - // Simple map to avoid two texts at same place (note that can still overlap!) - std::map, int> offsets; - int index = 0; - int const margin = 5; - - BOOST_FOREACH(turn_info const& turn, turns) - { - int lineheight = 8; - mapper.map(turn.point, "fill:rgb(255,128,0);" - "stroke:rgb(0,0,0);stroke-width:1", 3); - - { - coordinate_type half = 0.5; - coordinate_type ten = 10; - // Map characteristics - // Create a rounded off point - std::pair p - = std::make_pair( - boost::numeric_cast(half - + ten * bg::get<0>(turn.point)), - boost::numeric_cast(half - + ten * bg::get<1>(turn.point)) - ); - - std::string color = "fill:rgb(0,0,0);"; - std::string fontsize = "font-size:8px;"; - - if (turn.both(bg::detail::overlay::operation_union)) - { - // Adapt color to give visual feedback in SVG - if (turn.switch_source && turn.selectable_start) - { - color = "fill:rgb(0,0,255);"; // blue - } - else if (turn.switch_source) - { - color = "fill:rgb(0,128,0);"; // green - } - else - { - color = "fill:rgb(255,0,0);"; // red - } - } - else if (turn.discarded) - { - color = "fill:rgb(92,92,92);"; - fontsize = "font-size:6px;"; - lineheight = 6; - } - const std::string style = color + fontsize + "font-family:Arial;"; - - { - std::ostringstream out; - out << index - << ": " << bg::method_char(turn.method) - << std::endl - << "op: " << bg::operation_char(turn.operations[0].operation) - << " / " << bg::operation_char(turn.operations[1].operation) - << std::endl; - - if (turn.operations[0].enriched.next_ip_index != -1) - { - out << "ip: " << turn.operations[0].enriched.next_ip_index; - } - else - { - out << "vx: " << turn.operations[0].enriched.travels_to_vertex_index - << " -> ip: " << turn.operations[0].enriched.travels_to_ip_index; - } - out << " / "; - if (turn.operations[1].enriched.next_ip_index != -1) - { - out << "ip: " << turn.operations[1].enriched.next_ip_index; - } - else - { - out << "vx: " << turn.operations[1].enriched.travels_to_vertex_index - << " -> ip: " << turn.operations[1].enriched.travels_to_ip_index; - } - - out << std::endl; - - - - offsets[p] += lineheight; - int offset = offsets[p]; - offsets[p] += lineheight * 3; - mapper.text(turn.point, out.str(), style, margin, offset, lineheight); - } - index++; - } - } - } -#endif - } -}; -} - -template -< - typename G1, typename G2, - bg::detail::overlay::operation_type Direction, - bool Reverse1 = false, - bool Reverse2 = false - > -struct test_handle_touch -{ - typedef detail::test_handle_touch - < - G1, G2, Direction, Reverse1, Reverse2 - > detail_test_handle_touch; - - inline static void apply(std::string const& case_id, - std::size_t expected_traverse, - std::size_t expected_skipped, - std::size_t expected_start, - std::string const& wkt1, std::string const& wkt2) - { - if (wkt1.empty() || wkt2.empty()) - { - return; - } - - G1 g1; - bg::read_wkt(wkt1, g1); - - G2 g2; - bg::read_wkt(wkt2, g2); - - bg::correct(g1); - bg::correct(g2); - - detail_test_handle_touch::apply(case_id, - expected_traverse, - expected_skipped, - expected_start, - g1, g2); - - } -}; - -template -void test_geometries() -{ - namespace ov = bg::detail::overlay; - - typedef test_handle_touch - < - Polygon, Polygon, - ov::operation_union - > test_union; - - test_union::apply("case_36", 1, 0, 0, case_36[0], case_36[1]); - test_union::apply("case_80", 1, 0, 0, case_80[0], case_80[1]); - test_union::apply("case_81", 1, 0, 0, case_81[0], case_81[1]); - test_union::apply("case_82", 0, 2, 0, case_82[0], case_82[1]); - test_union::apply("case_83", 2, 0, 1, case_83[0], case_83[1]); - test_union::apply("case_84", 0, 3, 0, case_84[0], case_84[1]); - test_union::apply("case_85", 1, 0, 0, case_85[0], case_85[1]); -} - - -template -void test_multi_geometries() -{ - namespace ov = bg::detail::overlay; - - typedef test_handle_touch - < - MultiPolygon, MultiPolygon, - ov::operation_union - > test_union; - - test_union::apply - ( - "uu_case_1", 0, 1, 0, - "MULTIPOLYGON(((4 0,2 2,4 4,6 2,4 0)))", - "MULTIPOLYGON(((4 4,2 6,4 8,6 6,4 4)))" - ); - test_union::apply - ( - "uu_case_2", 0, 2, 0, - "MULTIPOLYGON(((0 0,0 2,2 4,4 2,6 4,8 2,8 0,0 0)))", - "MULTIPOLYGON(((0 8,8 8,8 6,6 4,4 6,2 4,0 6,0 8)))" - ); - - // Provided by Menelaos (1) - test_union::apply - ( - "uu_case_3", 0, 2, 0, - "MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0)),((15 5,15 10,20 10,20 5,15 5)))", - "MULTIPOLYGON(((10 0,15 5,15 0,10 0)),((10 5,10 10,15 10,15 5,10 5)))" - ); - // Provided by Menelaos (2) - test_union::apply - ( - "uu_case_4", 1, 0, 0, - "MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0)),((15 5,15 10,20 10,20 5,15 5)))", - "MULTIPOLYGON(((10 0,15 5,20 5,20 0,10 0)),((10 5,10 10,15 10,15 5,10 5)))" - ); - - // Mailed by Barend - test_union::apply - ( - "uu_case_5", 1, 0, 0, - "MULTIPOLYGON(((4 0,2 2,4 4,6 2,4 0)),((4 6,6 8,8 6,6 4,4 6)))", - "MULTIPOLYGON(((4 4,2 6,4 8,6 6,4 4)),((4 2,7 6,8 3,4 2)))" - ); - - // Formerly referred to as a - test_union::apply - ( - "uu_case_6", 2, 0, 0, - "MULTIPOLYGON(((4 8,4 10,6 10,6 8,4 8)),((7 7,7 11,10 11,10 7,7 7)))", - "MULTIPOLYGON(((6 6,6 8,8 8,8 6,6 6)),((6 10,6 12,8 12,8 10,6 10)),((9 9,11 9,11 2,3 2,3 9,5 9,5 3,9 3,9 9)))" - ); - // Should result in 1 polygon with 2 holes - // "POLYGON((4 9,4 10,6 10,6 12,8 12,8 11,10 11,10 9,11 9,11 2,3 2,3 9,4 9),(6 10,6 8,7 8,7 10,6 10),(6 8,5 8,5 3,9 3,9 7,8 7,8 6,6 6,6 8))" - - // Formerly referred to as b - test_union::apply - ( - "uu_case_7", 0, 2, 0, - "MULTIPOLYGON(((4 8,4 10,6 10,6 8,4 8)),((7 7,7 11,10 11,10 7,7 7)))", - "MULTIPOLYGON(((6 6,6 8,8 8,8 6,6 6)),((6 10,6 12,8 12,8 10,6 10)))" - ); - // Should result in 2 polygons - // "MULTIPOLYGON(((4 8,4 10,6 10,6 8,4 8)),((7 8,7 10,6 10,6 12,8 12,8 11,10 11,10 7,8 7,8 6,6 6,6 8,7 8)))" - - // Formerly referred to as c - test_union::apply - ( - "uu_case_8", 0, 4, 0, - "MULTIPOLYGON(((4 8,4 10,6 10,6 8,4 8)),((8 8,8 10,10 10,10 8,8 8)),((7 11,7 13,13 13,13 5,7 5,7 7,11 7,11 11,7 11)))", - "MULTIPOLYGON(((6 6,6 8,8 8,8 6,6 6)),((6 10,6 12,8 12,8 10,6 10)))" - ); - - // Shoud result in 3 polygons: - // "MULTIPOLYGON(((4 8,4 10,6 10,6 8,4 8)),((8 8,8 10,10 10,10 8,8 8)),((7 12,7 13,13 13,13 5,7 5,7 6,6 6,6 8,8 8,8 7,11 7,11 11,8 11,8 10,6 10,6 12,7 12)))" - - // Formerly referred to as d - test_union::apply - ( - "uu_case_9", 0, 2, 0, - "MULTIPOLYGON(((2 4,2 6,4 6,4 4,2 4)),((6 4,6 6,8 6,8 4,6 4)),((1 0,1 3,9 3,9 0,1 0)))", - "MULTIPOLYGON(((0 2,0 4,2 4,2 2,0 2)),((8 2,8 4,10 4,10 2,8 2)),((3 5,3 7,7 7,7 5,3 5)))" - ); - // Should result in 2 polygons: - // "MULTIPOLYGON(((2 4,2 6,3 6,3 7,7 7,7 6,8 6,8 4,6 4,6 5,4 5,4 4,2 4)),((1 0,1 2,0 2,0 4,2 4,2 3,8 3,8 4,10 4,10 2,9 2,9 0,1 0)))" - - // With a c/c turn - test_union::apply - ( - "uu_case_10", 1, 0, 0, - "MULTIPOLYGON(((6 4,6 9,9 9,9 6,11 6,11 4,6 4)),((10 7,10 10,12 10,12 7,10 7)))", - "MULTIPOLYGON(((10 5,10 8,12 8,12 5,10 5)),((6 10,8 12,10 10,8 8,6 10)))" - ); - - // With c/c turns in both involved polygons - test_union::apply - ( - "uu_case_11", 1, 0, 0, - "MULTIPOLYGON(((7 4,7 8,9 8,9 6,11 6,11 4,7 4)),((10 7,10 10,12 10,12 7,10 7)))", - "MULTIPOLYGON(((10 5,10 8,12 8,12 5,10 5)),((7 7,7 10,10 10,9 9,9 7,7 7)))" - ); - - // Same but here c/c not directly involved in the turns itself - // (This one breaks if continue is not checked in handle_touch) - test_union::apply - ( - "uu_case_12", 1, 0, 0, - "MULTIPOLYGON(((10 8,10 10,12 10,12 8,10 8)),((10 4,10 7,12 7,12 4,10 4)),((7 5,7 8,9 8,9 5,7 5)))", - "MULTIPOLYGON(((7 3,7 6,9 6,9 5,11 5,11 3,7 3)),((10 6,10 9,12 9,12 6,10 6)),((7 7,7 10,10 10,9 9,9 7,7 7)))" - ); - - test_union::apply - ( - "case_62_multi", 0, 1, 0, case_62_multi[0], case_62_multi[1] - ); - test_union::apply - ( - "case_63_multi", 0, 1, 0, case_63_multi[0], case_63_multi[1] - ); - test_union::apply - ( - "case_65_multi", 0, 2, 0, case_65_multi[0], case_65_multi[1] - ); - test_union::apply - ( - "case_66_multi", 0, 2, 0, case_66_multi[0], case_66_multi[1] - ); - test_union::apply - ( - "case_75_multi", 0, 4, 0, case_75_multi[0], case_75_multi[1] - ); - test_union::apply - ( - "case_76_multi", 0, 5, 0, case_76_multi[0], case_76_multi[1] - ); - test_union::apply - ( - "case_101_multi", 2, 0, 0, case_101_multi[0], case_101_multi[1] - ); - test_union::apply - ( - "case_108_multi", 0, 0, 0, case_108_multi[0], case_108_multi[1] - ); - - // NOTE: this result is still to be checked - test_union::apply - ( - "case_recursive_boxes_3", 8, 18, 0, - case_recursive_boxes_3[0], case_recursive_boxes_3[1] - ); - -} - - -template -void test_all() -{ - typedef bg::model::point point_type; - - test_multi_geometries - < - bg::model::multi_polygon - < - bg::model::polygon - > - >(); - - test_geometries >(); -} - - -int test_main(int, char* []) -{ - test_all(); - - return 0; -} diff --git a/test/algorithms/overlay/multi_overlay_cases.hpp b/test/algorithms/overlay/multi_overlay_cases.hpp index 531623915..4909d93e6 100644 --- a/test/algorithms/overlay/multi_overlay_cases.hpp +++ b/test/algorithms/overlay/multi_overlay_cases.hpp @@ -332,7 +332,7 @@ static std::string case_101_multi[2] = { // interior ring / union "MULTIPOLYGON(((7 2,7 3,8 2,7 2)),((9 3,9 4,10 3,9 3)),((10 1,10 0,8 0,8 1,9 2,10 2,10 1)),((9 3,9 2,8 2,8 3,7 3,7 4,8 4,9 3)),((8 4,8 7,9 6,9 4,8 4)))", - "MULTIPOLYGON(((6 1,5 1,5 2,6 3,6 4,7 5,6 5,7 6,8 6,8 5,9 5,8 4,9 4,9 5,10 5,10 1,8 1,8 3,7 3,7 2,6 2,7 1,8 1,7 0,5 0,5 1,5.5 0.5,6 1),(8.5 2.5,9 2,9 3,8.5 2.5)))" + "MULTIPOLYGON(((5 1,5 2,6 3,6 4,7 5,6 5,7 6,8 6,8 5,9 5,10 5,10 1,8 1,7 0,5 0,5 1),(9 5,8 4,9 4,9 5),(8 1,8 3,7 3,7 2,6 2,7 1,8 1),(5 1,5.5 0.5,6 1,5 1),(8.5 2.5,9 2,9 3,8.5 2.5)))" }; static std::string case_102_multi[4] = @@ -349,7 +349,7 @@ static std::string case_102_multi[4] = static std::string case_103_multi[2] = { // interior ring 'fit' (ix) / union / assemble - "MULTIPOLYGON(((0 0,0 5,5 5,5 0,2 0,2 1,3 1,3 2,2 2,2 3,1 2,2 2,2 1,1 0,0 0)))", + "MULTIPOLYGON(((0 0,0 5,5 5,5 0,2 0,2 1,1 0,0 0),(2 1,3 1,3 2,2 2,2 1),(2 2,2 3,1 2,2 2)))", "MULTIPOLYGON(((0 0,0 5,5 5,5 0,0 0),(2 1,2 2,1 1,2 1)))" }; @@ -364,14 +364,15 @@ static std::string case_105_multi[2] = { // interior ring 'fit' () / union / assemble "MULTIPOLYGON(((0 0,0 5,5 5,5 0,0 0),(2 2,3 2,3 3,1 3,2 2)))", - "MULTIPOLYGON(((0 0,0 5,5 5,5 0,0 0),(1 1,2 1,2 2,1 1),(2 1,3 1,3 2,2 1),(1 3,3 3,3 4,2 3,2 4,1 4,1 3)))" + "MULTIPOLYGON(((0 0,0 5,5 5,5 0,0 0),(1 1,2 1,2 2,1 1),(2 1,3 1,3 2,2 1),(1 3,2 3,2 4,1 4,1 3),(2 3,3 3,3 4,2 3)))" }; static std::string case_106_multi[2] = { // interior ring 'fit' () / union / assemble - "MULTIPOLYGON(((0 0,0 3,1 2,1 3,2 3,2 1,3 2,2 2,3 3,2 3,3 4,1 4,1 3,0 3,0 5,5 5,5 0,0 0)))", - "MULTIPOLYGON(((0 0,0 5,1 5,1 4,2 4,2 5,3 5,3 3,4 4,5 4,5 0,2 0,3 1,2 1,2 3,1 3,2 2,1.5 1.5,2 1,1 1,0 0)),((1 0,2 1,2 0,1 0)))" + // [1] is reported as invalid by BG, but not by postgis + "MULTIPOLYGON(((0 0,0 3,0 5,5 5,5 0,0 0),(0 3,1 2,1 3,0 3),(1 3,2 3,3 4,1 4,1 3),(2 3,2 2,3 3,2 3),(2 2,2 1,3 2,2 2)))", + "MULTIPOLYGON(((0 0,0 5,1 5,1 4,2 4,2 5,3 5,3 3,4 4,5 4,5 0,2 0,3 1,2 1,1 1,0 0),(2 1,2 2,1.5 1.5,2 1),(2 2,2 3,1 3,2 2)),((2 0,1 0,2 1,2 0)))" }; static std::string case_107_multi[4] = @@ -385,12 +386,11 @@ static std::string case_107_multi[4] = "MULTIPOLYGON(((4 5,4 11,9 11,9 5,4 5),(5 7,6 6,6 7,7 8,8 8,8 10,7 9,6 10,6 8,5 7)))" }; -static std::string case_108_multi[3] = +static std::string case_108_multi[2] = { // Missing intersection point in [0] / [1], [0] / [2] is OK - "MULTIPOLYGON(((3 4,4 4,4 2,4 1,1 1,1 2,2 2,2.5 1.5,3 2,2 2,3 3,1 3,1 2,0 1,0 6,1 6,2 5,2 4,1 4,1.5 3.5,2 4,3 4)))", - "MULTIPOLYGON(((0 3,0 4,1 4,0 3)),((3 6,3 5,5 5,5 0,4 0,4 1,1 1,1 2,2 3,2 4,2.5 3.5,3 4,4 3,3 3,3 2,4 2,4 4,2 4,1 3,1 5,2 6,3 6)),((1 3,1 2,0 2,0 3,1 3)))", - "MULTIPOLYGON(((0 3,0 4,1 4,0 3)),((3 6,3 5,5 5,5 1, 1 1,1 2,2 3,2 4,2.5 3.5,3 4,4 3,3 3,3 2,4 2,4 4,2 4,1 3,1 5,2 6,3 6)),((1 3,1 2,0 2,0 3,1 3)))" + "MULTIPOLYGON(((1 2,0 1,0 6,1 6,2 5,2 4,3 4,4 4,4 2,4 1,1 1,1 2),(1 2,2 2,3 3,1 3,1 2),(2 2,2.5 1.5,3 2,2 2),(2 4,1 4,1.5 3.5,2 4)))", + "MULTIPOLYGON(((1 2,2 3,2 4,1 3,1 4,1 5,2 6,3 6,3 5,5 5,5 0,4 0,4 1,1 1,1 2),(2 4,2.5 3.5,3 4,2 4),(3 4,4 3,4 4,3 4),(4 3,3 3,3 2,4 2,4 3)),((0 3,1 3,1 2,0 2,0 3)),((0 3,0 4,1 4,0 3)))" }; static std::string case_109_multi[2] = @@ -405,19 +405,110 @@ static std::string case_110_multi[2] = "MULTIPOLYGON(((15 10,10 15,10 17,15 10)),((15 10,10 20,10 22,15 10)),((15 10,10 25,10 27,15 10)),((25 10,30 17,30 15,25 10)),((25 10,30 22,30 20,25 10)),((25 10,30 27,30 25,25 10)),((18 10,20 30,19 10,18 10)),((21 10,20 30,22 10,21 10)))" }; + +// Cases 111 to 122 are for testing uu-cases, validity, touch, interior rings +static std::string case_111_multi[2] = +{ + "MULTIPOLYGON(((4 0,2 2,4 4,6 2,4 0)))", + "MULTIPOLYGON(((4 4,2 6,4 8,6 6,4 4)))" +}; + +static std::string case_112_multi[2] = +{ + "MULTIPOLYGON(((0 0,0 2,2 4,4 2,6 4,8 2,8 0,0 0)))", + "MULTIPOLYGON(((0 8,8 8,8 6,6 4,4 6,2 4,0 6,0 8)))" +}; + +// Provided by Menelaos (1) +static std::string case_113_multi[2] = +{ + "MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0)),((15 5,15 10,20 10,20 5,15 5)))", + "MULTIPOLYGON(((10 0,15 5,15 0,10 0)),((10 5,10 10,15 10,15 5,10 5)))" +}; + +// Provided by Menelaos (2) +static std::string case_114_multi[2] = +{ + "MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0)),((15 5,15 10,20 10,20 5,15 5)))", + "MULTIPOLYGON(((10 0,15 5,20 5,20 0,10 0)),((10 5,10 10,15 10,15 5,10 5)))" +}; + +// Mailed by Barend +static std::string case_115_multi[2] = +{ + "MULTIPOLYGON(((4 0,2 2,4 4,6 2,4 0)),((4 6,6 8,8 6,6 4,4 6)))", + "MULTIPOLYGON(((4 4,2 6,4 8,6 6,4 4)),((4 2,7 6,8 3,4 2)))" +}; + +// Formerly referred to as a +// Should result in 1 polygon with 2 holes +// "POLYGON((4 9,4 10,6 10,6 12,8 12,8 11,10 11,10 9,11 9,11 2,3 2,3 9,4 9),(6 10,6 8,7 8,7 10,6 10),(6 8,5 8,5 3,9 3,9 7,8 7,8 6,6 6,6 8))" +static std::string case_116_multi[2] = +{ + "MULTIPOLYGON(((4 8,4 10,6 10,6 8,4 8)),((7 7,7 11,10 11,10 7,7 7)))", + "MULTIPOLYGON(((6 6,6 8,8 8,8 6,6 6)),((6 10,6 12,8 12,8 10,6 10)),((9 9,11 9,11 2,3 2,3 9,5 9,5 3,9 3,9 9)))" +}; + +// Formerly referred to as b +// Should result in 2 polygons +// "MULTIPOLYGON(((4 8,4 10,6 10,6 8,4 8)),((7 8,7 10,6 10,6 12,8 12,8 11,10 11,10 7,8 7,8 6,6 6,6 8,7 8)))" +static std::string case_117_multi[2] = +{ + "MULTIPOLYGON(((4 8,4 10,6 10,6 8,4 8)),((7 7,7 11,10 11,10 7,7 7)))", + "MULTIPOLYGON(((6 6,6 8,8 8,8 6,6 6)),((6 10,6 12,8 12,8 10,6 10)))" +}; + +// Formerly referred to as c +// Shoud result in 3 polygons: +// "MULTIPOLYGON(((4 8,4 10,6 10,6 8,4 8)),((8 8,8 10,10 10,10 8,8 8)),((7 12,7 13,13 13,13 5,7 5,7 6,6 6,6 8,8 8,8 7,11 7,11 11,8 11,8 10,6 10,6 12,7 12)))" +static std::string case_118_multi[2] = +{ + "MULTIPOLYGON(((4 8,4 10,6 10,6 8,4 8)),((8 8,8 10,10 10,10 8,8 8)),((7 11,7 13,13 13,13 5,7 5,7 7,11 7,11 11,7 11)))", + "MULTIPOLYGON(((6 6,6 8,8 8,8 6,6 6)),((6 10,6 12,8 12,8 10,6 10)))" +}; + +// Formerly referred to as d +// Should result in 2 polygons: +// "MULTIPOLYGON(((2 4,2 6,3 6,3 7,7 7,7 6,8 6,8 4,6 4,6 5,4 5,4 4,2 4)),((1 0,1 2,0 2,0 4,2 4,2 3,8 3,8 4,10 4,10 2,9 2,9 0,1 0)))" +static std::string case_119_multi[2] = +{ + "MULTIPOLYGON(((2 4,2 6,4 6,4 4,2 4)),((6 4,6 6,8 6,8 4,6 4)),((1 0,1 3,9 3,9 0,1 0)))", + "MULTIPOLYGON(((0 2,0 4,2 4,2 2,0 2)),((8 2,8 4,10 4,10 2,8 2)),((3 5,3 7,7 7,7 5,3 5)))" +}; + +// With a c/c turn +static std::string case_120_multi[2] = +{ + "MULTIPOLYGON(((6 4,6 9,9 9,9 6,11 6,11 4,6 4)),((10 7,10 10,12 10,12 7,10 7)))", + "MULTIPOLYGON(((10 5,10 8,12 8,12 5,10 5)),((6 10,8 12,10 10,8 8,6 10)))" +}; + +// With c/c turns in both involved polygons +static std::string case_121_multi[2] = +{ + "MULTIPOLYGON(((7 4,7 8,9 8,9 6,11 6,11 4,7 4)),((10 7,10 10,12 10,12 7,10 7)))", + "MULTIPOLYGON(((10 5,10 8,12 8,12 5,10 5)),((7 7,7 10,10 10,9 9,9 7,7 7)))" +}; + +// Same but here c/c not directly involved in the turns itself +// (This one breaks if continue is not checked in handle_touch) +static std::string case_122_multi[2] = +{ + "MULTIPOLYGON(((10 8,10 10,12 10,12 8,10 8)),((10 4,10 7,12 7,12 4,10 4)),((7 5,7 8,9 8,9 5,7 5)))", + "MULTIPOLYGON(((7 3,7 6,9 6,9 5,11 5,11 3,7 3)),((10 6,10 9,12 9,12 6,10 6)),((7 7,7 10,10 10,9 9,9 7,7 7)))" +}; + static std::string case_recursive_boxes_1[2] = { - // == 70 - // Used in blog. KEEP - "MULTIPOLYGON(((1 0,0 0,0 1,1 1,1 2,0 2,0 4,2 4,2 5,3 5,3 6,1 6,1 5,0 5,0 10,9 10,9 9,7 9,7 8,6 8,6 7,8 7,8 6,9 6,9 4,8 4,8 5,7 5,7 6,6 6,6 5,5 5,5 4,4 4,4 3,5 3,5 2,7 2,7 3,6 3,6 4,8 4,8 3,10 3,10 0,6 0,6 1,5 1,5 0,1 0),(4 7,4 9,3 9,3 7,4 7),(8 1,9 1,9 2,8 2,8 1)),((10 7,10 6,9 6,9 7,8 7,8 8,9 8,9 9,10 9,10 7)))", - "MULTIPOLYGON(((1 0,0 0,0 7,2 7,2 6,5 6,5 5,4 5,4 4,5 4,5 3,7 3,7 2,6 2,6 0,1 0),(2 1,2 2,3 2,3 3,1 3,1 1,2 1)),((7 0,7 2,10 2,10 0,9 0,9 1,8 1,8 0,7 0)),((6 4,6 6,5 6,5 7,6 7,6 8,5 8,5 7,3 7,3 9,2 9,2 8,1 8,1 10,4 10,4 9,6 9,6 10,10 10,10 9,9 9,9 8,10 8,10 6,9 6,9 5,10 5,10 3,7 3,7 4,6 4),(7 7,7 6,8 6,8 7,7 7)))" + "MULTIPOLYGON(((1 0,0 0,0 1,1 1,1 2,0 2,0 4,2 4,2 5,3 5,3 6,1 6,1 5,0 5,0 10,9 10,9 9,7 9,7 8,6 8,6 7,8 7,8 6,9 6,9 4,8 4,8 3,10 3,10 0,6 0,6 1,5 1,5 0,1 0),(8 4,8 5,7 5,7 6,6 6,6 5,5 5,5 4,4 4,4 3,5 3,5 2,7 2,7 3,6 3,6 4,8 4),(8 1,9 1,9 2,8 2,8 1),(4 7,4 9,3 9,3 7,4 7)),((9 9,10 9,10 7,10 6,9 6,9 7,8 7,8 8,9 8,9 9)))", + "MULTIPOLYGON(((5 6,5 7,3 7,3 9,2 9,2 8,1 8,1 10,4 10,4 9,6 9,6 10,10 10,10 9,9 9,9 8,10 8,10 6,9 6,9 5,10 5,10 3,7 3,7 4,6 4,6 6,5 6),(5 7,6 7,6 8,5 8,5 7),(7 7,7 6,8 6,8 7,7 7)),((1 0,0 0,0 7,2 7,2 6,5 6,5 5,4 5,4 4,5 4,5 3,7 3,7 2,6 2,6 0,1 0),(2 1,2 2,3 2,3 3,1 3,1 1,2 1)),((7 2,10 2,10 0,9 0,9 1,8 1,8 0,7 0,7 2)))" }; static std::string case_recursive_boxes_2[2] = { // Traversal problem; Many ii-cases -> formerly caused "Endless loop" // So it appears that there might be more decisions than intersection points - "MULTIPOLYGON(((1 0,0 0,0 4,1 4,1 5,0 5,0 10,3 10,3 9,4 9,4 10,6 10,6 9,5 9,5 8,6 8,6 9,7 9,7 10,10 10,10 0,1 0),(7 6,8 6,8 7,9 7,9 8,8 8,8 7,7 7,7 6),(9 1,9 2,8 2,8 1,9 1)))", + "MULTIPOLYGON(((1 0,0 0,0 4,1 4,1 5,0 5,0 10,3 10,3 9,4 9,4 10,6 10,6 9,7 9,7 10,10 10,10 0,1 0),(6 9,5 9,5 8,6 8,6 9),(7 6,8 6,8 7,7 7,7 6),(8 7,9 7,9 8,8 8,8 7),(9 1,9 2,8 2,8 1,9 1)))", "MULTIPOLYGON(((0 0,0 10,10 10,10 0,8 0,8 1,7 1,7 0,0 0),(7 3,6 3,6 2,7 2,7 3),(6 7,7 7,7 8,6 8,6 7)))" }; @@ -426,31 +517,31 @@ static std::string case_recursive_boxes_3[2] = { // Previously a iu/ux problem causing union to fail. // For CCW polygon it also reports a iu/iu problem. - // KEEP "MULTIPOLYGON(((8 3,9 4,9 3,8 3)),((5 9,5 10,6 10,5 9)),((2 0,2 1,3 0,2 0)),((2 5,2 6,3 6,3 5,2 5)),((2 2,1 2,1 3,2 3,3 2,3 1,2 1,2 2)),((6 8,7 9,7 7,8 7,7 6,6 6,6 8)),((4 6,5 7,5 6,4 6)),((4 8,4 9,5 9,5 8,4 8)),((0 3,1 4,1 3,0 3)),((8 7,9 8,9 7,8 7)),((9 6,9 7,10 7,9 6)),((7 0,8 1,8 0,7 0)),((0 4,0 5,1 5,1 4,0 4)),((4 2,5 3,5 2,4 1,4 2)),((4 10,4 9,2 9,3 10,4 10)),((5 2,6 3,7 3,7 2,6 2,6 1,5 0,5 2)),((5 3,4 3,4 4,2 4,4 6,4 5,4.5 4.5,6 6,6 5,7 4,5 4,5 3)),((10 2,9 1,9 3,10 2)),((8 4,7 4,8 5,7 5,7 6,9 6,9 5,10 5,10 4,8 4)),((1 7,0 7,0 8,1 8,1 7)),((1 10,2 10,1 9,0 9,0 10,1 10)),((6.5 9.5,7 10,7 9,6 9,6 10,6.5 9.5)),((8 8,8 9,10 9,9 8,8 8)))", - "MULTIPOLYGON(((0 7,0 8,1 8,1 7,0 7)),((5 3,4 3,4 4,6 4,6 3,7 3,6 2,5 2,5 3)),((8 2,8 3,9 2,8 2)),((1 1,2 2,2 1,1 1)),((2 1,3 1,2 0,1 0,2 1)),((2 3,3 4,3 3,2 3)),((1 9,2 8,1 8,1 9)),((2 10,2 9,1 9,1 10,2 10)),((9 7,9 8,10 8,10 7,9 7)),((6 0,6 1,7 1,7 0,6 0)),((8 0,9 1,9 0,8 0)),((1 6,1 5,0 5,1 6)),((0 2,1 1,0 1,0 2)),((1 3,2 3,2 2,1 2,1 3)),((5 1,5 0,4 0,4 1,3 1,4 2,5 2,6 1,5 1)),((1 3,0 3,0 4,1 4,1 3)),((3 6,4 5,2 5,3 6)),((9 2,10 2,10 1,9 1,9 2)),((7 5,6 4,6 5,7 6,8 6,8 5,7 5)),((7 4,8 5,8.5 4.5,9 5,9 4,8 4,8.5 3.5,9 4,10 3,7 3,7 4)),((1 6,1 7,3 7,3 8,4 7,5 7,6 8,6 10,7 9,8 10,9 10,9 9,8 9,8 8,7 8,6 7,6 6,1 6)))" + "MULTIPOLYGON(((7 3,7 4,8 5,8.5 4.5,9 5,9 4,10 3,8 3,7 3),(9 4,8 4,8.5 3.5,9 4)),((0 2,1 1,0 1,0 2)),((1 1,2 2,2 1,1 1)),((2 2,1 2,1 3,2 3,2 2)),((2 1,3 1,2 0,1 0,2 1)),((3 1,4 2,5 2,6 1,5 1,5 0,4 0,4 1,3 1)),((5 2,5 3,4 3,4 4,6 4,6 3,7 3,6 2,5 2)),((6 1,7 1,7 0,6 0,6 1)),((6 4,6 5,7 6,8 6,8 5,7 5,6 4)),((8 3,9 2,8 2,8 3)),((9 2,10 2,10 1,9 1,9 2)),((9 1,9 0,8 0,9 1)),((1 3,0 3,0 4,1 4,1 3)),((2 3,3 4,3 3,2 3)),((9 7,9 8,10 8,10 7,9 7)),((0 7,0 8,1 8,1 7,0 7)),((1 8,1 9,2 8,1 8)),((1 7,3 7,3 8,4 7,5 7,6 8,6 10,7 9,8 10,9 10,9 9,8 9,8 8,7 8,6 7,6 6,3 6,1 6,1 7)),((1 6,1 5,0 5,1 6)),((3 6,4 5,2 5,3 6)),((1 9,1 10,2 10,2 9,1 9)))" }; static std::string case_recursive_boxes_4[2] = { - // Occurred after refactoring assemble - not valid! - "MULTIPOLYGON(((9 3,10 4,10 3,9 3)),((9 9,10 10,10 9,9 9)),((0 1,0 3,1 4,0 4,0 5,1 6,0 6,0 8,1 9,1 8,2 9,2 7,1.5 6.5,2.5 5.5,3 6,3 5,4 6,2 6,2 7,3 8,2 8,3 9,0 9,0 10,6 10,5.5 9.5,6 9,6 10,7 10,7.5 9.5,8 10,8 9,7 9,7 8,6 8,6.5 7.5,7 8,8 8,8 9,9 9,9.5 8.5,10 9,10 8,9.5 7.5,10 7,10 5,8 5,8 4,7 3,7 2,8 3,8 4,9 5,9 3,10 2,10 1,8 1,8.5 0.5,9 1,10 0,4 0,4 1,3 1,3 0,1 0,1 1,0 0,0 1),(4 2,4.5 1.5,5 2,5 4,4.5 3.5,5 3,4 3,4 2),(3 3,4 4,2 4,2.5 3.5,3 4,3 3),(6 4,6.5 3.5,7 4,6 4),(5 7,5 9,4 9,4 8,5 7)))", - "MULTIPOLYGON(((1 0,2 1,2 0,1 0)),((7 9,7 10,8 10,7 9)),((1 0,0 0,0 3,1 3,2 2,2 3,1 3,1 4,2 4,2 5,1 4,0 4,0 8,1 7,1 6,2 7,1 7,1 9,0 9,0 10,7 10,6 9,6.5 8.5,7 9,8 9,9 8,8 8,9 7,9 6,10 7,10 5,9 5,9 4,10 5,10 0,7 0,8 1,7 1,6 0,3 0,3 1,1 1,1 0),(5 1,5.5 0.5,6 1,6 2,6.5 1.5,7 2,8 2,8 4,7 3,6 3,6 2,5 2,6 1,5 1),(4 4,5 4,5 5,4 4),(4 6,4 7,3 7,2 6,3 6,3 7,4 6),(6 5,6.5 4.5,7 5,6 5,7 6,7 7,6 7,6 5),(3.5 7.5,4 8,4 9,3 8,3.5 7.5)),((9 8,9 9,8 9,9 10,10 10,10 8,9 8)))" + // Occurred after refactoring assemble + "MULTIPOLYGON(((0 1,0 3,1 4,0 4,0 5,1 6,0 6,0 8,1 9,0 9,0 10,6 10,7 10,7.5 9.5,8 10,8 9,9 9,9.5 8.5,10 9,10 8,9.5 7.5,10 7,10 5,9 5,9 3,10 2,10 1,9 1,10 0,4 0,4 1,3 1,3 0,1 0,1 1,0 0,0 1),(1 9,1 8,2 9,1 9),(2 9,2 8,3 9,2 9),(2 8,2 7,3 8,2 8),(2 7,1.5 6.5,2 6,2 7),(2 6,2.5 5.5,3 6,2 6),(3 6,3 5,4 6,3 6),(6 10,5.5 9.5,6 9,6 10),(8 9,7 9,7 8,8 8,8 9),(7 8,6 8,6.5 7.5,7 8),(9 5,8 5,8 4,9 5),(8 4,7 3,7 2,8 3,8 4),(9 1,8 1,8.5 0.5,9 1),(6 4,6.5 3.5,7 4,6 4),(4 2,4.5 1.5,5 2,5 3,4 3,4 2),(5 3,5 4,4.5 3.5,5 3),(5 7,5 9,4 9,4 8,5 7),(3 3,4 4,3 4,3 3),(3 4,2 4,2.5 3.5,3 4)),((9 3,10 4,10 3,9 3)),((10 9,9 9,10 10,10 9)))", + "MULTIPOLYGON(((1 0,0 0,0 3,1 3,1 4,0 4,0 8,1 7,1 9,0 9,0 10,7 10,6 9,6.5 8.5,7 9,8 9,9 8,8 8,9 7,9 6,10 7,10 5,10 0,7 0,8 1,7 1,6 0,3 0,3 1,2 1,1 1,1 0),(1 3,2 2,2 3,1 3),(1 4,2 4,2 5,1 4),(1 7,1 6,2 7,1 7),(10 5,9 5,9 4,10 5),(5 1,5.5 0.5,6 1,5 1),(6 1,6 2,5 2,6 1),(6 2,6.5 1.5,7 2,8 2,8 4,7 3,6 3,6 2),(6 5,7 6,7 7,6 7,6 5),(6 5,6.5 4.5,7 5,6 5),(4 4,5 4,5 5,4 4),(3 7,2 6,3 6,3 7),(3 7,4 6,4 7,3 7),(3.5 7.5,4 8,4 9,3 8,3.5 7.5)),((1 0,2 1,2 0,1 0)),((7 10,8 10,7 9,7 10)),((8 9,9 10,10 10,10 8,9 8,9 9,8 9)))" }; static std::string case_recursive_boxes_5[2] = { // Occurs after refactoring uu / handle_touch (not yet integrated) "MULTIPOLYGON(((0 9,0 10,1 10,1 9,0 9)),((9 0,9 1,10 1,10 0,9 0)),((5 6,5 7,6 7,6 6,7 6,7 4,6 4,6 5,5 5,5 6)),((5 3,7 3,7 2,4 2,4 3,5 3)),((5 8,5 9,7 9,7 8,5 8)),((4 0,1 0,1 1,5 1,5 0,4 0)),((3 5,3 4,4 4,4 3,2 3,2 2,1 2,1 3,0 3,0 4,2 4,2 5,1 5,1 6,4 6,4 5,3 5)),((0 2,1 2,1 1,0 1,0 2)),((4 10,4 7,1 7,1 6,0 6,0 8,1 8,1 9,2 9,2 10,4 10)),((9 4,9 3,8 3,8 5,9 5,9 4)),((7 2,8 2,8 0,7 0,7 2)),((8 7,10 7,10 6,7 6,7 8,8 8,8 7)))", - "MULTIPOLYGON(((2 3,2 4,3 4,3 3,2 3)),((1 5,1 6,2 6,2 5,1 5)),((2 1,2 2,3 2,3 1,2 1)),((8 1,9 1,9 0,8 0,8 1)),((9 7,10 7,10 6,9 6,9 7)),((1 4,1 3,0 3,0 5,1 5,1 4)),((7 6,7 7,8 7,8 6,7 6)),((7 1,7 2,8 2,8 1,7 1)),((6 2,6 3,7 3,7 2,6 2)),((6 8,6 9,7 9,7 8,6 8)),((5 0,3 0,3 1,4 1,4 2,6 2,6 1,7 1,7 0,5 0)),((5 5,5 6,6 6,6 5,8 5,8 6,9 6,9 4,8 4,8 3,7 3,7 4,6 4,6 3,5 3,5 4,3 4,3 6,2 6,2 8,3 8,3 7,5 7,5 6,4 6,4 5,5 5)),((1 1,2 1,2 0,1 0,1 1)),((1 3,2 3,2 2,1 2,1 3)),((3 10,4 10,4 9,2 9,2 8,0 8,0 10,3 10)),((10 3,10 1,9 1,9 2,8 2,8 3,9 3,9 4,10 4,10 3)),((9 9,10 9,10 8,9 8,9 7,8 7,8 10,9 10,9 9)))" + "MULTIPOLYGON(((2 6,2 8,3 8,3 7,5 7,5 6,6 6,6 5,8 5,8 6,9 6,9 4,8 4,8 3,7 3,7 4,6 4,6 3,5 3,5 4,3 4,3 6,2 6),(5 6,4 6,4 5,5 5,5 6)),((1 1,2 1,2 0,1 0,1 1)),((2 1,2 2,3 2,3 1,2 1)),((2 2,1 2,1 3,2 3,2 2)),((1 3,0 3,0 5,1 5,1 4,1 3)),((1 5,1 6,2 6,2 5,1 5)),((2 8,0 8,0 10,3 10,4 10,4 9,2 9,2 8)),((8 6,7 6,7 7,8 7,8 6)),((8 7,8 10,9 10,9 9,10 9,10 8,9 8,9 7,8 7)),((9 7,10 7,10 6,9 6,9 7)),((9 4,10 4,10 3,10 1,9 1,9 2,8 2,8 3,9 3,9 4)),((8 2,8 1,7 1,7 2,8 2)),((8 1,9 1,9 0,8 0,8 1)),((7 1,7 0,5 0,3 0,3 1,4 1,4 2,6 2,6 1,7 1)),((6 2,6 3,7 3,7 2,6 2)),((3 4,3 3,2 3,2 4,3 4)),((6 8,6 9,7 9,7 8,6 8)))" }; static std::string case_recursive_boxes_6[2] = { + // [1] is reported as invalid by BG, but not by postgis // Fixed by replacing handle_tangencies - "MULTIPOLYGON(((2 2,1.5 1.5,2 1,1 1,2 0,0 0,0 3,1 3,1 4,2 4,2 5,5 5,5 0,2 0,2 2,3 1,3 2,3.5 1.5,4 2,2 2)),((1 5,2 5,0 3,0 5,1 5)))", - "MULTIPOLYGON(((2 1,2 2,1 2,2 3,1 3,1 4,0 4,0 5,5 5,5 2,4 2,4 3,3 3,4 2,3 2,3 1,2 1)),((2 0,0 0,0 3,1 3,1 2,3 0,2 0)),((4 0,3 0,3 1,4 2,4 1,5 1,5 0,4 0)))" + "MULTIPOLYGON(((0 3,1 3,1 4,2 4,2 5,5 5,5 0,2 0,0 0,0 3),(2 0,2 1,1 1,2 0),(2 1,2 2,1.5 1.5,2 1),(2 2,3 1,3 2,2 2),(3 2,3.5 1.5,4 2,3 2)),((0 3,0 5,1 5,2 5,1 4,0 3)))", + "MULTIPOLYGON(((1 2,2 3,1 3,1 4,0 4,0 5,5 5,5 2,4 2,3 2,3 1,2 1,2 2,1 2),(4 2,4 3,3 3,4 2)),((1 2,2 1,3 0,2 0,0 0,0 3,1 3,1 2)),((3 0,3 1,4 2,4 1,5 1,5 0,4 0,3 0)))" }; static std::string case_recursive_boxes_7[2] = @@ -463,7 +554,7 @@ static std::string case_recursive_boxes_8[2] = { // Having colocated IP halfway segment "MULTIPOLYGON(((3 4,3 3,2 3,2 2,0 2,0 3,1 3,1 4,1.5 3.5,2 4,3 4)),((2 5,2 4,1 4,0 3,0 5,2 5)))", - "MULTIPOLYGON(((3 4,4 4,4 3,3 3,3 1,0 1,0 2,1 2,1 3,0 2,0 4,3 4)))" + "MULTIPOLYGON(((0 2,0 4,3 4,4 4,4 3,3 3,3 1,0 1,0 2),(0 2,1 2,1 3,0 2)))" }; static std::string case_recursive_boxes_9[2] = @@ -496,44 +587,63 @@ static std::string case_recursive_boxes_11[4] = }; static std::string case_recursive_boxes_12[2] = +{ + "MULTIPOLYGON(((0 3,1 3,0.5 2.5,1 2,0 2,0 3)),((1 2,2 2,2 1,1 1,1 2)),((2 1,3 2,3 1,2 1)),((2 2,2 3,3 3,2 2)),((0 0,0 1,1 0,0 0)))", + "MULTIPOLYGON(((0 1,0 2,1 2,0 1)),((0 1,1 1,1.5 0.5,2 1,2 0,0 0,0 1)),((1 3,1 4,2 3,1 2,1 3)))" +}; + +static std::string case_recursive_boxes_13[2] = +{ + "MULTIPOLYGON(((1 3,1 5,2 5,2 4,1.5 3.5,2 3,1 3)),((1 3,2 2,0 2,1 3)),((2 2,3 2,3 1,2 1,2 2)),((3 2,3 3,4 3,4 2,3 2)))", + "MULTIPOLYGON(((1 4,1 3,0 3,0 4,1 5,1 4)),((3 5,4 5,4 4,2 4,2 5,3 5)),((3 1,3 2,5 2,5 1,3 1)))" +}; + +static std::string case_recursive_boxes_14[2] = +{ + "MULTIPOLYGON(((2 2,2 3,3 2,2 2)),((2 3,3 4,3 3,2 3)),((2 3,1 3,1 4,2 4,2 3)))", + "MULTIPOLYGON(((3 3,4 4,4 3,3 3)),((1 2,2 3,2 2,1 2)),((2 1,2 2,3 1,2 1)),((1 4,1 5,2 5,2 4,1 4)))" +}; + +static std::string case_recursive_boxes_12_invalid[2] = { // One of them is invalid requiring discarding turns colocated with uu in these clusters "MULTIPOLYGON(((2 2,2 3,3 3,2 2)),((0 0,0 1,1 0,0 0)),((0 3,1 3,0.5 2.5,1 2,0 2,0 3)),((3 2,3 1,1 1,1 2,2 2,2 1,3 2)))", "MULTIPOLYGON(((0 1,0 2,1 2,0 1)),((0 1,1 1,1.5 0.5,2 1,2 0,0 0,0 1)),((1 3,1 4,2 3,1 2,1 3)))" }; -static std::string case_recursive_boxes_13[2] = +static std::string case_recursive_boxes_13_invalid[2] = { // Strictly invalid, requires checking seg_id while considering skipping to next turn "MULTIPOLYGON(((2 1,2 2,3 2,3 1,2 1)),((3 2,3 3,4 3,4 2,3 2)),((2 4,1.5 3.5,2 3,1 3,2 2,0 2,1 3,1 5,2 5,2 4)))", "MULTIPOLYGON(((1 4,1 3,0 3,0 4,1 5,1 4)),((3 5,4 5,4 4,2 4,2 5,3 5)),((3 1,3 2,5 2,5 1,3 1)))" }; -static std::string case_recursive_boxes_14[2] = +static std::string case_recursive_boxes_14_invalid[2] = { // Strictly invalid, requires skipping assignment of discarded turns for clusters "MULTIPOLYGON(((2 2,2 3,3 2,2 2)),((2 4,2 3,3 4,3 3,1 3,1 4,2 4)))", "MULTIPOLYGON(((3 3,4 4,4 3,3 3)),((1 2,2 3,2 2,1 2)),((2 1,2 2,3 1,2 1)),((1 4,1 5,2 5,2 4,1 4)))" }; + static std::string case_recursive_boxes_15[2] = { // Requires inspecting blocked operations in traversing cluster "MULTIPOLYGON(((3 2,3 3,4 3,3 2)),((4 1,4 2,5 2,5 1,4 1)),((4 2,4 3,5 3,4 2)),((3 5,4 4,2 4,2 5,3 5)))", - "MULTIPOLYGON(((3 4,4 3,4 4,5 4,5 3,4 3,3 2,3 3,2 3,2 4,3 4)))" + "MULTIPOLYGON(((3 4,4 3,3 2,3 3,2 3,2 4,3 4)),((4 3,4 4,5 4,5 3,4 3)))" }; static std::string case_recursive_boxes_16[2] = { // Requires inspecting if traverse is possible in selecting continue operation - "MULTIPOLYGON(((2 4,1 3,0 3,0 5,3 5,3 4,4 4,4 5,5 5,5 4,4 3,2 3,3 4,2 4)),((2.5 1.5,3 1,3 2,4 2,4 1,5 2,5 0,3 0,3 1,2.5 0.5,3 0,0 0,0 2,3 2,2.5 1.5)))", - "MULTIPOLYGON(((2 1,2 2,3 1,2 1)),((3 5,5 5,5 4,4 4,4 3,5 3,5 2,4 1,4 2,3 2,3 4,2 4,2 5,3 5)),((2 2,1 1,1 2,0 1,1 1,1 0,0 0,0 5,1 5,1 3,2 3,2 2)),((4 1,5 1,5 0,3 0,3 2,4 1)))" + "MULTIPOLYGON(((2 4,1 3,0 3,0 5,3 5,3 4,2 4)),((3 4,4 4,4 5,5 5,5 4,4 3,2 3,3 4)),((2.5 1.5,3 1,2.5 0.5,3 0,0 0,0 2,3 2,2.5 1.5)),((3 1,3 2,4 2,4 1,5 2,5 0,3 0,3 1)))", + "MULTIPOLYGON(((0 1,1 1,1 0,0 0,0 1)),((0 1,0 5,1 5,1 3,2 3,2 2,1 1,1 2,0 1)),((2 2,3 1,2 1,2 2)),((3 1,3 2,4 1,5 1,5 0,3 0,3 1)),((4 1,4 2,3 2,3 4,2 4,2 5,3 5,5 5,5 4,4 4,4 3,5 3,5 2,4 1)))" }; static std::string case_recursive_boxes_17[2] = { // Requires including uu turns, at least in clusters - "MULTIPOLYGON(((0 4,0 5,1 5,0 4)),((4 0,5 1,5 0,4 0)),((4 5,5 5,5 4,3 4,3 5,4 5)),((3 4,3 3,2 2,1 2,1 1,2 1,2 2,2.5 1.5,4 3,5 3,5 1,4 1,4 0,3 0,3 1,2 1,3 0,0 0,0 2,1 2,1 5,1.5 4.5,2 5,2 4,3 4),(2 3,2 4,1 3,2 3)))", + "MULTIPOLYGON(((0 4,0 5,1 5,0 4)),((1 5,1.5 4.5,2 5,2 4,1 3,1 5)),((2 4,3 4,3 3,2 2,1 2,1 3,2 3,2 4)),((1 2,1 1,2 1,3 0,0 0,0 2,1 2)),((2 1,2 2,2.5 1.5,4 3,5 3,5 1,4 1,4 0,3 0,3 1,2 1)),((4 0,5 1,5 0,4 0)),((3 4,3 5,4 5,5 5,5 4,3 4)))", "MULTIPOLYGON(((2 5,3 5,2 4,2 5)),((3 1,4 2,4 0,3 0,3 1)),((2 0,0 0,0 1,1 2,0 2,1 3,2 2,2 3,3 2,3 1,2 0)),((1 4,0.5 3.5,1 3,0 3,0 4,1 4)),((4 3,3 3,3 5,4 5,4 4,5 4,5 2,4 2,4 3)))" }; @@ -569,15 +679,14 @@ static std::string case_recursive_boxes_21[2] = static std::string case_recursive_boxes_22[2] = { // Requires including ux turns for intersections to block paths - "MULTIPOLYGON(((2.5 1.5,3 1,2 1,2 3,3 3,2 2,3 2,2.5 1.5)))", + "MULTIPOLYGON(((2 2,3 2,2.5 1.5,3 1,2 1,2 2)),((2 2,2 3,3 3,2 2)))", "MULTIPOLYGON(((1 2,0 2,0 3,1 2)),((1 2,2 3,2 1,1 1,1 2)))" }; static std::string case_recursive_boxes_23[2] = { - // [0] is invalid, [1] is valid // Requires discarding turns with uu for intersection/difference too - "MULTIPOLYGON(((4.5 3.5,5 4,5 3,4 3,5 2,4 2,4 4,4.5 3.5)))", + "MULTIPOLYGON(((4 3,4 4,4.5 3.5,5 4,5 3,4 3)),((4 3,5 2,4 2,4 3)))", "MULTIPOLYGON(((4 3,5 4,5 3,4 3)),((3 3,3 4,4 3,3 3)))" }; @@ -627,7 +736,7 @@ static std::string case_recursive_boxes_30[2] = { // Requires not discarding turns colocated with uu/invalid polygons (now not necessary anymore because of startable) "MULTIPOLYGON(((2 2,2 3,4 3,4 4,4.5 3.5,5 4,5 0,3 0,3 1,4 1,4 2,2 2)),((1 5,3 5,4 4,0 4,0 5,1 5)))", - "MULTIPOLYGON(((2 1,2 3,1 3,1 4,2 5,2 4,3 4,3 5,5 5,5 4,4 4,3.5 3.5,4 3,4 4,5 3,4.5 2.5,5 2,5 0,4 0,4 2,3 2,3 3,2.5 2.5,4 1,3 1,3 0,1 0,2 1)))" + "MULTIPOLYGON(((2 1,2 3,1 3,1 4,2 5,2 4,3 4,3 5,5 5,5 4,4 4,5 3,4.5 2.5,5 2,5 0,4 0,4 1,3 1,3 0,1 0,2 1),(4 4,3.5 3.5,4 3,4 4),(4 1,4 2,3 2,4 1),(3 2,3 3,2.5 2.5,3 2)))" }; static std::string case_recursive_boxes_31[2] = @@ -655,14 +764,14 @@ static std::string case_recursive_boxes_34[2] = { // Requires detecting finished arcs during cluster traversal "MULTIPOLYGON(((2 0,0 0,0 5,2 5,2 4,3 5,5 5,5 0,2 0)))", - "MULTIPOLYGON(((3 3,2 3,2 2,3 2,3 1,2 0,1 0,2 1,1 1,1 0,0 0,0 5,1 4,1 5,4 5,3 4,3.5 3.5,4 4,4 5,5 4,5 1,4 1,4 3,3 3)),((3 1,4 1,3 0,3 1)))" + "MULTIPOLYGON(((1 0,0 0,0 5,1 4,1 5,4 5,5 4,5 1,4 1,4 3,3 3,2 3,2 2,3 2,3 1,2 0,1 0),(1 0,2 1,1 1,1 0),(4 5,3 4,3.5 3.5,4 4,4 5)),((4 1,3 0,3 1,4 1)))" }; static std::string case_recursive_boxes_35[2] = { // Requires detecting finished arcs during cluster traversal - "MULTIPOLYGON(((3 1,2 1,3 0,0 0,0 2,1 2,1 3,0 2,0 5,4 5,4 4,5 4,5 1,4 1,5 0,3 0,3 1),(2.5 1.5,3 2,2 2,2.5 1.5),(2 4,1 4,2 3,2 4)))", - "MULTIPOLYGON(((2 2,1.5 1.5,2 1,1 1,1 0,0 0,0 5,3 5,2.5 4.5,3 4,3 5,5 5,5 0,1 0,2 1,2 2),(3 2,3 3,2.5 2.5,3 2),(2 3,2 4,1 4,1 3,2 3)))" + "MULTIPOLYGON(((0 2,0 5,4 5,4 4,5 4,5 1,4 1,5 0,3 0,0 0,0 2),(0 2,1 2,1 3,0 2),(3 0,3 1,2 1,3 0),(2.5 1.5,3 2,2 2,2.5 1.5),(2 4,1 4,2 3,2 4)))", + "MULTIPOLYGON(((1 0,0 0,0 5,3 5,5 5,5 0,1 0),(1 0,2 1,1 1,1 0),(2 1,2 2,1.5 1.5,2 1),(3 5,2.5 4.5,3 4,3 5),(3 2,3 3,2.5 2.5,3 2),(2 3,2 4,1 4,1 3,2 3)))" }; static std::string case_recursive_boxes_36[2] = @@ -674,9 +783,17 @@ static std::string case_recursive_boxes_36[2] = static std::string case_recursive_boxes_37[2] = { + // [1] is reported as invalid by BG, but not by postgis // Requires skipping arc for union too, to avoid duplicate hole "MULTIPOLYGON(((4 0,5 1,5 0,4 0)),((2 0,3 1,3 0,2 0)),((2 3,2 2,1 2,1 3,2 3)),((2 1,2 2,4 2,3 1,2 1)))", - "MULTIPOLYGON(((2 3,1 2,1 3,2 3)),((3 1,3.5 0.5,4 1,3 1,4 2,4 3,5 3,5 0,3 0,3 1)),((3 1,2 0,2 1,3 1)))" + "MULTIPOLYGON(((3 1,4 2,4 3,5 3,5 0,3 0,3 1),(3 1,3.5 0.5,4 1,3 1)),((3 1,2 0,2 1,3 1)),((2 3,1 2,1 3,2 3)))" +}; + +static std::string case_recursive_boxes_38[2] = +{ + // Smaller version of 29, removing generated lower interior in a union + "MULTIPOLYGON(((2 3,2 4,1 4,2 5,4 5,4 4,3 4,3 3,2 3)),((3 3,4 3,4 1,5 1,5 0,3 0,3 2,2 2,3 3)),((1 2,0 2,0 3,1 3,1 2)),((1 1,0 1,1 2,2 2,2 1,1 1)))", + "MULTIPOLYGON(((2 2,4 2,4 1,2 1,2 2)),((0 4,0 5,1 4,0 4)),((2 3,2 4,4 4,4 3,2 3)),((2 2,1 2,1 3,2 3,2 2)),((1 2,0 2,0 3,1 3,0.5 2.5,1 2)))" }; static std::string pie_21_7_21_0_3[2] = @@ -791,6 +908,17 @@ static std::string ticket_11984[2] = "MULTIPOLYGON(((-31 6,-51 220,-84 241,-120 249,-146 224,-67 56,-74 52,-95 60,-38 10,-38 9)))", }; +static std::string ticket_12118[2] = + { + "MULTIPOLYGON(((13.08940410614013671875 -70.98416137695312500000,12.81384754180908203125 -67.55441284179687500000,12.60483169555664062500 -63.57923889160156250000,13.56438255310058593750 -54.91608428955078125000,13.80568027496337890625 -43.62073516845703125000,13.00057315826416015625 -33.85240554809570312500,9.29664993286132812500 -33.23409271240234375000,19.66869926452636718750 -14.42036247253417968750,-5.96064376831054687500 -17.19871711730957031250,-14.87041568756103515625 -6.99879980087280273438,-22.50806808471679687500 -27.92480468750000000000,-22.16161727905273437500 -45.15484619140625000000,-22.42436790466308593750 -54.01613616943359375000,-23.13828659057617187500 -59.28628540039062500000,-23.18314933776855468750 -68.01937866210937500000,-22.86939430236816406250 -72.78530883789062500000,-23.02970123291015625000 -72.76760864257812500000,-22.81921195983886718750 -73.54760742187500000000,-18.65677833557128906250 -73.25045776367187500000,3.16641521453857421875 -75.66014099121093750000,12.75282478332519531250 -76.71865844726562500000,13.08940410614013671875 -70.98416137695312500000)))", + "MULTIPOLYGON(((3.16641521453857421875 -75.66014099121093750000,12.75282478332519531250 -76.71865844726562500000,12.95001888275146484375 -74.61856842041015625000,3.16641521453857421875 -75.66014099121093750000)),((-22.84768676757812500000 -78.42963409423828125000,-20.92837524414062500000 -78.22530364990234375000,3.16641521453857421875 -75.66014099121093750000,-23.02970123291015625000 -72.76760864257812500000,-22.84768676757812500000 -78.42963409423828125000)))", + }; + +static std::string ticket_12125[2] = + { + "MULTIPOLYGON(((-5.96064376831054687500 -17.19871711730957031250,7.83307075500488281250 -32.98977279663085937500,8.81292819976806640625 -34.11151504516601562500,19.66869926452636718750 -14.42036247253417968750,-5.96064376831054687500 -17.19871711730957031250)),((-14.87041568756103515625 -6.99879980087280273438,-16.12161636352539062500 -18.30021858215332031250,-5.96064376831054687500 -17.19871711730957031250,-14.87041568756103515625 -6.99879980087280273438)))", + "MULTIPOLYGON(((7.83307075500488281250 -32.98977279663085937500,8.81292819976806640625 -34.11151504516601562500,13.00057315826416015625 -33.85240554809570312500,7.83307075500488281250 -32.98977279663085937500)),((-22.50806808471679687500 -27.92480468750000000000,7.83307075500488281250 -32.98977279663085937500,-14.87041568756103515625 -6.99879980087280273438,-22.50806808471679687500 -27.92480468750000000000))) ", + }; static std::string bug_21155501[2] = { diff --git a/test/algorithms/overlay/overlay.cpp b/test/algorithms/overlay/overlay.cpp index ef10d7681..f45b211e4 100644 --- a/test/algorithms/overlay/overlay.cpp +++ b/test/algorithms/overlay/overlay.cpp @@ -129,8 +129,9 @@ struct map_visitor for (typename Clusters::const_iterator it = clusters.begin(); it != clusters.end(); ++it) { std::cout << " CLUSTER " << it->first << ": "; - for (typename std::set::const_iterator sit = it->second.begin(); - sit != it->second.end(); ++sit) + for (typename std::set::const_iterator sit + = it->second.turn_indices.begin(); + sit != it->second.turn_indices.end(); ++sit) { std::cout << " " << *sit; } diff --git a/test/algorithms/overlay/overlay_cases.hpp b/test/algorithms/overlay/overlay_cases.hpp index ee88b0a57..b31fb3358 100644 --- a/test/algorithms/overlay/overlay_cases.hpp +++ b/test/algorithms/overlay/overlay_cases.hpp @@ -508,6 +508,12 @@ static std::string case_99[2] = "POLYGON((10 10,10 30,30 30,30 10,10 10))" }; +static std::string case_100[2] = + { + "POLYGON((2 1,4 1,4 3,2 3,2 1),(3 1.5,4 3,2.5 2.5,3 1.5))", + "POLYGON((4 0,8 0,8 4,4 4,4 0))" + }; + static std::string case_many_situations[2] = { "POLYGON((2 6,2 14,10 18,18 14,18 6,16 5,14 4,12 3,10 2,8 3,6 4,4 5,2 6))", "POLYGON((2 6,2 7,2 8,2 9,2 10,2 11,2 12,1 14" @@ -1105,12 +1111,6 @@ static std::string mysql_23023665_3[2] = "POLYGON((6 0,-5 0,-1 -12,6 0))" }; -static std::string mysql_23023665_4[2] = - { - "POLYGON((7 0,10 -3,7 1,7 0))", - "POLYGON((7 4,-14 10,7 -17,7 4),(7 1,0 3,-2 4,7 1))" - }; - static std::string mysql_23023665_5[2] = { "POLYGON((8 6,5 7,-1 4,-8 -7,0 -17,8 6),(3 6,5 5,0 -2,3 6))", diff --git a/test/algorithms/overlay/traverse_multi.cpp b/test/algorithms/overlay/traverse_multi.cpp index 7c2f1090f..ef424763a 100644 --- a/test/algorithms/overlay/traverse_multi.cpp +++ b/test/algorithms/overlay/traverse_multi.cpp @@ -191,14 +191,9 @@ void test_geometries() test_traverse_intersection::apply ( - "case_108_multi_a", 7, 7.5, + "case_108_multi", 7, 7.5, case_108_multi[0], case_108_multi[1] ); - test_traverse_intersection::apply - ( - "case_108_multi_b", 7, 7.5, - case_108_multi[0], case_108_multi[2] - ); test_traverse_intersection::apply ( diff --git a/test/algorithms/set_operations/difference/difference.cpp b/test/algorithms/set_operations/difference/difference.cpp index 9d1c106f4..3e92f6848 100644 --- a/test/algorithms/set_operations/difference/difference.cpp +++ b/test/algorithms/set_operations/difference/difference.cpp @@ -17,10 +17,6 @@ #include #include -// If defined, tests are run without rescaling-to-integer or robustness policy -// Test which would fail then are disabled automatically -// #define BOOST_GEOMETRY_NO_ROBUSTNESS - #include #include @@ -48,10 +44,19 @@ void test_all() typedef typename bg::coordinate_type

::type ct; + ut_settings ignore_validity; + ignore_validity.test_validity = false; + + ut_settings sym_settings; +#if defined(BOOST_GEOMETRY_NO_ROBUSTNESS) + sym_settings.sym_difference = false; +#endif + test_one("simplex_normal", simplex_normal[0], simplex_normal[1], 3, 12, 2.52636706856656, - 3, 12, 3.52636706856656); + 3, 12, 3.52636706856656, + sym_settings); test_one("simplex_with_empty", simplex_normal[0], polygon_empty, @@ -61,19 +66,19 @@ void test_all() test_one( "star_ring", example_star, example_ring, 5, 22, 1.1901714, - 5, 27, 1.6701714); + 5, 27, 1.6701714, + sym_settings); test_one("two_bends", two_bends[0], two_bends[1], 1, 5, 8.0, 1, 5, 8.0); -#if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS) test_one("star_comb_15", star_comb_15[0], star_comb_15[1], 30, 160, 227.658275102812, - 30, 198, 480.485775259312); -#endif + 30, 198, 480.485775259312, + sym_settings); test_one("new_hole", new_hole[0], new_hole[1], @@ -107,12 +112,14 @@ void test_all() test_one("only_hole_intersections1", only_hole_intersections[0], only_hole_intersections[1], 2, 10, 1.9090909, - 4, 16, 10.9090909); + 4, 16, 10.9090909, + sym_settings); test_one("only_hole_intersection2", only_hole_intersections[0], only_hole_intersections[2], 3, 20, 30.9090909, - 4, 16, 10.9090909); + 4, 16, 10.9090909, + sym_settings); test_one("first_within_second", first_within_second[1], first_within_second[0], @@ -145,11 +152,15 @@ void test_all() 3, 21, 16.25, 3, 17, 6.25); - test_one("intersect_holes_new_ring", - intersect_holes_new_ring[0], intersect_holes_new_ring[1], - 3, 15, 9.8961, - 4, 25, 121.8961, - tolerance(0.01)); + { + ut_settings settings = sym_settings; + settings.percentage = 0.01; + test_one("intersect_holes_new_ring", + intersect_holes_new_ring[0], intersect_holes_new_ring[1], + 3, 15, 9.8961, + 4, 25, 121.8961, + settings); + } test_one("first_within_hole_of_second", first_within_hole_of_second[0], first_within_hole_of_second[1], @@ -169,7 +180,8 @@ void test_all() test_one( "case4", case_4[0], case_4[1], 6, 28, 2.77878787878788, - 4, 22, 4.77878787878788); + 4, 22, 4.77878787878788, + sym_settings); test_one( "case5", case_5[0], case_5[1], @@ -188,7 +200,8 @@ void test_all() test_one("case_80", case_80[0], case_80[1], 1, 9, 44.5, - 1, 10, 84.5); + 1, 10, 84.5, + ignore_validity); #ifdef BOOST_GEOMETRY_TEST_INCLUDE_FAILING_TESTS // Fails, holes are not subtracted @@ -199,6 +212,13 @@ void test_all() 1, 12, 80.5 + 83.0); #endif + test_one("case_100", + case_100[0], case_100[1], + 1, 7, 3.125, + 1, 7, 16.0, + 1, 13, 16.0 + 3.125, + ignore_validity); + test_one("winded", winded[0], winded[1], 3, 37, 61, @@ -215,12 +235,12 @@ void test_all() 1, 5, 1, 1, 7, 2); -#if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS) test_one("buffer_mp1", buffer_mp1[0], buffer_mp1[1], 1, 61, 10.2717, 1, 61, 10.2717); +#if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS) if ( BOOST_GEOMETRY_CONDITION((boost::is_same::value)) ) { test_one("buffer_mp2", @@ -242,17 +262,23 @@ void test_all() 1, 0, 13); ***/ - // Isovist - the # output polygons differ per compiler/pointtype, (very) small - // rings might be discarded. We check area only - test_one("isovist", - isovist1[0], isovist1[1], - -1, -1, 0.279132, - -1, -1, 224.8892, + { + ut_settings settings; #if defined(BOOST_GEOMETRY_NO_ROBUSTNESS) - tolerance(0.1)); + settings.percentage = 0.1; + settings.test_validity = false; #else - tolerance(0.001)); + settings.percentage = 0.001; #endif + + // Isovist - the # output polygons differ per compiler/pointtype, (very) small + // rings might be discarded. We check area only + test_one("isovist", + isovist1[0], isovist1[1], + -1, -1, 0.279132, + -1, -1, 224.8892, + settings); + } // SQL Server gives: 0.279121891701124 and 224.889211358929 // PostGIS gives: 0.279121991127244 and 224.889205853156 // No robustness gives: 0.279121991127106 and 224.825363749290 @@ -272,30 +298,38 @@ void test_all() // PostGIS gives: 0.30859375 and 0.033203125 with 35/35 rings #endif -#if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS) - test_one("geos_2", - geos_2[0], geos_2[1], - 1, -1, 138.6923828, - 1, -1, 211.859375, - tolerance(0.01)); // MSVC 14 expects 138.69214 and 211.85913 + { + // MSVC 14 expects 138.69214 and 211.85913: increase percentage + + ut_settings settings = sym_settings; + settings.percentage = 0.01; + settings.test_validity = false; + + test_one("geos_2", + geos_2[0], geos_2[1], + 1, -1, 138.6923828, + 1, -1, 211.859375, + settings); + } test_one("geos_3", geos_3[0], geos_3[1], 1, -1, 16211128.5, 1, -1, 13180420.0, - 1, -1, 16211128.5 + 13180420.0); -#endif + 1, -1, 16211128.5 + 13180420.0, + sym_settings); test_one("geos_4", geos_4[0], geos_4[1], 1, -1, 971.9163115, - 1, -1, 1332.4163115); + 1, -1, 1332.4163115, + sym_settings); test_one("ggl_list_20110306_javier", ggl_list_20110306_javier[0], ggl_list_20110306_javier[1], 1, -1, 71495.3331, 2, -1, 8960.49049, - 1, -1, 71495.3331 + 8960.49049); + 2, -1, 71495.3331 + 8960.49049); test_one("ggl_list_20110307_javier", ggl_list_20110307_javier[0], ggl_list_20110307_javier[1], @@ -373,11 +407,15 @@ void test_all() ticket_9563[0], ticket_9563[1], 0, 0, 0, 6, 24, 20.096189); +#endif test_one("ticket_10108_a", ticket_10108_a[0], ticket_10108_a[1], 1, 4, 0.0145037, - 1, 4, 0.029019232); + 1, 4, 0.029019232, + sym_settings); + +#if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS) test_one("ticket_10108_b", ticket_10108_b[0], ticket_10108_b[1], 1, 5, 1081.68697, @@ -401,11 +439,15 @@ void test_all() { test_one( "star_ring_ring", example_star, example_ring, - 5, 22, 1.1901714, 5, 27, 1.6701714); + 5, 22, 1.1901714, + 5, 27, 1.6701714, + sym_settings); test_one( "ring_star_ring", example_ring, example_star, - 5, 27, 1.6701714, 5, 22, 1.1901714); + 5, 27, 1.6701714, + 5, 22, 1.1901714, + sym_settings); static std::string const clip = "POLYGON((2.5 0.5,5.5 2.5))"; @@ -423,13 +465,19 @@ void test_all() typedef bg::model::polygon polygon_ccw; test_one( "star_ring_ccw", example_star, example_ring, - 5, 22, 1.1901714, 5, 27, 1.6701714); + 5, 22, 1.1901714, + 5, 27, 1.6701714, + sym_settings); test_one( "star_ring_ccw1", example_star, example_ring, - 5, 22, 1.1901714, 5, 27, 1.6701714); + 5, 22, 1.1901714, + 5, 27, 1.6701714, + sym_settings); test_one( "star_ring_ccw2", example_star, example_ring, - 5, 22, 1.1901714, 5, 27, 1.6701714); + 5, 22, 1.1901714, + 5, 27, 1.6701714, + sym_settings); } // Multi/box (should be moved to multi) @@ -457,54 +505,65 @@ void test_all() 5, 27, 1.6701714); ***/ -#ifdef BOOST_GEOMETRY_TEST_INCLUDE_FAILING_TESTS + // Should have 2 outputs + int const correction_for_invalidity = 1; // should be 0 test_one("mysql_21977775", mysql_21977775[0], mysql_21977775[1], - 2, -1, 160.856568913, 2, -1, 92.3565689126); + 2 - correction_for_invalidity, -1, 160.856568913, + 2, -1, 92.3565689126, + ignore_validity); // also mysql_23023665 test_one("mysql_21965285", mysql_21965285[0], mysql_21965285[1], - 1, 2, -1, 92.0, + 1, 2 - correction_for_invalidity, -1, 92.0, 1, 1, -1, 14.0, - 1, 2, -1, 92.0 + 14.0); + 1, 2, -1, 92.0 + 14.0, + ignore_validity); test_one("mysql_23023665_1", mysql_23023665_1[0], mysql_23023665_1[1], - 1, 2, -1, 92.0, - 1, 1, -1, 142.5); + 1, 2 - correction_for_invalidity, -1, 92.0, + 1, 1, -1, 142.5, + ignore_validity); test_one("mysql_23023665_2", mysql_23023665_2[0], mysql_23023665_2[1], - 1, 2, -1, 96.0, - 1, 1, -1, 16.0); + 1, 2 - correction_for_invalidity, -1, 96.0, + 1, 1, -1, 16.0, + ignore_validity); test_one("mysql_23023665_3", mysql_23023665_3[0], mysql_23023665_3[1], - 1, 2, -1, 225.0, - 1, 1, -1, 66.0); + 1, 2 - correction_for_invalidity, -1, 225.0, + 1, 1, -1, 66.0, + ignore_validity); - test_one("mysql_23023665_4", - mysql_23023665_4[0], mysql_23023665_4[1], - 1, 1, -1, 1.5, - 1, 2, -1, 219.0, - 1, 2, -1, 1.5 + 219.0); +// Case mysql_23023665_4 is not yet included! +// test_one("mysql_23023665_4", +// mysql_23023665_4[0], mysql_23023665_4[1], +// 1, 1, -1, 1.5, +// 1, 2, -1, 219.0, +// 1, 2, -1, 1.5 + 219.0); test_one("mysql_23023665_5", mysql_23023665_5[0], mysql_23023665_5[1], - 2, 2, -1, 165.23735, - 2, 2, -1, 105.73735); -#endif + 2 - correction_for_invalidity, 2 - correction_for_invalidity, -1, 165.23735, + 2, 2, -1, 105.73735, + ignore_validity); test_one("mysql_23023665_6", mysql_23023665_6[0], mysql_23023665_6[1], 2, 2, -1, 105.68756, - 3, 3, -1, 10.18756); -#ifdef BOOST_GEOMETRY_TEST_INCLUDE_FAILING_TESTS + 3, 3, -1, 10.18756 +#if defined(BOOST_GEOMETRY_NO_ROBUSTNESS) + , ignore_validity +#endif + ); test_one("mysql_23023665_13", mysql_23023665_13[0], mysql_23023665_13[1], - 3, 3, -1, 99.74526, - 3, 3, -1, 37.74526); -#endif + 3 - correction_for_invalidity, 3 - correction_for_invalidity, -1, 99.74526, + 3, 3, -1, 37.74526, + ignore_validity); } @@ -514,30 +573,25 @@ void test_specific() { typedef bg::model::polygon polygon; - ut_settings settings; - settings.test_validity = true; - test_one("ggl_list_20120717_volker", ggl_list_20120717_volker[0], ggl_list_20120717_volker[1], 1, 11, 3371540, 1, 4, 385, - 1, 16, 3371540 + 385, - settings); + 1, 16, 3371540 + 385); test_one("ticket_10658", ticket_10658[0], ticket_10658[1], 1, 6, 1510434, - 0, 0, 0, - settings); + 0, 0, 0); test_one("ticket_11121", ticket_11121[0], ticket_11121[1], 2, 8, 489763.5, - 1, 4, 6731652.0, - settings); + 1, 4, 6731652.0); { ut_settings settings; + settings.test_validity = false; #ifdef BOOST_GEOMETRY_TEST_INCLUDE_FAILING_TESTS settings.test_validity = true; #endif @@ -547,7 +601,7 @@ void test_specific() ticket_11676[0], ticket_11676[1], 1, 18, 2537992.5, 2, 11, 294963.5, - 1, -1, 2537992.5 + 294963.5, + 2, -1, 2537992.5 + 294963.5, settings); } } diff --git a/test/algorithms/set_operations/difference/difference_multi.cpp b/test/algorithms/set_operations/difference/difference_multi.cpp index 3621f15d4..e84930ad8 100644 --- a/test/algorithms/set_operations/difference/difference_multi.cpp +++ b/test/algorithms/set_operations/difference/difference_multi.cpp @@ -10,19 +10,6 @@ #include #include -// If defined, tests are run without rescaling-to-integer or robustness policy -// This multi_difference currently contains no tests for double which then fail -// #define BOOST_GEOMETRY_NO_ROBUSTNESS - -//#define HAVE_TTMATH -//#define BOOST_GEOMETRY_DEBUG_ASSEMBLE -//#define BOOST_GEOMETRY_CHECK_WITH_SQLSERVER - -//#define BOOST_GEOMETRY_DEBUG_SEGMENT_IDENTIFIER -//#define BOOST_GEOMETRY_DEBUG_FOLLOW -//#define BOOST_GEOMETRY_DEBUG_TRAVERSE - - #include "test_difference.hpp" #include #include @@ -39,6 +26,14 @@ template void test_areal() { + ut_settings ignore_validity; + ignore_validity.test_validity = false; + + ut_settings sym_settings; +#if defined(BOOST_GEOMETRY_NO_ROBUSTNESS) + sym_settings.sym_difference = false; +#endif + test_one("simplex_multi", case_multi_simplex[0], case_multi_simplex[1], 5, 21, 5.58, 4, 17, 2.58); @@ -79,19 +74,33 @@ void test_areal() test_one("case_72_multi", case_72_multi[0], case_72_multi[1], - 3, 13, 1.65, 3, 17, 6.15); + 3, 13, 1.65, 3, 17, 6.15, ignore_validity); - // 77_b, fixed by sorting colocated ix/ix turns like ux/ux test_one("case_77_multi", case_77_multi[0], case_77_multi[1], 6, 31, 7.0, 5, 36, 13.0, - 4, 43, 7.0 + 13.0); + 5, 43, 7.0 + 13.0); test_one("case_78_multi", case_78_multi[0], case_78_multi[1], 1, 5, 1.0, 1, 5, 1.0); + { + ut_settings settings; + +#if !defined(BOOST_GEOMETRY_NO_ROBUSTNESS) + settings.sym_difference = false; +#endif + + test_one("case_108_multi", + case_108_multi[0], case_108_multi[1], + 7, 32, 5.5, + 4, 28, 9.75, + 7, 45, 15.25, + settings); + } + // Ticket on GGL list 2011/10/25 // to mix polygon/multipolygon in call to difference test_one("ggl_list_20111025_vd_pp", @@ -118,10 +127,16 @@ void test_areal() ggl_list_20120915_h2[0], ggl_list_20120915_h2[2], 2, 13, 17.0, 0, 0, 0.0); - test_one("ggl_list_20120221_volker", - ggl_list_20120221_volker[0], ggl_list_20120221_volker[1], - 2, 12, 7962.66, 1, 18, 2775258.93, - tolerance(0.001)); + { + ut_settings settings; + settings.percentage = 0.001; + settings.test_validity = false; + + test_one("ggl_list_20120221_volker", + ggl_list_20120221_volker[0], ggl_list_20120221_volker[1], + 2, 12, 7962.66, 1, 18, 2775258.93, + settings); + } #if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS) test_one("ticket_9081", @@ -129,31 +144,21 @@ void test_areal() 2, 28, 0.0907392476356186, 4, 25, 0.126018011439877, 4, 42, 0.0907392476356186 + 0.126018011439877, tolerance(0.001)); + + // POSTGIS areas: 3.75893745345145, 2.5810000723917e-15 + test_one("bug_21155501", + bug_21155501[0], bug_21155501[1], + 1, 9, 3.758937, + 0, 0, 0.0, + ignore_validity); #endif - { - // Bug 21155501 - - // POSTGIS areas: 3.75893745345145, 2.5810000723917e-15 - - ut_settings settings; -#ifdef BOOST_GEOMETRY_TEST_INCLUDE_FAILING_TESTS - settings.test_validity = true; -#endif - test_one("bug_21155501", - bug_21155501[0], bug_21155501[1], - 1, 9, 3.758937, - 0, 0, 0.0, - settings); - - } - // Areas and #clips correspond with POSTGIS (except sym case) test_one("case_101_multi", case_101_multi[0], case_101_multi[1], 5, 23, 4.75, 5, 40, 12.75, - 4, 48, 4.75 + 12.75); + 5, 48, 4.75 + 12.75); // Areas and #clips correspond with POSTGIS test_one("case_102_multi", @@ -162,33 +167,35 @@ void test_areal() 6, 25, 3.75, 6, 27, 0.75 + 3.75); - // Areas and #clips correspond with POSTGIS (except sym case) + // Areas and #clips correspond with POSTGIS test_one("case_107_multi", case_107_multi[0], case_107_multi[1], 2, 11, 2.25, 3, 14, 3.0, - 3, 21, 5.25); + 4, 21, 5.25); // Areas correspond with POSTGIS, // #clips in PostGIS is 11,11,5 but should most probably be be 12,12,6 test_one("case_recursive_boxes_1", case_recursive_boxes_1[0], case_recursive_boxes_1[1], - 10, 75, 26.0, - 11, 77, 24.0, - 3, 98, 50.0); + 11, 75, 26.0, + 12, 77, 24.0, + 5, 98, 50.0, + ignore_validity); // Areas and #clips correspond with POSTGIS test_one("case_recursive_boxes_2", case_recursive_boxes_2[0], case_recursive_boxes_2[1], 3, 15, 3.0, - 5, 33, 7.0); + 7, 33, 7.0, + 10, 48, 10.0); // Areas and #clips by POSTGIS (except sym case) test_one("case_recursive_boxes_3", case_recursive_boxes_3[0], case_recursive_boxes_3[1], 24, -1, 21.5, 25, -1, 22.5, - 18, -1, 44.0); + 37, -1, 44.0); // 4, input is not valid @@ -196,31 +203,33 @@ void test_areal() case_recursive_boxes_5[0], case_recursive_boxes_5[1], 15, -1, 22.0, // #clips should be 16 11, -1, 27.0, // #clips should be 12 - 7, -1, 49.0); + 8, -1, 49.0, + ignore_validity); test_one("case_recursive_boxes_6", case_recursive_boxes_6[0], case_recursive_boxes_6[1], 6, -1, 3.5, 3, -1, 1.5, - 7, -1, 5.0); + 8, -1, 5.0, + ignore_validity); test_one("case_recursive_boxes_7", case_recursive_boxes_7[0], case_recursive_boxes_7[1], 3, 15, 2.75, 4, 19, 2.75, - 2, 22, 5.5); + 3, 22, 5.5); test_one("case_recursive_boxes_8", case_recursive_boxes_8[0], case_recursive_boxes_8[1], 2, -1, 2.50, 4, -1, 5.75, - 3, -1, 8.25); + 4, -1, 8.25); test_one("case_recursive_boxes_9", case_recursive_boxes_9[0], case_recursive_boxes_9[1], 3, -1, 1.5, 4, -1, 2.5, - 4, -1, 4.0); + 6, -1, 4.0); test_one("case_recursive_boxes_10", case_recursive_boxes_10[0], case_recursive_boxes_10[1], @@ -232,13 +241,14 @@ void test_areal() case_recursive_boxes_11[0], case_recursive_boxes_11[1], 3, -1, 2.5, 3, -1, 4.5, - 2, -1, 7.0); + 3, -1, 7.0); test_one("mysql_21965285_b", mysql_21965285_b[0], mysql_21965285_b[1], 2, -1, 183.71376870369406, - 2, -1, 131.21376870369406); + 2, -1, 131.21376870369406, + sym_settings); } @@ -264,6 +274,7 @@ void test_specific() ut_settings settings; settings.sym_difference = false; + settings.test_validity = false; #ifdef BOOST_GEOMETRY_TEST_INCLUDE_FAILING_TESTS settings.test_validity = true; settings.sym_difference = true; diff --git a/test/algorithms/set_operations/difference/difference_multi_spike.cpp b/test/algorithms/set_operations/difference/difference_multi_spike.cpp index 7ec3d2ce0..932fb8739 100644 --- a/test/algorithms/set_operations/difference/difference_multi_spike.cpp +++ b/test/algorithms/set_operations/difference/difference_multi_spike.cpp @@ -18,6 +18,9 @@ template void test_spikes_in_ticket_8364() { + ut_settings ignore_validity; + ignore_validity.test_validity = false; + // See: https://svn.boost.org/trac/boost/ticket/8364 //_TPolygon polygon( "MULTIPOLYGON(((1031 1056,3232 1056,3232 2856,1031 2856)))" ); //polygon -= _TPolygon( "MULTIPOLYGON(((1032 1458,1032 1212,2136 2328,3234 2220,3234 2412,2136 2646)))" ); @@ -46,7 +49,8 @@ void test_spikes_in_ticket_8364() if_typed(7893.0, 7810.487954), // SQL Server: 7810.48711165739 if_typed(1, 5), -1, - if_typed(2783349.5, 2775256.487954 + 7810.487954)); + if_typed(2783349.5, 2775256.487954 + 7810.487954), + ignore_validity); test_one("ticket_8364_step4", "MULTIPOLYGON(((2567 2688,2136 2790,2052 2712,1032 2130,1032 1764,1032 1458,1032 1212,2136 2328,3232 2220,3232 1056,1031 1056,1031 2856,3232 2856,3232 2580,2567 2688)))", @@ -59,7 +63,8 @@ void test_spikes_in_ticket_8364() if_typed(161133.5, 161054.559567), // SQL Server: 161054.560110092 if_typed(1, 2), if_typed(25, 31), - if_typed(2776875.5, 2616029.559567 + 161054.559567)); + if_typed(2776875.5, 2616029.559567 + 161054.559567), + ignore_validity); } template diff --git a/test/algorithms/set_operations/difference/test_difference.hpp b/test/algorithms/set_operations/difference/test_difference.hpp index 0059bcdd4..947d09131 100644 --- a/test/algorithms/set_operations/difference/test_difference.hpp +++ b/test/algorithms/set_operations/difference/test_difference.hpp @@ -62,14 +62,13 @@ struct ut_settings bool sym_difference; bool remove_spikes; - // TODO: set by default to true when all tests pass bool test_validity; ut_settings() : percentage(0.0001) , sym_difference(true) , remove_spikes(false) - , test_validity(false) + , test_validity(true) {} }; diff --git a/test/algorithms/set_operations/intersection/intersection.cpp b/test/algorithms/set_operations/intersection/intersection.cpp index ee1e16894..504bc3233 100644 --- a/test/algorithms/set_operations/intersection/intersection.cpp +++ b/test/algorithms/set_operations/intersection/intersection.cpp @@ -21,10 +21,6 @@ #include #include -// If defined, tests are run without rescaling-to-integer or robustness policy -// Test which would fail then are disabled automatically -// #define BOOST_GEOMETRY_NO_ROBUSTNESS - #include #include @@ -54,6 +50,10 @@ void test_areal() bool const ccw = bg::point_order::value == bg::counterclockwise; bool const open = bg::closure::value == bg::open; + ut_settings ignore_validity; + ignore_validity.test_validity = false; + + test_one("simplex_with_empty_1", simplex_normal[0], polygon_empty, 0, 0, 0.0); @@ -167,17 +167,24 @@ void test_areal() pie_2_3_23_0[0], pie_2_3_23_0[1], 1, 4, 163292.679042133, ut_settings(0.1)); +#if defined(BOOST_GEOMETRY_NO_ROBUSTNESS) + test_one("isovist", + isovist1[0], isovist1[1], + 1, 19, 88.4178, + ignore_validity); +#else + // SQL Server gives: 88.1920416352664 + // PostGIS gives: 88.19203677911 test_one("isovist", isovist1[0], isovist1[1], 1, 19, 88.19203, ut_settings(if_typed_tt(0.01, 0.1))); - - // SQL Server gives: 88.1920416352664 - // PostGIS gives: 88.19203677911 +#endif test_one("geos_1", geos_1[0], geos_1[1], - 1, -1, 3461.0214843, ut_settings(0.005)); // MSVC 14 reports 3461.025390625 + 1, -1, 3461.0214843, // MSVC 14 reports 3461.025390625 + ut_settings(0.005, false)); // Expectations: // In most cases: 0 (no intersection) @@ -250,23 +257,17 @@ void test_areal() #if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS) test_one("buffer_rt_f", buffer_rt_f[0], buffer_rt_f[1], 1, 4, 0.00029437899183903937, ut_settings(0.01)); -#endif test_one("buffer_rt_g", buffer_rt_g[0], buffer_rt_g[1], 1, 0, 2.914213562373); +#endif -#if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS) test_one("ticket_8254", ticket_8254[0], ticket_8254[1], 1, 4, 3.635930e-08, ut_settings(0.01)); -#endif - test_one("ticket_6958", ticket_6958[0], ticket_6958[1], 1, 4, 4.34355e-05, ut_settings(0.01)); - -#if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS) test_one("ticket_8652", ticket_8652[0], ticket_8652[1], 1, 4, 0.0003); -#endif test_one("ticket_8310a", ticket_8310a[0], ticket_8310a[1], 1, 5, 0.3843747); @@ -311,16 +312,11 @@ void test_areal() ticket_11576[0], ticket_11576[1], 1, 0, 5.585617332907136e-07); -#if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS) test_one("ticket_9563", ticket_9563[0], ticket_9563[1], 1, 8, 129.90381); -#endif -#if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS) test_one("buffer_mp1", buffer_mp1[0], buffer_mp1[1], 1, 31, 2.271707796); -#endif - test_one("buffer_mp2", buffer_mp2[0], buffer_mp2[1], 1, 29, 0.457126); @@ -349,27 +345,26 @@ void test_areal() mysql_21965285_b_inv[1], 2, -1, 183.71376870369406); -#ifdef BOOST_GEOMETRY_TEST_INCLUDE_FAILING_TESTS test_one("mysql_23023665_6", mysql_23023665_6[0], mysql_23023665_6[1], - 2, -1, 11.812440191387557); + 1, -1, 11.812440191387557, + ignore_validity); test_one("mysql_23023665_10", mysql_23023665_10[0], mysql_23023665_10[1], - 1, 1, -1, 54.701340543162523); + 1, 0, -1, 54.701340543162523, + ignore_validity); test_one("mysql_23023665_11", mysql_23023665_11[0], mysql_23023665_11[1], - 1, 1, -1, 35.933385462482065); -#endif + 1, 0, -1, 35.933385462482065, + ignore_validity); - return; - - test_one( - "polygon_pseudo_line", - "Polygon((0 0,0 4,4 4,4 0,0 0))", - "Polygon((2 -2,2 -1,2 6,2 -2))", - 5, 22, 1.1901714); +// test_one( +// "polygon_pseudo_line", +// "Polygon((0 0,0 4,4 4,4 0,0 0))", +// "Polygon((2 -2,2 -1,2 6,2 -2))", +// 5, 22, 1.1901714); } template @@ -622,6 +617,9 @@ void test_all() typedef bg::model::polygon polygon_ccw_open; boost::ignore_unused(); + ut_settings ignore_validity; + ignore_validity.test_validity = false; + std::string clip = "box(2 2,8 8)"; test_areal_linear(); @@ -674,8 +672,7 @@ void test_all() test_one("llbo", "LINESTRING(9 9,10 10)", clip, 0, 0, 0.0); // Touching with point (-> output linestring with ONE point) - //std::cout << "Note: the output line is degenerate! Might be removed!" << std::endl; - test_one("llb_touch", "LINESTRING(8 8,10 10)", clip, 1, 1, 0.0); + test_one("llb_touch", "LINESTRING(8 8,10 10)", clip, 1, 1, 0.0, ignore_validity); // Along border test_one("llb_along", "LINESTRING(2 2,2 8)", clip, 1, 2, 6.0); diff --git a/test/algorithms/set_operations/intersection/intersection_multi.cpp b/test/algorithms/set_operations/intersection/intersection_multi.cpp index 379ede648..2e46408ca 100644 --- a/test/algorithms/set_operations/intersection/intersection_multi.cpp +++ b/test/algorithms/set_operations/intersection/intersection_multi.cpp @@ -14,12 +14,6 @@ #include #include -// If defined, tests are run without rescaling-to-integer or robustness policy -// This multi_intersection currently contains no tests for double then failing -// #define BOOST_GEOMETRY_NO_ROBUSTNESS - -// #define BOOST_GEOMETRY_DEBUG_ASSEMBLE - #include "test_intersection.hpp" #include #include @@ -37,6 +31,9 @@ template void test_areal() { + ut_settings ignore_validity; + ignore_validity.test_validity = false; + test_one("simplex_multi", case_multi_simplex[0], case_multi_simplex[1], 2, 12, 6.42); @@ -105,13 +102,15 @@ void test_areal() 3, 14, 2.85); test_one("case_72_multi_inv_b", case_72_multi[1], case_72_multi[2], - 3, 16, 6.15); + 3, 16, 6.15, + ignore_validity); test_one("case_77_multi", case_77_multi[0], case_77_multi[1], 5, 33, 9.0); test_one("case_78_multi", case_78_multi[0], case_78_multi[1], - 1, 0, 22.0); // In "get_turns" using partitioning, #points went from 17 to 16 + 1, 16, 22.0, + ignore_validity); test_one("case_101_multi", case_101_multi[0], case_101_multi[1], 4, 22, 4.75); @@ -120,26 +119,38 @@ void test_areal() 3, 26, 19.75); test_one("case_102_multi_inv_b", case_102_multi[1], case_102_multi[2], - 6, 25, 3.75); + 3, 25, 3.75, + ignore_validity); test_one("case_107_multi", case_107_multi[0], case_107_multi[1], 2, 10, 1.5); test_one("case_107_multi_inv_b", case_107_multi[1], case_107_multi[2], 3, 13, 3.0); + +#ifdef BOOST_GEOMETRY_TEST_INCLUDE_FAILING_TESTS + // One intersection is missing (by rescaling) + test_one("case_108_multi", + case_108_multi[0], case_108_multi[1], + 5, 33, 7.5, + ignore_validity); +#endif test_one("case_recursive_boxes_1", case_recursive_boxes_1[0], case_recursive_boxes_1[1], - 10, 97, 47.0); + 8, 97, 47.0, + ignore_validity); test_one("case_recursive_boxes_2", case_recursive_boxes_2[0], case_recursive_boxes_2[1], - 1, 47, 90.0); // Area from SQL Server + 1, 50, 90.0, // Area from SQL Server + ignore_validity); test_one("case_recursive_boxes_3", case_recursive_boxes_3[0], case_recursive_boxes_3[1], 19, 87, 12.5); // Area from SQL Server test_one("case_recursive_boxes_4", case_recursive_boxes_4[0], case_recursive_boxes_4[1], - 13, 157, 67.0); // Area from SQL Server + 8, 174, 67.0, // Area from SQL Server + ignore_validity); // Fixed by replacing handle_tangencies in less_by_segment_ratio sort order test_one("case_recursive_boxes_6", @@ -180,7 +191,7 @@ void test_areal() 9, 43, 10.0); test_one("case_recursive_boxes_17", case_recursive_boxes_17[0], case_recursive_boxes_17[1], - 6, -1, 7.75); + 7, -1, 7.75); test_one("case_recursive_boxes_18", case_recursive_boxes_18[0], case_recursive_boxes_18[1], 0, 0, 0.0); @@ -231,10 +242,12 @@ void test_areal() 3, 0, 2.0); test_one("case_recursive_boxes_34", case_recursive_boxes_34[0], case_recursive_boxes_34[1], - 2, 0, 17.25); + 2, 0, 17.25, + ignore_validity); test_one("case_recursive_boxes_35", case_recursive_boxes_35[0], case_recursive_boxes_35[1], - 2, 0, 20.0); + 1, 0, 20.0, + ignore_validity); test_one("case_recursive_boxes_36", case_recursive_boxes_36[0], case_recursive_boxes_36[1], 1, 0, 0.5); @@ -253,19 +266,26 @@ void test_areal() ticket_9081[0], ticket_9081[1], 2, 10, 0.0019812556); + // qcc-arm reports 1.7791215549400884e-14 test_one("ticket_11018", ticket_11018[0], ticket_11018[1], - 1, 4, 1.7791170511070893e-14); + 1, 4, +#ifdef BOOST_GEOMETRY_NO_ROBUSTNESS + 9.896437631745599e-09 +#else + 1.7791170511070893e-14, ut_settings(0.001) +#endif + + ); test_one("mysql_23023665_7", mysql_23023665_7[0], mysql_23023665_7[1], 2, 11, 9.80505786783); -#ifdef BOOST_GEOMETRY_TEST_INCLUDE_FAILING_TESTS test_one("mysql_23023665_12", mysql_23023665_12[0], mysql_23023665_12[1], - 2, -1, 11.812440191387557); -#endif + 1, -1, 11.812440191387557, + ignore_validity); } template diff --git a/test/algorithms/set_operations/intersection/test_intersection.hpp b/test/algorithms/set_operations/intersection/test_intersection.hpp index bdd0459a4..adface270 100644 --- a/test/algorithms/set_operations/intersection/test_intersection.hpp +++ b/test/algorithms/set_operations/intersection/test_intersection.hpp @@ -48,9 +48,9 @@ struct ut_settings bool test_validity; bool debug; - explicit ut_settings(double p = 0.0001) + explicit ut_settings(double p = 0.0001, bool tv = true) : percentage(p) - , test_validity(false) + , test_validity(tv) , debug(false) {} diff --git a/test/algorithms/set_operations/union/test_union.hpp b/test/algorithms/set_operations/union/test_union.hpp index 90050a8be..810c7c353 100644 --- a/test/algorithms/set_operations/union/test_union.hpp +++ b/test/algorithms/set_operations/union/test_union.hpp @@ -50,11 +50,25 @@ struct ut_settings ut_settings() : percentage(0.001) - , test_validity(false) + , test_validity(true) {} }; +#if defined(BOOST_GEOMETRY_TEST_CHECK_VALID_INPUT) +template +inline void check_input_validity(std::string const& caseid, int case_index, + Geometry const& geometry) +{ + std::string message; + if (!bg::is_valid(geometry, message)) + { + std::cout << caseid << " Input [" + << case_index << "] not valid" << std::endl + << " (" << message << ")" << std::endl; + } +} +#endif template void test_union(std::string const& caseid, G1 const& g1, G2 const& g2, @@ -74,6 +88,11 @@ void test_union(std::string const& caseid, G1 const& g1, G2 const& g2, std::cout << "*** UNION " << caseid << std::endl; #endif +#if defined(BOOST_GEOMETRY_TEST_CHECK_VALID_INPUT) + check_input_validity(caseid, 0, g1); + check_input_validity(caseid, 1, g2); +#endif + bg::union_(g1, g2, clip); typename bg::default_area_result::type area = 0; diff --git a/test/algorithms/set_operations/union/union.cpp b/test/algorithms/set_operations/union/union.cpp index 0c5a8e8bd..f2b7cf0ee 100644 --- a/test/algorithms/set_operations/union/union.cpp +++ b/test/algorithms/set_operations/union/union.cpp @@ -19,10 +19,6 @@ #include #include -// If defined, tests are run without rescaling-to-integer or robustness policy -// Test which would fail then are disabled automatically -// #define BOOST_GEOMETRY_NO_ROBUSTNESS - #include "test_union.hpp" #include @@ -36,6 +32,9 @@ void test_areal() { typedef typename bg::coordinate_type::type ct; + ut_settings ignore_validity; + ignore_validity.test_validity = false; + test_one("simplex_normal", simplex_normal[0], simplex_normal[1], 1, 0, 13, 11.526367); @@ -186,9 +185,8 @@ void test_areal() test_one("59_iet", case_59[0], case_59[2], 1, 1, 14, 17.20833); - // #holes should be 2 test_one("80", - case_80[0], case_80[1], 2, 0, 18, 129.0); + case_80[0], case_80[1], 2, 2, 18, 129.0); test_one("81", case_81[0], case_81[1], 1, 2, 15, 163.5); @@ -230,6 +228,9 @@ void test_areal() test_one("99", case_99[0], case_99[1], 1, 0, 5, 1600.0); + test_one("100", + case_100[0], case_100[1], 1, 1, 13, 19.125); + /* test_one(102, simplex_normal[0], simplex_reversed[1], @@ -293,6 +294,9 @@ void test_areal() { ut_settings settings; settings.percentage = 0.1; +#if defined(BOOST_GEOMETRY_NO_ROBUSTNESS) + settings.test_validity = false; +#endif test_one("isovist", isovist1[0], isovist1[1], @@ -333,23 +337,21 @@ void test_areal() ticket_9081_15[0], ticket_9081_15[1], 1, 0, 10, 0.0403425433); -#if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS) test_one("ticket_9563", ticket_9563[0], ticket_9563[1], 1, 0, 13, 150.0); -#endif test_one("ticket_9756", ticket_9756[0], ticket_9756[1], 1, 0, 10, 1289.08374); #if defined(BOOST_GEOMETRY_NO_ROBUSTNESS) - // The number of clips is reversed here test_one("ticket_10108_a", ticket_10108_a[0], ticket_10108_a[1], 1, 0, 8, 0.0435229); - test_one("ticket_10108_b", ticket_10108_b[0], ticket_10108_b[1], - 2, 0, 10, 2424.3449); #else test_one("ticket_10108_a", ticket_10108_a[0], ticket_10108_a[1], 2, 0, 8, 0.0435229); +#endif + +#if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS) test_one("ticket_10108_b", ticket_10108_b[0], ticket_10108_b[1], 1, 0, 10, 2424.3449); #endif @@ -361,7 +363,8 @@ void test_areal() 1, 1, 10, 7.5); test_one("geos_1", geos_1[0], geos_1[1], - 1, 0, -1, 3461.3203125); + 1, 0, -1, 3461.3203125, + ignore_validity); test_one("geos_2", geos_2[0], geos_2[1], 1, 0, -1, 350.55102539); test_one("geos_3", geos_3[0], geos_3[1], @@ -375,9 +378,11 @@ void test_areal() // Robustness issues, followed out buffer-robustness-tests, test them also reverse #if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS) test_one("buffer_rt_f", buffer_rt_f[0], buffer_rt_f[1], - 1, 0, if_typed(18, 23), 4.60853); + 1, 0, if_typed(18, 23), 4.60853, + ignore_validity); test_one("buffer_rt_f_rev", buffer_rt_f[1], buffer_rt_f[0], - 1, 0, if_typed(18, 23), 4.60853); + 1, 0, if_typed(18, 23), 4.60853, + ignore_validity); #endif test_one("buffer_rt_g", buffer_rt_g[0], buffer_rt_g[1], @@ -437,18 +442,19 @@ void test_areal() 1, 0, if_typed_tt(93, 91), 22.815); test_one("buffer_mp2", buffer_mp2[0], buffer_mp2[1], +#if defined(BOOST_GEOMETRY_NO_ROBUSTNESS) + 1, 0, 217, 36.752837, ignore_validity); +#else 1, 1, 217, 36.752837); +#endif -#ifdef BOOST_GEOMETRY_TEST_INCLUDE_FAILING_TESTS test_one("mysql_21964079_1", mysql_21964079_1[0], mysql_21964079_1[1], 2, 1, -1, 234.5); test_one("mysql_21964079_2", mysql_21964079_2[0], mysql_21964079_2[1], 2, 1, -1, 112.0); - test_one("mysql_21964049", - mysql_21964049[0], mysql_21964049[1], - 1, 1, -1, 220.5); + test_one("mysql_23023665_1", mysql_23023665_1[0], mysql_23023665_1[1], 2, 1, -1, 92.0 + 142.5); @@ -458,10 +464,9 @@ void test_areal() test_one("mysql_23023665_3", mysql_23023665_3[0], mysql_23023665_3[1], 2, 1, -1, 225.0 + 66.0); - test_one("mysql_23023665_4", - mysql_23023665_4[0], mysql_23023665_4[1], - 1, 1, -1, 1.5 + 219.0); -#endif + test_one("mysql_21964049", + mysql_21964049[0], mysql_21964049[1], + 1, 1, -1, 220.5); } template diff --git a/test/algorithms/set_operations/union/union_multi.cpp b/test/algorithms/set_operations/union/union_multi.cpp index 19dd3d76c..419ed8377 100644 --- a/test/algorithms/set_operations/union/union_multi.cpp +++ b/test/algorithms/set_operations/union/union_multi.cpp @@ -14,10 +14,6 @@ #include #include -// If defined, tests are run without rescaling-to-integer or robustness policy -// This multi_union currently contains no tests for double which then fail -// #define BOOST_GEOMETRY_NO_ROBUSTNESS - #include "test_union.hpp" #include #include @@ -36,6 +32,12 @@ template void test_areal() { + ut_settings ignore_validity; + ignore_validity.test_validity = false; + + // Some output is only invalid for CCW + bool const ccw = bg::point_order::value == bg::counterclockwise; + test_one("simplex_multi", case_multi_simplex[0], case_multi_simplex[1], 1, 0, 20, 14.58); @@ -67,10 +69,9 @@ void test_areal() case_58_multi[0], case_58_multi[3], 2, 0, 21, 19.83333333); - // (#holes should be 3) test_one("case_58_multi_b", case_58_multi[1], case_58_multi[2], - 1, 1, 17, 48.333333); + 1, 3, 17, 48.333333); // Constructed cases for multi/touch/equal/etc test_one("case_61_multi", @@ -99,13 +100,13 @@ void test_areal() 5, 0, 25, 5.0); test_one("case_76_multi", case_76_multi[0], case_76_multi[1], - 4, 0, 31, 8.0); + 5, 0, 31, 8.0); test_one("case_89_multi", case_89_multi[0], case_89_multi[1], 1, 0, 13, 6); test_one("case_101_multi", case_101_multi[0], case_101_multi[1], - 1, 0, 32, 22.25); + 1, 3, 35, 22.25); test_one("case_103_multi", case_103_multi[0], case_103_multi[1], 1, 0, 7, 25); @@ -123,17 +124,58 @@ void test_areal() 1, 0, 15, 6.75); test_one("case_108_multi", case_108_multi[0], case_108_multi[1], - 1, 0, 20, 22.75); + 1, 1, 20, 22.75); // Should have 2 holes + // To make it valid, it is necessary to calculate and use self turns + // for each input. Now the two holes are connected because a turn is missing + // there. test_one("case_109_multi", case_109_multi[0], case_109_multi[1], - 1, 1, 14, 1400); + 1, 1, 14, 1400, + ignore_validity); // Should have 9 holes, they are all separate and touching test_one("case_110_multi", case_110_multi[0], case_110_multi[1], - 1, 1, 37, 1250); + 1, 9, 45, 1250); + + test_one("case_111_multi", + case_111_multi[0], case_111_multi[1], + 2, 0, 10, 16); + test_one("case_112_multi", + case_112_multi[0], case_112_multi[1], + 2, 0, 16, 48); + test_one("case_113_multi", + case_113_multi[0], case_113_multi[1], + 2, 0, 13, 162.5); + test_one("case_114_multi", + case_114_multi[0], case_114_multi[1], + 1, 1, 13, 187.5); + test_one("case_115_multi", + case_115_multi[0], case_115_multi[1], + 1, 1, 18, 26.7036); + test_one("case_116_multi", + case_116_multi[0], case_116_multi[1], + 1, 2, 27, 51); + test_one("case_117_multi", + case_117_multi[0], case_117_multi[1], + 2, 0, 18, 22); + test_one("case_118_multi", + case_118_multi[0], case_118_multi[1], + 3, 0, 27, 46); + test_one("case_119_multi", + case_119_multi[0], case_119_multi[1], + 2, 0, 26, 44); + test_one("case_120_multi", + case_120_multi[0], case_120_multi[1], + 1, 1, 20, 35); + test_one("case_121_multi", + case_121_multi[0], case_121_multi[1], + 1, 1, 21, 25.5); + test_one("case_122_multi", + case_122_multi[0], case_122_multi[1], + 1, 1, 28, 29.5); test_one("case_recursive_boxes_1", case_recursive_boxes_1[0], case_recursive_boxes_1[1], @@ -143,19 +185,24 @@ void test_areal() 1, 0, 14, 100.0); // Area from SQL Server test_one("case_recursive_boxes_3", case_recursive_boxes_3[0], case_recursive_boxes_3[1], - 14, 0, 159, 56.5); // Area from SQL Server + 17, 6, 166, 56.5); // Area from SQL Server test_one("case_recursive_boxes_4", case_recursive_boxes_4[0], case_recursive_boxes_4[1], - 1, 1, 42, 96.75); + 1, 2, 42, 96.75); + + // Should have 10 holes. + // For making #5 valid, it is necessary to calculate and use self turns + // for each input. Now one hole is connected to another hole because a turn + // missing there. test_one("case_recursive_boxes_5", case_recursive_boxes_5[0], case_recursive_boxes_5[1], - 3, 2, 110, 70.0); + 3, 9, 115, 70.0, + ignore_validity); - // TODO: fix self touching interior ring (should get 3 interior rings) test_one("case_recursive_boxes_6", case_recursive_boxes_6[0], case_recursive_boxes_6[1], - 1, 2, 25, 24.0); + 1, 3, 25, 24.0); test_one("case_recursive_boxes_7", case_recursive_boxes_7[0], case_recursive_boxes_7[1], @@ -177,22 +224,49 @@ void test_areal() 1, 0, -1, 8.0); test_one("case_recursive_boxes_12", case_recursive_boxes_12[0], case_recursive_boxes_12[1], - 3, 0, -1, 6.0); + 6, 0, -1, 6.0); test_one("case_recursive_boxes_13", case_recursive_boxes_13[0], case_recursive_boxes_13[1], 3, 0, -1, 10.25); + test_one("case_recursive_boxes_14", case_recursive_boxes_14[0], case_recursive_boxes_14[1], - 4, 0, -1, 4.5); + 5, 0, -1, 4.5); + + // Invalid versions of 12/13/14 + test_one("case_recursive_boxes_12_invalid", + case_recursive_boxes_12_invalid[0], case_recursive_boxes_12_invalid[1], + 6, 0, -1, 6.0); + + if (! ccw) + { + // Handling this invalid input delivers invalid results for CCW + test_one("case_recursive_boxes_13_invalid", + case_recursive_boxes_13_invalid[0], case_recursive_boxes_13_invalid[1], + 3, 0, -1, 10.25); + } + else + { + test_one("case_recursive_boxes_13_invalid", + case_recursive_boxes_13_invalid[0], case_recursive_boxes_13_invalid[1], + 2, 0, -1, 10.25, + ignore_validity); + } + + test_one("case_recursive_boxes_14_invalid", + case_recursive_boxes_14_invalid[0], case_recursive_boxes_14_invalid[1], + 5, 0, -1, 4.5); + + test_one("case_recursive_boxes_15", case_recursive_boxes_15[0], case_recursive_boxes_15[1], - 2, 0, -1, 6.0); + 3, 0, -1, 6.0); test_one("case_recursive_boxes_16", case_recursive_boxes_16[0], case_recursive_boxes_16[1], - 1, 1, -1, 22.0); + 1, 4, -1, 22.0); test_one("case_recursive_boxes_17", case_recursive_boxes_17[0], case_recursive_boxes_17[1], - 3, 1, -1, 21.0); + 5, 2, -1, 21.0); test_one("case_recursive_boxes_18", case_recursive_boxes_18[0], case_recursive_boxes_18[1], 3, 0, -1, 2.5); @@ -228,10 +302,10 @@ void test_areal() 2, 0, -1, 6.5); test_one("case_recursive_boxes_29", case_recursive_boxes_29[0], case_recursive_boxes_29[1], - 1, 0, -1, 15.5); + 2, 2, -1, 15.5); test_one("case_recursive_boxes_30", case_recursive_boxes_30[0], case_recursive_boxes_30[1], - 1, 2, -1, 17.5); + 1, 3, -1, 17.5); test_one("case_recursive_boxes_31", case_recursive_boxes_31[0], case_recursive_boxes_31[1], 3, 0, -1, 5.0); @@ -240,7 +314,7 @@ void test_areal() 2, 0, -1, 5.75); test_one("case_recursive_boxes_33", case_recursive_boxes_33[0], case_recursive_boxes_33[1], - 1, 0, -1, 11.0); + 1, 1, -1, 11.0); test_one("case_recursive_boxes_34", case_recursive_boxes_34[0], case_recursive_boxes_34[1], 1, 0, -1, 25.0); @@ -249,10 +323,13 @@ void test_areal() 1, 1, -1, 24.5); test_one("case_recursive_boxes_36", case_recursive_boxes_36[0], case_recursive_boxes_36[1], - 2, 0, -1, 3.0); + 3, 0, -1, 3.0); test_one("case_recursive_boxes_37", case_recursive_boxes_37[0], case_recursive_boxes_37[1], 2, 1, -1, 7.75); + test_one("case_recursive_boxes_38", + case_recursive_boxes_38[0], case_recursive_boxes_38[1], + 2, 1, -1, 14.0); test_one("ggl_list_20120915_h2_a", ggl_list_20120915_h2[0], ggl_list_20120915_h2[1], @@ -281,17 +358,32 @@ void test_areal() ticket_11984[0], ticket_11984[1], 1, 2, 134, 60071.08077); -#ifdef BOOST_GEOMETRY_ENABLE_FAILING_TESTS + test_one("ticket_12118", + ticket_12118[0], ticket_12118[1], + 1, 1, 27, 2221.38713); + +#if defined(BOOST_GEOMETRY_ENABLE_FAILING_TESTS) || defined(BOOST_GEOMETRY_NO_ROBUSTNESS) + // No output if rescaling is done + test_one("ticket_12125", + ticket_12125[0], ticket_12125[1], + 1, 0, -1, 575.831180350007); +#endif + + // TODO: solve validity, it needs calculating self-turns + // Should have 1 hole test_one("mysql_23023665_7", mysql_23023665_7[0], mysql_23023665_7[1], - 1, 1, -1, 99.19494); + 1, 0, -1, 99.19494, + ignore_validity); + // Should have 2 holes test_one("mysql_23023665_8", mysql_23023665_8[0], mysql_23023665_8[1], - 1, 2, -1, 1400.0); + 1, 1, -1, 1400.0, + ignore_validity); + test_one("mysql_23023665_9", mysql_23023665_9[0], mysql_23023665_9[1], 1, 9, -1, 1250.0); -#endif } // Test cases (generic) diff --git a/test/algorithms/test_simplify.hpp b/test/algorithms/test_simplify.hpp index a7b9ce6af..d80da5653 100644 --- a/test/algorithms/test_simplify.hpp +++ b/test/algorithms/test_simplify.hpp @@ -128,7 +128,7 @@ void test_geometry(std::string const& wkt, check_geometry(v, expected, distance); - BOOST_CONCEPT_ASSERT( (bg::concept::SimplifyStrategy) ); + BOOST_CONCEPT_ASSERT( (bg::concepts::SimplifyStrategy) ); check_geometry(geometry, expected, distance, dp()); check_geometry(v, expected, distance, dp()); @@ -155,7 +155,7 @@ void test_geometry(std::string const& wkt, less_comparator > douglass_peucker_with_less; - BOOST_CONCEPT_ASSERT( (bg::concept::SimplifyStrategy) ); + BOOST_CONCEPT_ASSERT( (bg::concepts::SimplifyStrategy) ); check_geometry(geometry, expected, distance, douglass_peucker_with_less(less)); check_geometry(v, expected, distance, douglass_peucker_with_less(less)); @@ -172,7 +172,7 @@ void test_geometry(std::string const& wkt, bg::read_wkt(wkt, geometry); boost::variant v(geometry); - BOOST_CONCEPT_ASSERT( (bg::concept::SimplifyStrategy::type>) ); check_geometry(geometry, expected, distance, strategy); diff --git a/test/concepts/function_asserting_a_point.hpp b/test/concepts/function_asserting_a_point.hpp index 8ff84d449..802d19852 100644 --- a/test/concepts/function_asserting_a_point.hpp +++ b/test/concepts/function_asserting_a_point.hpp @@ -20,8 +20,8 @@ namespace test template void function_asserting_a_point(P& p1, const CP& p2) { - BOOST_CONCEPT_ASSERT((bg::concept::Point

)); - BOOST_CONCEPT_ASSERT((bg::concept::ConstPoint

)); + BOOST_CONCEPT_ASSERT((bg::concepts::Point

)); + BOOST_CONCEPT_ASSERT((bg::concepts::ConstPoint

)); bg::get<0>(p1) = bg::get<0>(p2); } diff --git a/test/concepts/function_requiring_a_point.hpp b/test/concepts/function_requiring_a_point.hpp index 77e7bdd12..d8628e940 100644 --- a/test/concepts/function_requiring_a_point.hpp +++ b/test/concepts/function_requiring_a_point.hpp @@ -19,8 +19,8 @@ namespace test template inline void function_requiring_a_point(P& p1, const C& p2) { - BOOST_CONCEPT_ASSERT((bg::concept::Point

)); - BOOST_CONCEPT_ASSERT((bg::concept::ConstPoint)); + BOOST_CONCEPT_ASSERT((bg::concepts::Point

)); + BOOST_CONCEPT_ASSERT((bg::concepts::ConstPoint)); bg::set<0>(p1, bg::get<0>(p2)); } diff --git a/test/concepts/linestring_concept.cpp b/test/concepts/linestring_concept.cpp index 9b202f1e2..06f3dfcf9 100644 --- a/test/concepts/linestring_concept.cpp +++ b/test/concepts/linestring_concept.cpp @@ -31,8 +31,8 @@ template void test_linestring() { - BOOST_CONCEPT_ASSERT( (bg::concept::Linestring) ); - BOOST_CONCEPT_ASSERT( (bg::concept::ConstLinestring) ); + BOOST_CONCEPT_ASSERT( (bg::concepts::Linestring) ); + BOOST_CONCEPT_ASSERT( (bg::concepts::ConstLinestring) ); Geometry geometry; typedef typename bg::point_type::type P; diff --git a/test/concepts/point_concept_checker.cpp b/test/concepts/point_concept_checker.cpp index 0750972f4..ea51a2e96 100644 --- a/test/concepts/point_concept_checker.cpp +++ b/test/concepts/point_concept_checker.cpp @@ -71,6 +71,6 @@ template <> struct access int main() { - boost::geometry::concept::check(); - boost::geometry::concept::check(); + boost::geometry::concepts::check(); + boost::geometry::concepts::check(); } diff --git a/test/concepts/point_geographic_custom_with_wrong_units.cpp b/test/concepts/point_geographic_custom_with_wrong_units.cpp index f2985b841..5ac6e03e7 100644 --- a/test/concepts/point_geographic_custom_with_wrong_units.cpp +++ b/test/concepts/point_geographic_custom_with_wrong_units.cpp @@ -20,7 +20,7 @@ struct dummy {}; int main() { - bg::concept::check + bg::concepts::check < ro_lon_lat_point > const >(); diff --git a/test/concepts/point_geographic_with_wrong_units.cpp b/test/concepts/point_geographic_with_wrong_units.cpp index ab5fdc704..9ea423181 100644 --- a/test/concepts/point_geographic_with_wrong_units.cpp +++ b/test/concepts/point_geographic_with_wrong_units.cpp @@ -20,7 +20,7 @@ namespace bg = boost::geometry; int main() { - bg::concept::check + bg::concepts::check < bg::model::point > >(); diff --git a/test/concepts/point_spherical_custom_with_wrong_units.cpp b/test/concepts/point_spherical_custom_with_wrong_units.cpp index f5c5bb573..4a44f3236 100644 --- a/test/concepts/point_spherical_custom_with_wrong_units.cpp +++ b/test/concepts/point_spherical_custom_with_wrong_units.cpp @@ -19,7 +19,7 @@ namespace bg = boost::geometry; int main() { - bg::concept::check + bg::concepts::check < rw_lon_lat_point > >(); diff --git a/test/concepts/point_well_formed_non_cartesian.cpp b/test/concepts/point_well_formed_non_cartesian.cpp index e6817adb3..adbc14ce0 100644 --- a/test/concepts/point_well_formed_non_cartesian.cpp +++ b/test/concepts/point_well_formed_non_cartesian.cpp @@ -30,19 +30,19 @@ inline void test_coordinate_system() typedef rw_lon_lat_point rw_int_point; typedef ro_lon_lat_point ro_int_point; - bg::concept::check(); - bg::concept::check(); + bg::concepts::check(); + bg::concepts::check(); - bg::concept::check(); - bg::concept::check(); + bg::concepts::check(); + bg::concepts::check(); - bg::concept::check(); - bg::concept::check(); - bg::concept::check(); + bg::concepts::check(); + bg::concepts::check(); + bg::concepts::check(); - bg::concept::check(); - bg::concept::check(); - bg::concept::check(); + bg::concepts::check(); + bg::concepts::check(); + bg::concepts::check(); } diff --git a/test/formulas/Jamfile.v2 b/test/formulas/Jamfile.v2 new file mode 100644 index 000000000..18587bc24 --- /dev/null +++ b/test/formulas/Jamfile.v2 @@ -0,0 +1,16 @@ +# Boost.Geometry +# +# Copyright (c) 2016, Oracle and/or its affiliates. +# +# 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) + +test-suite boost-geometry-formulas + : + [ run inverse.cpp : : : : formulas_inverse ] + [ run direct.cpp : : : : formulas_direct ] + [ run intersection.cpp : : : : formulas_intersection ] + ; diff --git a/test/formulas/direct.cpp b/test/formulas/direct.cpp new file mode 100644 index 000000000..1f0254925 --- /dev/null +++ b/test/formulas/direct.cpp @@ -0,0 +1,66 @@ +// Boost.Geometry +// Unit Test + +// Copyright (c) 2016 Oracle and/or its affiliates. + +// 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) + +#include "test_formula.hpp" +#include "direct_cases.hpp" + +#include +#include + +template +void check_direct(Result const& result, expected_result const& expected, expected_result const& reference, double reference_error) +{ + check_one(result.lon2, expected.lon2, reference.lon2, reference_error); + check_one(result.lat2, expected.lat2, reference.lat2, reference_error); + check_one(result.reverse_azimuth, expected.reverse_azimuth, reference.reverse_azimuth, reference_error, true); + check_one(result.reduced_length, expected.reduced_length, reference.reduced_length, reference_error); + check_one(result.geodesic_scale, expected.geodesic_scale, reference.geodesic_scale, reference_error); +} + +void test_all(expected_results const& results) +{ + double const d2r = bg::math::d2r(); + double const r2d = bg::math::r2d(); + + double lon1r = results.p1.lon * d2r; + double lat1r = results.p1.lat * d2r; + double distance = results.distance; + double azi12r = results.azimuth12 * d2r; + + // WGS84 + bg::srs::spheroid spheroid(6378137.0, 6356752.3142451793); + + bg::formula::result_direct result; + + typedef bg::formula::vincenty_direct vi_t; + result = vi_t::apply(lon1r, lat1r, distance, azi12r, spheroid); + result.lon2 *= r2d; + result.lat2 *= r2d; + result.reverse_azimuth *= r2d; + check_direct(result, results.vincenty, results.karney, 0.00000001); + + typedef bg::formula::thomas_direct th_t; + result = th_t::apply(lon1r, lat1r, distance, azi12r, spheroid); + result.lon2 *= r2d; + result.lat2 *= r2d; + result.reverse_azimuth *= r2d; + check_direct(result, results.thomas, results.karney, 0.0000001); +} + +int test_main(int, char*[]) +{ + for (size_t i = 0; i < expected_size; ++i) + { + test_all(expected[i]); + } + + return 0; +} diff --git a/test/formulas/direct_cases.hpp b/test/formulas/direct_cases.hpp new file mode 100644 index 000000000..d62e65d28 --- /dev/null +++ b/test/formulas/direct_cases.hpp @@ -0,0 +1,452 @@ +// Boost.Geometry +// Unit Test + +// Copyright (c) 2016 Oracle and/or its affiliates. + +// 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_TEST_DIRECT_CASES_HPP +#define BOOST_GEOMETRY_TEST_DIRECT_CASES_HPP + +struct coordinates +{ + double lon; + double lat; +}; + +struct expected_result +{ + double lon2; + double lat2; + double reverse_azimuth; + double reduced_length; + double geodesic_scale; +}; + +struct expected_results +{ + coordinates p1; + double distance; + double azimuth12; + expected_result karney; + expected_result vincenty; + expected_result thomas; +}; + +expected_results expected[] = +{ + { + { 0, 0 }, 250000, 0, + { 0.00000000000000000000, 2.26091191238511868278, 0.00000000000000000000, 249935.55905595037620514631, 0.99922674639115516282 }, + { 0.00000000000000000000, 2.26091191236402178077, 0.00000000000000000000, 249935.55905951990280300379, 0.99922674639116959572 }, + { 0.00000000000000000000, 2.26091189386641744363, 0.00000000000000000000, 249935.55701571033569052815, 0.99922674640382092015 } + },{ + { 0, 0 }, 250000, 45, + { 1.58842150169031337548, 1.59850419267109766785, 45.02216068943542381930, 249935.55885449703782796860, 0.99922674504834751996 }, + { 1.58842150168977558344, 1.59850419267017707092, 45.02216068943540250302, 249935.55886070139240473509, 0.99922674504834840814 }, + { 1.58842149958854261804, 1.59850419056543535667, 45.02216068937701010100, 249935.55853169565671123564, 0.99922674505038500126 } + },{ + { 0, 0 }, 250000, 90, + { 2.24578821029880382198, 0.00000000000000000000, 90.00000000000000000000, 249935.55865304186590947211, 0.99922674370552955203 }, + { 2.24578821029880382198, 0.00000000000000013841, 90.00000000000000000000, 249935.55865304186590947211, 0.99922674370552955203 }, + { 2.24578821029880382198, 0.00000000000000013841, 90.00000000000000000000, 249935.55865304186590947211, 0.99922674370552955203 } + },{ + { 0, 0 }, 250000, 135, + { 1.58842150169031337548, -1.59850419267109766785, 134.97783931056457618070, 249935.55885449703782796860, 0.99922674504834751996 }, + { 1.58842150168977580549, -1.59850419267017707092, 134.97783931056460460240, 249935.55886070139240473509, 0.99922674504834840814 }, + { 1.58842149958854261804, -1.59850419056543602281, 134.97783931062298279357, 249935.55853169583133421838, 0.99922674505038500126 } + },{ + { 0, 0 }, 250000, 180, + { 0.00000000000000000000, -2.26091191238511868278, -180.00000000000000000000, 249935.55905595037620514631, 0.99922674639115516282 }, + { 0.00000000000000027517, -2.26091191236402178077, 180.00000000000000000000, 249935.55905951990280300379, 0.99922674639116959572 }, + { 0.00000000000000000000, -2.26091189386641744363, 180.00000000000000000000, 249935.55701571033569052815, 0.99922674640382092015 } + },{ + { 0, 0 }, 250000, -45, + { -1.58842150169031337548, 1.59850419267109766785, -45.02216068943542381930, 249935.55885449703782796860, 0.99922674504834751996 }, + { -1.58842150168977558344, 1.59850419267017707092, -45.02216068943540250302, 249935.55886070139240473509, 0.99922674504834840814 }, + { -1.58842149958854261804, 1.59850419056543535667, -45.02216068937701010100, 249935.55853169565671123564, 0.99922674505038500126 } + },{ + { 0, 0 }, 250000, -90, + { -2.24578821029880382198, 0.00000000000000000000, -90.00000000000000000000, 249935.55865304186590947211, 0.99922674370552955203 }, + { -2.24578821029880382198, 0.00000000000000013841, -90.00000000000000000000, 249935.55865304186590947211, 0.99922674370552955203 }, + { -2.24578821029880382198, 0.00000000000000013841, -90.00000000000000000000, 249935.55865304186590947211, 0.99922674370552955203 } + },{ + { 0, 0 }, 250000, -135, + { -1.58842150169031337548, -1.59850419267109766785, -134.97783931056457618070, 249935.55885449703782796860, 0.99922674504834751996 }, + { -1.58842150168977580549, -1.59850419267017707092, -134.97783931056460460240, 249935.55886070139240473509, 0.99922674504834840814 }, + { -1.58842149958854261804, -1.59850419056543602281, -134.97783931062298279357, 249935.55853169583133421838, 0.99922674505038500126 } + },{ + { 0, 0 }, 250000, -180, + { 0.00000000000000000000, -2.26091191238511868278, -180.00000000000000000000, 249935.55905595037620514631, 0.99922674639115516282 }, + { -0.00000000000000027517, -2.26091191236402178077, -180.00000000000000000000, 249935.55905951990280300379, 0.99922674639116959572 }, + { 0.00000000000000000000, -2.26091189386641744363, -180.00000000000000000000, 249935.55701571033569052815, 0.99922674640382092015 } + },{ + { -1, 0 }, 250000, 0, + { -1.00000000000000000000, 2.26091191238511868278, 0.00000000000000000000, 249935.55905595037620514631, 0.99922674639115516282 }, + { -1.00000000000000000000, 2.26091191236402178077, 0.00000000000000000000, 249935.55905951990280300379, 0.99922674639116959572 }, + { -1.00000000000000000000, 2.26091189386641744363, 0.00000000000000000000, 249935.55701571033569052815, 0.99922674640382092015 } + },{ + { -1, 0 }, 250000, 45, + { 0.58842150169031337548, 1.59850419267109766785, 45.02216068943542381930, 249935.55885449703782796860, 0.99922674504834751996 }, + { 0.58842150168977558344, 1.59850419267017707092, 45.02216068943540250302, 249935.55886070139240473509, 0.99922674504834840814 }, + { 0.58842149958854272906, 1.59850419056543535667, 45.02216068937701010100, 249935.55853169565671123564, 0.99922674505038500126 } + },{ + { -1, 0 }, 250000, 90, + { 1.24578821029880382198, 0.00000000000000000000, 90.00000000000000000000, 249935.55865304186590947211, 0.99922674370552955203 }, + { 1.24578821029880382198, 0.00000000000000013841, 90.00000000000000000000, 249935.55865304186590947211, 0.99922674370552955203 }, + { 1.24578821029880382198, 0.00000000000000013841, 90.00000000000000000000, 249935.55865304186590947211, 0.99922674370552955203 } + },{ + { -1, 0 }, 250000, 135, + { 0.58842150169031337548, -1.59850419267109766785, 134.97783931056457618070, 249935.55885449703782796860, 0.99922674504834751996 }, + { 0.58842150168977569447, -1.59850419267017707092, 134.97783931056460460240, 249935.55886070139240473509, 0.99922674504834840814 }, + { 0.58842149958854272906, -1.59850419056543602281, 134.97783931062298279357, 249935.55853169583133421838, 0.99922674505038500126 } + },{ + { -1, 0 }, 250000, 180, + { -1.00000000000000000000, -2.26091191238511868278, -180.00000000000000000000, 249935.55905595037620514631, 0.99922674639115516282 }, + { -0.99999999999999977796, -2.26091191236402178077, 180.00000000000000000000, 249935.55905951990280300379, 0.99922674639116959572 }, + { -1.00000000000000000000, -2.26091189386641744363, 180.00000000000000000000, 249935.55701571033569052815, 0.99922674640382092015 } + },{ + { -1, 0 }, 250000, -45, + { -2.58842150169031359752, 1.59850419267109766785, -45.02216068943542381930, 249935.55885449703782796860, 0.99922674504834751996 }, + { -2.58842150168977536140, 1.59850419267017707092, -45.02216068943540250302, 249935.55886070139240473509, 0.99922674504834840814 }, + { -2.58842149958854284009, 1.59850419056543535667, -45.02216068937701010100, 249935.55853169565671123564, 0.99922674505038500126 } + },{ + { -1, 0 }, 250000, -90, + { -3.24578821029880382198, 0.00000000000000000000, -90.00000000000000000000, 249935.55865304186590947211, 0.99922674370552955203 }, + { -3.24578821029880382198, 0.00000000000000013841, -90.00000000000000000000, 249935.55865304192411713302, 0.99922674370552955203 }, + { -3.24578821029880382198, 0.00000000000000013841, -90.00000000000000000000, 249935.55865304192411713302, 0.99922674370552955203 } + },{ + { -1, 0 }, 250000, -135, + { -2.58842150169031359752, -1.59850419267109766785, -134.97783931056457618070, 249935.55885449703782796860, 0.99922674504834751996 }, + { -2.58842150168977580549, -1.59850419267017707092, -134.97783931056460460240, 249935.55886070139240473509, 0.99922674504834840814 }, + { -2.58842149958854284009, -1.59850419056543602281, -134.97783931062298279357, 249935.55853169583133421838, 0.99922674505038500126 } + },{ + { -1, 0 }, 250000, -180, + { -1.00000000000000000000, -2.26091191238511868278, -180.00000000000000000000, 249935.55905595037620514631, 0.99922674639115516282 }, + { -1.00000000000000022204, -2.26091191236402178077, -180.00000000000000000000, 249935.55905951990280300379, 0.99922674639116959572 }, + { -1.00000000000000000000, -2.26091189386641744363, -180.00000000000000000000, 249935.55701571033569052815, 0.99922674640382092015 } + },{ + { 1, 0 }, 250000, 0, + { 1.00000000000000000000, 2.26091191238511868278, 0.00000000000000000000, 249935.55905595037620514631, 0.99922674639115516282 }, + { 1.00000000000000000000, 2.26091191236402178077, 0.00000000000000000000, 249935.55905951990280300379, 0.99922674639116959572 }, + { 1.00000000000000000000, 2.26091189386641744363, 0.00000000000000000000, 249935.55701571033569052815, 0.99922674640382092015 } + },{ + { 1, 0 }, 250000, 45, + { 2.58842150169031359752, 1.59850419267109766785, 45.02216068943542381930, 249935.55885449703782796860, 0.99922674504834751996 }, + { 2.58842150168977536140, 1.59850419267017707092, 45.02216068943540250302, 249935.55886070139240473509, 0.99922674504834840814 }, + { 2.58842149958854284009, 1.59850419056543535667, 45.02216068937701010100, 249935.55853169565671123564, 0.99922674505038500126 } + },{ + { 1, 0 }, 250000, 90, + { 3.24578821029880382198, 0.00000000000000000000, 90.00000000000000000000, 249935.55865304186590947211, 0.99922674370552955203 }, + { 3.24578821029880382198, 0.00000000000000013841, 90.00000000000000000000, 249935.55865304192411713302, 0.99922674370552955203 }, + { 3.24578821029880382198, 0.00000000000000013841, 90.00000000000000000000, 249935.55865304192411713302, 0.99922674370552955203 } + },{ + { 1, 0 }, 250000, 135, + { 2.58842150169031359752, -1.59850419267109766785, 134.97783931056457618070, 249935.55885449703782796860, 0.99922674504834751996 }, + { 2.58842150168977580549, -1.59850419267017707092, 134.97783931056460460240, 249935.55886070139240473509, 0.99922674504834840814 }, + { 2.58842149958854284009, -1.59850419056543602281, 134.97783931062298279357, 249935.55853169583133421838, 0.99922674505038500126 } + },{ + { 1, 0 }, 250000, 180, + { 1.00000000000000000000, -2.26091191238511868278, -180.00000000000000000000, 249935.55905595037620514631, 0.99922674639115516282 }, + { 1.00000000000000022204, -2.26091191236402178077, 180.00000000000000000000, 249935.55905951990280300379, 0.99922674639116959572 }, + { 1.00000000000000000000, -2.26091189386641744363, 180.00000000000000000000, 249935.55701571033569052815, 0.99922674640382092015 } + },{ + { 1, 0 }, 250000, -45, + { -0.58842150169031337548, 1.59850419267109766785, -45.02216068943542381930, 249935.55885449703782796860, 0.99922674504834751996 }, + { -0.58842150168977558344, 1.59850419267017707092, -45.02216068943540250302, 249935.55886070139240473509, 0.99922674504834840814 }, + { -0.58842149958854272906, 1.59850419056543535667, -45.02216068937701010100, 249935.55853169565671123564, 0.99922674505038500126 } + },{ + { 1, 0 }, 250000, -90, + { -1.24578821029880382198, 0.00000000000000000000, -90.00000000000000000000, 249935.55865304186590947211, 0.99922674370552955203 }, + { -1.24578821029880382198, 0.00000000000000013841, -90.00000000000000000000, 249935.55865304186590947211, 0.99922674370552955203 }, + { -1.24578821029880382198, 0.00000000000000013841, -90.00000000000000000000, 249935.55865304186590947211, 0.99922674370552955203 } + },{ + { 1, 0 }, 250000, -135, + { -0.58842150169031337548, -1.59850419267109766785, -134.97783931056457618070, 249935.55885449703782796860, 0.99922674504834751996 }, + { -0.58842150168977569447, -1.59850419267017707092, -134.97783931056460460240, 249935.55886070139240473509, 0.99922674504834840814 }, + { -0.58842149958854272906, -1.59850419056543602281, -134.97783931062298279357, 249935.55853169583133421838, 0.99922674505038500126 } + },{ + { 1, 0 }, 250000, -180, + { 1.00000000000000000000, -2.26091191238511868278, -180.00000000000000000000, 249935.55905595037620514631, 0.99922674639115516282 }, + { 0.99999999999999977796, -2.26091191236402178077, -180.00000000000000000000, 249935.55905951990280300379, 0.99922674639116959572 }, + { 1.00000000000000000000, -2.26091189386641744363, -180.00000000000000000000, 249935.55701571033569052815, 0.99922674640382092015 } + },{ + { 0, -1 }, 250000, 0, + { 0.00000000000000000000, 1.26092062918498104551, 0.00000000000000000000, 249935.55872467698645778000, 0.99922674479230122468 }, + { 0.00000000000000000000, 1.26092062916373448545, 0.00000000000000000000, 249935.55872643628390505910, 0.99922674479075712650 }, + { 0.00000000000000000000, 1.26092061053506587776, 0.00000000000000000000, 249935.55666816755547188222, 0.99922674480349771287 } + },{ + { 0, -1 }, 250000, 45, + { 1.58789352027561725400, 0.59889382252477618707, 44.99444098733987829064, 249935.55869720416376367211, 0.99922674484119022864 }, + { 1.58789352027508279264, 0.59889382252384637528, 44.99444098733987118521, 249935.55869934445945546031, 0.99922674484277662632 }, + { 1.58789351816042789700, 0.59889382039736038799, 44.99444098731778751699, 249935.55836710281437262893, 0.99922674484483320345 } + },{ + { 0, -1 }, 250000, 90, + { 2.24612766651409989649, -0.99922666842209439952, 89.96080977150054991398, 249935.55891569345840252936, 0.99922674685767398639 }, + { 2.24612766651347328661, -0.99922666842209439952, 89.96080977150054991398, 249935.55891513984533958137, 0.99922674686822765544 }, + { 2.24612766651409945240, -0.99922666842208529570, 89.96080977150032254031, 249935.55891660030465573072, 0.99922674686821844059 } + },{ + { 0, -1 }, 250000, 135, + { 1.58943065821228057821, -2.59810442478829362045, 134.95009296248679220298, 249935.55953696221695281565, 0.99922675155892082266 }, + { 1.58943065821171258811, -2.59810442478739078709, 134.95009296248684904640, 249935.55953448649961501360, 0.99922675162094776180 }, + { 1.58943065613921019619, -2.59810442273856878614, 134.95009296257936171060, 249935.55921406237757764757, 0.99922675162293117523 } + },{ + { 0, -1 }, 250000, 180, + { 0.00000000000000000000, -3.26088938011404927408, -180.00000000000000000000, 249935.55991226507467217743, 0.99922675429255258805 }, + { 0.00000000000000027540, -3.26088938009322193423, 180.00000000000000000000, 249935.55988221566076390445, 0.99922675435769237051 }, + { 0.00000000000000000000, -3.26088936183515265554, 180.00000000000000000000, 249935.55786483851261436939, 0.99922675437017982603 } + },{ + { 0, -1 }, 250000, -45, + { -1.58789352027561725400, 0.59889382252477618707, -44.99444098733987829064, 249935.55869720416376367211, 0.99922674484119022864 }, + { -1.58789352027508279264, 0.59889382252384637528, -44.99444098733987118521, 249935.55869934445945546031, 0.99922674484277662632 }, + { -1.58789351816042789700, 0.59889382039736038799, -44.99444098731778751699, 249935.55836710281437262893, 0.99922674484483320345 } + },{ + { 0, -1 }, 250000, -90, + { -2.24612766651409989649, -0.99922666842209439952, -89.96080977150054991398, 249935.55891569345840252936, 0.99922674685767398639 }, + { -2.24612766651347328661, -0.99922666842209439952, -89.96080977150054991398, 249935.55891513984533958137, 0.99922674686822765544 }, + { -2.24612766651409945240, -0.99922666842208529570, -89.96080977150032254031, 249935.55891660030465573072, 0.99922674686821844059 } + },{ + { 0, -1 }, 250000, -135, + { -1.58943065821228057821, -2.59810442478829362045, -134.95009296248679220298, 249935.55953696221695281565, 0.99922675155892082266 }, + { -1.58943065821171258811, -2.59810442478739078709, -134.95009296248684904640, 249935.55953448649961501360, 0.99922675162094776180 }, + { -1.58943065613921019619, -2.59810442273856878614, -134.95009296257936171060, 249935.55921406237757764757, 0.99922675162293117523 } + },{ + { 0, -1 }, 250000, -180, + { 0.00000000000000000000, -3.26088938011404927408, -180.00000000000000000000, 249935.55991226507467217743, 0.99922675429255258805 }, + { -0.00000000000000027540, -3.26088938009322193423, -180.00000000000000000000, 249935.55988221566076390445, 0.99922675435769237051 }, + { 0.00000000000000000000, -3.26088936183515265554, -180.00000000000000000000, 249935.55786483851261436939, 0.99922675437017982603 } + },{ + { 0, 1 }, 250000, 0, + { 0.00000000000000000000, 3.26088938011404927408, 0.00000000000000000000, 249935.55991226507467217743, 0.99922675429255258805 }, + { 0.00000000000000000000, 3.26088938009322193423, 0.00000000000000000000, 249935.55988221566076390445, 0.99922675435769237051 }, + { 0.00000000000000000000, 3.26088936183515265554, 0.00000000000000000000, 249935.55786483851261436939, 0.99922675437017982603 } + },{ + { 0, 1 }, 250000, 45, + { 1.58943065821228057821, 2.59810442478829362045, 45.04990703751319358616, 249935.55953696221695281565, 0.99922675155892082266 }, + { 1.58943065821171236607, 2.59810442478739123118, 45.04990703751315805903, 249935.55953448649961501360, 0.99922675162094765078 }, + { 1.58943065613921019619, 2.59810442273856923023, 45.04990703742064539483, 249935.55921406255220063031, 0.99922675162293117523 } + },{ + { 0, 1 }, 250000, 90, + { 2.24612766651409989649, 0.99922666842209439952, 90.03919022849945008602, 249935.55891569345840252936, 0.99922674685767398639 }, + { 2.24612766651347328661, 0.99922666842209484361, 90.03919022849945008602, 249935.55891513981623575091, 0.99922674686822765544 }, + { 2.24612766651409945240, 0.99922666842208562876, 90.03919022849967745969, 249935.55891660030465573072, 0.99922674686821866263 } + },{ + { 0, 1 }, 250000, 135, + { 1.58789352027561725400, -0.59889382252477618707, 135.00555901266011460393, 249935.55869720416376367211, 0.99922674484119022864 }, + { 1.58789352027508301468, -0.59889382252384604222, 135.00555901266014302564, 249935.55869934437214396894, 0.99922674484277662632 }, + { 1.58789351816042789700, -0.59889382039736038799, 135.00555901268222669387, 249935.55836710284347645938, 0.99922674484483320345 } + },{ + { 0, 1 }, 250000, 180, + { 0.00000000000000000000, -1.26092062918498104551, -180.00000000000000000000, 249935.55872467698645778000, 0.99922674479230122468 }, + { 0.00000000000000027502, -1.26092062916373448545, 180.00000000000000000000, 249935.55872643628390505910, 0.99922674479075712650 }, + { 0.00000000000000000000, -1.26092061053506587776, 180.00000000000000000000, 249935.55666816755547188222, 0.99922674480349771287 } + },{ + { 0, 1 }, 250000, -45, + { -1.58943065821228057821, 2.59810442478829362045, -45.04990703751319358616, 249935.55953696221695281565, 0.99922675155892082266 }, + { -1.58943065821171236607, 2.59810442478739123118, -45.04990703751315805903, 249935.55953448649961501360, 0.99922675162094765078 }, + { -1.58943065613921019619, 2.59810442273856923023, -45.04990703742064539483, 249935.55921406255220063031, 0.99922675162293117523 } + },{ + { 0, 1 }, 250000, -90, + { -2.24612766651409989649, 0.99922666842209439952, -90.03919022849945008602, 249935.55891569345840252936, 0.99922674685767398639 }, + { -2.24612766651347328661, 0.99922666842209484361, -90.03919022849945008602, 249935.55891513981623575091, 0.99922674686822765544 }, + { -2.24612766651409945240, 0.99922666842208562876, -90.03919022849967745969, 249935.55891660030465573072, 0.99922674686821866263 } + },{ + { 0, 1 }, 250000, -135, + { -1.58789352027561725400, -0.59889382252477618707, -135.00555901266011460393, 249935.55869720416376367211, 0.99922674484119022864 }, + { -1.58789352027508301468, -0.59889382252384604222, -135.00555901266014302564, 249935.55869934437214396894, 0.99922674484277662632 }, + { -1.58789351816042789700, -0.59889382039736038799, -135.00555901268222669387, 249935.55836710284347645938, 0.99922674484483320345 } + },{ + { 0, 1 }, 250000, -180, + { 0.00000000000000000000, -1.26092062918498104551, -180.00000000000000000000, 249935.55872467698645778000, 0.99922674479230122468 }, + { -0.00000000000000027502, -1.26092062916373448545, -180.00000000000000000000, 249935.55872643628390505910, 0.99922674479075712650 }, + { 0.00000000000000000000, -1.26092061053506587776, -180.00000000000000000000, 249935.55666816755547188222, 0.99922674480349771287 } + },{ + { -1, -1 }, 250000, 0, + { -1.00000000000000000000, 1.26092062918498104551, 0.00000000000000000000, 249935.55872467698645778000, 0.99922674479230122468 }, + { -1.00000000000000000000, 1.26092062916373448545, 0.00000000000000000000, 249935.55872643628390505910, 0.99922674479075712650 }, + { -1.00000000000000000000, 1.26092061053506587776, 0.00000000000000000000, 249935.55666816755547188222, 0.99922674480349771287 } + },{ + { -1, -1 }, 250000, 45, + { 0.58789352027561725400, 0.59889382252477618707, 44.99444098733987829064, 249935.55869720416376367211, 0.99922674484119022864 }, + { 0.58789352027508279264, 0.59889382252384637528, 44.99444098733987118521, 249935.55869934445945546031, 0.99922674484277662632 }, + { 0.58789351816042800802, 0.59889382039736038799, 44.99444098731778751699, 249935.55836710281437262893, 0.99922674484483320345 } + },{ + { -1, -1 }, 250000, 90, + { 1.24612766651409989649, -0.99922666842209439952, 89.96080977150054991398, 249935.55891569345840252936, 0.99922674685767398639 }, + { 1.24612766651347328661, -0.99922666842209439952, 89.96080977150054991398, 249935.55891513984533958137, 0.99922674686822765544 }, + { 1.24612766651409945240, -0.99922666842208529570, 89.96080977150032254031, 249935.55891660030465573072, 0.99922674686821844059 } + },{ + { -1, -1 }, 250000, 135, + { 0.58943065821228057821, -2.59810442478829362045, 134.95009296248679220298, 249935.55953696221695281565, 0.99922675155892082266 }, + { 0.58943065821171258811, -2.59810442478739078709, 134.95009296248684904640, 249935.55953448649961501360, 0.99922675162094776180 }, + { 0.58943065613921030721, -2.59810442273856878614, 134.95009296257936171060, 249935.55921406237757764757, 0.99922675162293117523 } + },{ + { -1, -1 }, 250000, 180, + { -1.00000000000000000000, -3.26088938011404927408, -180.00000000000000000000, 249935.55991226507467217743, 0.99922675429255258805 }, + { -0.99999999999999977796, -3.26088938009322193423, 180.00000000000000000000, 249935.55988221566076390445, 0.99922675435769237051 }, + { -1.00000000000000000000, -3.26088936183515265554, 180.00000000000000000000, 249935.55786483851261436939, 0.99922675437017982603 } + },{ + { -1, -1 }, 250000, -45, + { -2.58789352027561747605, 0.59889382252477618707, -44.99444098733987829064, 249935.55869720416376367211, 0.99922674484119022864 }, + { -2.58789352027508279264, 0.59889382252384637528, -44.99444098733987118521, 249935.55869934445945546031, 0.99922674484277662632 }, + { -2.58789351816042811905, 0.59889382039736038799, -44.99444098731778751699, 249935.55836710281437262893, 0.99922674484483320345 } + },{ + { -1, -1 }, 250000, -90, + { -3.24612766651409989649, -0.99922666842209439952, -89.96080977150054991398, 249935.55891569345840252936, 0.99922674685767398639 }, + { -3.24612766651347328661, -0.99922666842209439952, -89.96080977150054991398, 249935.55891513984533958137, 0.99922674686822765544 }, + { -3.24612766651409989649, -0.99922666842208529570, -89.96080977150032254031, 249935.55891660030465573072, 0.99922674686821844059 } + },{ + { -1, -1 }, 250000, -135, + { -2.58943065821228035617, -2.59810442478829362045, -134.95009296248679220298, 249935.55953696221695281565, 0.99922675155892082266 }, + { -2.58943065821171281016, -2.59810442478739078709, -134.95009296248684904640, 249935.55953448649961501360, 0.99922675162094776180 }, + { -2.58943065613921019619, -2.59810442273856878614, -134.95009296257936171060, 249935.55921406237757764757, 0.99922675162293117523 } + },{ + { -1, -1 }, 250000, -180, + { -1.00000000000000000000, -3.26088938011404927408, -180.00000000000000000000, 249935.55991226507467217743, 0.99922675429255258805 }, + { -1.00000000000000022204, -3.26088938009322193423, -180.00000000000000000000, 249935.55988221566076390445, 0.99922675435769237051 }, + { -1.00000000000000000000, -3.26088936183515265554, -180.00000000000000000000, 249935.55786483851261436939, 0.99922675437017982603 } + },{ + { -1, 1 }, 250000, 0, + { -1.00000000000000000000, 3.26088938011404927408, 0.00000000000000000000, 249935.55991226507467217743, 0.99922675429255258805 }, + { -1.00000000000000000000, 3.26088938009322193423, 0.00000000000000000000, 249935.55988221566076390445, 0.99922675435769237051 }, + { -1.00000000000000000000, 3.26088936183515265554, 0.00000000000000000000, 249935.55786483851261436939, 0.99922675437017982603 } + },{ + { -1, 1 }, 250000, 45, + { 0.58943065821228057821, 2.59810442478829362045, 45.04990703751319358616, 249935.55953696221695281565, 0.99922675155892082266 }, + { 0.58943065821171236607, 2.59810442478739123118, 45.04990703751315805903, 249935.55953448649961501360, 0.99922675162094765078 }, + { 0.58943065613921030721, 2.59810442273856923023, 45.04990703742064539483, 249935.55921406255220063031, 0.99922675162293117523 } + },{ + { -1, 1 }, 250000, 90, + { 1.24612766651409989649, 0.99922666842209439952, 90.03919022849945008602, 249935.55891569345840252936, 0.99922674685767398639 }, + { 1.24612766651347328661, 0.99922666842209484361, 90.03919022849945008602, 249935.55891513981623575091, 0.99922674686822765544 }, + { 1.24612766651409945240, 0.99922666842208562876, 90.03919022849967745969, 249935.55891660030465573072, 0.99922674686821866263 } + },{ + { -1, 1 }, 250000, 135, + { 0.58789352027561725400, -0.59889382252477618707, 135.00555901266011460393, 249935.55869720416376367211, 0.99922674484119022864 }, + { 0.58789352027508301468, -0.59889382252384604222, 135.00555901266014302564, 249935.55869934437214396894, 0.99922674484277662632 }, + { 0.58789351816042800802, -0.59889382039736038799, 135.00555901268222669387, 249935.55836710284347645938, 0.99922674484483320345 } + },{ + { -1, 1 }, 250000, 180, + { -1.00000000000000000000, -1.26092062918498104551, -180.00000000000000000000, 249935.55872467698645778000, 0.99922674479230122468 }, + { -0.99999999999999977796, -1.26092062916373448545, 180.00000000000000000000, 249935.55872643628390505910, 0.99922674479075712650 }, + { -1.00000000000000000000, -1.26092061053506587776, 180.00000000000000000000, 249935.55666816755547188222, 0.99922674480349771287 } + },{ + { -1, 1 }, 250000, -45, + { -2.58943065821228035617, 2.59810442478829362045, -45.04990703751319358616, 249935.55953696221695281565, 0.99922675155892082266 }, + { -2.58943065821171236607, 2.59810442478739123118, -45.04990703751315805903, 249935.55953448649961501360, 0.99922675162094765078 }, + { -2.58943065613921019619, 2.59810442273856923023, -45.04990703742064539483, 249935.55921406255220063031, 0.99922675162293117523 } + },{ + { -1, 1 }, 250000, -90, + { -3.24612766651409989649, 0.99922666842209439952, -90.03919022849945008602, 249935.55891569345840252936, 0.99922674685767398639 }, + { -3.24612766651347328661, 0.99922666842209484361, -90.03919022849945008602, 249935.55891513981623575091, 0.99922674686822765544 }, + { -3.24612766651409989649, 0.99922666842208562876, -90.03919022849967745969, 249935.55891660030465573072, 0.99922674686821866263 } + },{ + { -1, 1 }, 250000, -135, + { -2.58789352027561747605, -0.59889382252477618707, -135.00555901266011460393, 249935.55869720416376367211, 0.99922674484119022864 }, + { -2.58789352027508279264, -0.59889382252384604222, -135.00555901266014302564, 249935.55869934437214396894, 0.99922674484277662632 }, + { -2.58789351816042811905, -0.59889382039736038799, -135.00555901268222669387, 249935.55836710284347645938, 0.99922674484483320345 } + },{ + { -1, 1 }, 250000, -180, + { -1.00000000000000000000, -1.26092062918498104551, -180.00000000000000000000, 249935.55872467698645778000, 0.99922674479230122468 }, + { -1.00000000000000022204, -1.26092062916373448545, -180.00000000000000000000, 249935.55872643628390505910, 0.99922674479075712650 }, + { -1.00000000000000000000, -1.26092061053506587776, -180.00000000000000000000, 249935.55666816755547188222, 0.99922674480349771287 } + },{ + { 1, 1 }, 250000, 0, + { 1.00000000000000000000, 3.26088938011404927408, 0.00000000000000000000, 249935.55991226507467217743, 0.99922675429255258805 }, + { 1.00000000000000000000, 3.26088938009322193423, 0.00000000000000000000, 249935.55988221566076390445, 0.99922675435769237051 }, + { 1.00000000000000000000, 3.26088936183515265554, 0.00000000000000000000, 249935.55786483851261436939, 0.99922675437017982603 } + },{ + { 1, 1 }, 250000, 45, + { 2.58943065821228035617, 2.59810442478829362045, 45.04990703751319358616, 249935.55953696221695281565, 0.99922675155892082266 }, + { 2.58943065821171236607, 2.59810442478739123118, 45.04990703751315805903, 249935.55953448649961501360, 0.99922675162094765078 }, + { 2.58943065613921019619, 2.59810442273856923023, 45.04990703742064539483, 249935.55921406255220063031, 0.99922675162293117523 } + },{ + { 1, 1 }, 250000, 90, + { 3.24612766651409989649, 0.99922666842209439952, 90.03919022849945008602, 249935.55891569345840252936, 0.99922674685767398639 }, + { 3.24612766651347328661, 0.99922666842209484361, 90.03919022849945008602, 249935.55891513981623575091, 0.99922674686822765544 }, + { 3.24612766651409989649, 0.99922666842208562876, 90.03919022849967745969, 249935.55891660030465573072, 0.99922674686821866263 } + },{ + { 1, 1 }, 250000, 135, + { 2.58789352027561747605, -0.59889382252477618707, 135.00555901266011460393, 249935.55869720416376367211, 0.99922674484119022864 }, + { 2.58789352027508279264, -0.59889382252384604222, 135.00555901266014302564, 249935.55869934437214396894, 0.99922674484277662632 }, + { 2.58789351816042811905, -0.59889382039736038799, 135.00555901268222669387, 249935.55836710284347645938, 0.99922674484483320345 } + },{ + { 1, 1 }, 250000, 180, + { 1.00000000000000000000, -1.26092062918498104551, -180.00000000000000000000, 249935.55872467698645778000, 0.99922674479230122468 }, + { 1.00000000000000022204, -1.26092062916373448545, 180.00000000000000000000, 249935.55872643628390505910, 0.99922674479075712650 }, + { 1.00000000000000000000, -1.26092061053506587776, 180.00000000000000000000, 249935.55666816755547188222, 0.99922674480349771287 } + },{ + { 1, 1 }, 250000, -45, + { -0.58943065821228057821, 2.59810442478829362045, -45.04990703751319358616, 249935.55953696221695281565, 0.99922675155892082266 }, + { -0.58943065821171236607, 2.59810442478739123118, -45.04990703751315805903, 249935.55953448649961501360, 0.99922675162094765078 }, + { -0.58943065613921030721, 2.59810442273856923023, -45.04990703742064539483, 249935.55921406255220063031, 0.99922675162293117523 } + },{ + { 1, 1 }, 250000, -90, + { -1.24612766651409989649, 0.99922666842209439952, -90.03919022849945008602, 249935.55891569345840252936, 0.99922674685767398639 }, + { -1.24612766651347328661, 0.99922666842209484361, -90.03919022849945008602, 249935.55891513981623575091, 0.99922674686822765544 }, + { -1.24612766651409945240, 0.99922666842208562876, -90.03919022849967745969, 249935.55891660030465573072, 0.99922674686821866263 } + },{ + { 1, 1 }, 250000, -135, + { -0.58789352027561725400, -0.59889382252477618707, -135.00555901266011460393, 249935.55869720416376367211, 0.99922674484119022864 }, + { -0.58789352027508301468, -0.59889382252384604222, -135.00555901266014302564, 249935.55869934437214396894, 0.99922674484277662632 }, + { -0.58789351816042800802, -0.59889382039736038799, -135.00555901268222669387, 249935.55836710284347645938, 0.99922674484483320345 } + },{ + { 1, 1 }, 250000, -180, + { 1.00000000000000000000, -1.26092062918498104551, -180.00000000000000000000, 249935.55872467698645778000, 0.99922674479230122468 }, + { 0.99999999999999977796, -1.26092062916373448545, -180.00000000000000000000, 249935.55872643628390505910, 0.99922674479075712650 }, + { 1.00000000000000000000, -1.26092061053506587776, -180.00000000000000000000, 249935.55666816755547188222, 0.99922674480349771287 } + },{ + { 1, -1 }, 250000, 0, + { 1.00000000000000000000, 1.26092062918498104551, 0.00000000000000000000, 249935.55872467698645778000, 0.99922674479230122468 }, + { 1.00000000000000000000, 1.26092062916373448545, 0.00000000000000000000, 249935.55872643628390505910, 0.99922674479075712650 }, + { 1.00000000000000000000, 1.26092061053506587776, 0.00000000000000000000, 249935.55666816755547188222, 0.99922674480349771287 } + },{ + { 1, -1 }, 250000, 45, + { 2.58789352027561747605, 0.59889382252477618707, 44.99444098733987829064, 249935.55869720416376367211, 0.99922674484119022864 }, + { 2.58789352027508279264, 0.59889382252384637528, 44.99444098733987118521, 249935.55869934445945546031, 0.99922674484277662632 }, + { 2.58789351816042811905, 0.59889382039736038799, 44.99444098731778751699, 249935.55836710281437262893, 0.99922674484483320345 } + },{ + { 1, -1 }, 250000, 90, + { 3.24612766651409989649, -0.99922666842209439952, 89.96080977150054991398, 249935.55891569345840252936, 0.99922674685767398639 }, + { 3.24612766651347328661, -0.99922666842209439952, 89.96080977150054991398, 249935.55891513984533958137, 0.99922674686822765544 }, + { 3.24612766651409989649, -0.99922666842208529570, 89.96080977150032254031, 249935.55891660030465573072, 0.99922674686821844059 } + },{ + { 1, -1 }, 250000, 135, + { 2.58943065821228035617, -2.59810442478829362045, 134.95009296248679220298, 249935.55953696221695281565, 0.99922675155892082266 }, + { 2.58943065821171281016, -2.59810442478739078709, 134.95009296248684904640, 249935.55953448649961501360, 0.99922675162094776180 }, + { 2.58943065613921019619, -2.59810442273856878614, 134.95009296257936171060, 249935.55921406237757764757, 0.99922675162293117523 } + },{ + { 1, -1 }, 250000, 180, + { 1.00000000000000000000, -3.26088938011404927408, -180.00000000000000000000, 249935.55991226507467217743, 0.99922675429255258805 }, + { 1.00000000000000022204, -3.26088938009322193423, 180.00000000000000000000, 249935.55988221566076390445, 0.99922675435769237051 }, + { 1.00000000000000000000, -3.26088936183515265554, 180.00000000000000000000, 249935.55786483851261436939, 0.99922675437017982603 } + },{ + { 1, -1 }, 250000, -45, + { -0.58789352027561725400, 0.59889382252477618707, -44.99444098733987829064, 249935.55869720416376367211, 0.99922674484119022864 }, + { -0.58789352027508279264, 0.59889382252384637528, -44.99444098733987118521, 249935.55869934445945546031, 0.99922674484277662632 }, + { -0.58789351816042800802, 0.59889382039736038799, -44.99444098731778751699, 249935.55836710281437262893, 0.99922674484483320345 } + },{ + { 1, -1 }, 250000, -90, + { -1.24612766651409989649, -0.99922666842209439952, -89.96080977150054991398, 249935.55891569345840252936, 0.99922674685767398639 }, + { -1.24612766651347328661, -0.99922666842209439952, -89.96080977150054991398, 249935.55891513984533958137, 0.99922674686822765544 }, + { -1.24612766651409945240, -0.99922666842208529570, -89.96080977150032254031, 249935.55891660030465573072, 0.99922674686821844059 } + },{ + { 1, -1 }, 250000, -135, + { -0.58943065821228057821, -2.59810442478829362045, -134.95009296248679220298, 249935.55953696221695281565, 0.99922675155892082266 }, + { -0.58943065821171258811, -2.59810442478739078709, -134.95009296248684904640, 249935.55953448649961501360, 0.99922675162094776180 }, + { -0.58943065613921030721, -2.59810442273856878614, -134.95009296257936171060, 249935.55921406237757764757, 0.99922675162293117523 } + },{ + { 1, -1 }, 250000, -180, + { 1.00000000000000000000, -3.26088938011404927408, -180.00000000000000000000, 249935.55991226507467217743, 0.99922675429255258805 }, + { 0.99999999999999977796, -3.26088938009322193423, -180.00000000000000000000, 249935.55988221566076390445, 0.99922675435769237051 }, + { 1.00000000000000000000, -3.26088936183515265554, -180.00000000000000000000, 249935.55786483851261436939, 0.99922675437017982603 } + } +}; + +size_t const expected_size = sizeof(expected) / sizeof(expected_results); + +#endif // BOOST_GEOMETRY_TEST_DIRECT_CASES_HPP diff --git a/test/formulas/intersection.cpp b/test/formulas/intersection.cpp new file mode 100644 index 000000000..f0b1b49d7 --- /dev/null +++ b/test/formulas/intersection.cpp @@ -0,0 +1,87 @@ +// Boost.Geometry +// Unit Test + +// Copyright (c) 2016 Oracle and/or its affiliates. + +// 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) + +#include "test_formula.hpp" +#include "intersection_cases.hpp" + +#include +#include +#include +#include +#include +#include +#include + +void check_inverse(expected_result const& result, expected_result const& expected, expected_result const& reference, double reference_error) +{ + check_one(result.lon, expected.lon, reference.lon, reference_error); + check_one(result.lat, expected.lat, reference.lat, reference_error); +} + +void test_all(expected_results const& results) +{ + double const d2r = bg::math::d2r(); + double const r2d = bg::math::r2d(); + + double lona1r = results.p1.lon * d2r; + double lata1r = results.p1.lat * d2r; + double lona2r = results.p2.lon * d2r; + double lata2r = results.p2.lat * d2r; + double lonb1r = results.q1.lon * d2r; + double latb1r = results.q1.lat * d2r; + double lonb2r = results.q2.lon * d2r; + double latb2r = results.q2.lat * d2r; + + expected_result result; + + // WGS84 + bg::srs::spheroid spheroid(6378137.0, 6356752.3142451793); + + bg::formula::gnomonic_intersection + ::apply(lona1r, lata1r, lona2r, lata2r, lonb1r, latb1r, lonb2r, latb2r, result.lon, result.lat, spheroid); + result.lon *= r2d; + result.lat *= r2d; + check_inverse(result, results.gnomonic_vincenty, results.gnomonic_karney, 0.00000001); + + bg::formula::gnomonic_intersection + ::apply(lona1r, lata1r, lona2r, lata2r, lonb1r, latb1r, lonb2r, latb2r, result.lon, result.lat, spheroid); + result.lon *= r2d; + result.lat *= r2d; + check_inverse(result, results.gnomonic_thomas, results.gnomonic_karney, 0.0000001); + + bg::formula::sjoberg_intersection + ::apply(lona1r, lata1r, lona2r, lata2r, lonb1r, latb1r, lonb2r, latb2r, result.lon, result.lat, spheroid); + result.lon *= r2d; + result.lat *= r2d; + check_inverse(result, results.sjoberg_vincenty, results.sjoberg_karney, 0.00000001); + + bg::formula::sjoberg_intersection + ::apply(lona1r, lata1r, lona2r, lata2r, lonb1r, latb1r, lonb2r, latb2r, result.lon, result.lat, spheroid); + result.lon *= r2d; + result.lat *= r2d; + check_inverse(result, results.sjoberg_thomas, results.sjoberg_karney, 0.0000001); + + bg::formula::sjoberg_intersection + ::apply(lona1r, lata1r, lona2r, lata2r, lonb1r, latb1r, lonb2r, latb2r, result.lon, result.lat, spheroid); + result.lon *= r2d; + result.lat *= r2d; + check_inverse(result, results.sjoberg_andoyer, results.sjoberg_karney, 0.0001); +} + +int test_main(int, char*[]) +{ + for (size_t i = 0; i < expected_size; ++i) + { + test_all(expected[i]); + } + + return 0; +} diff --git a/test/formulas/intersection_cases.hpp b/test/formulas/intersection_cases.hpp new file mode 100644 index 000000000..d3d148db3 --- /dev/null +++ b/test/formulas/intersection_cases.hpp @@ -0,0 +1,129 @@ +// Boost.Geometry +// Unit Test + +// Copyright (c) 2016 Oracle and/or its affiliates. + +// 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_TEST_INTERSECTION_CASES_HPP +#define BOOST_GEOMETRY_TEST_INTERSECTION_CASES_HPP + +struct coordinates +{ + double lon; + double lat; +}; + +struct expected_result +{ + double lon; + double lat; +}; + +struct expected_results +{ + coordinates p1; + coordinates p2; + coordinates q1; + coordinates q2; + expected_result gnomonic_karney; + expected_result gnomonic_vincenty; + expected_result gnomonic_thomas; + expected_result sjoberg_karney; + expected_result sjoberg_vincenty; + expected_result sjoberg_thomas; + expected_result sjoberg_andoyer; +}; + +expected_results expected[] = +{ + { + { -1, -1 },{ 1, 1 }, + { -1, 1 },{ 1, -1 }, + { 0.0000000000000000, 0.0000000000000002 }, + { 0.0000000000000000, 0.0000000000000000 }, + { 0.0000000000000000, 0.0000000000000000 }, + { 0.0000000000633173, 0.0000000000000003 }, + { 0.0000000000626537, -0.0000000000000000 }, + { -0.0000000187861002, -0.0000000000000000 }, + { -0.0000055778585615, -0.0000000000000000 } + },{ + { 1, 1 },{ -1, -1 }, + { -1, 1 },{ 1, -1 }, + { 0.0000000000000000, 0.0000000000000002 }, + { 0.0000000000000000, 0.0000000000000000 }, + { 0.0000000000000000, 0.0000000000000000 }, + { 0.0000000000000000, 0.0000000000633274 }, + { 0.0000000000000000, 0.0000000000626632 }, + { -0.0000000000000006, -0.0000000187889745 }, + { -0.0000000000000001, -0.0000055787431353 } + },{ + { -1, -1 },{ 1, 1 }, + { 1, -1 },{ -1, 1 }, + { 0.0000000000000000, 0.0000000000000002 }, + { 0.0000000000000000, 0.0000000000000000 }, + { 0.0000000000000000, 0.0000000000000000 }, + { -0.0000000000000000, -0.0000000000633268 }, + { -0.0000000000000000, -0.0000000000626632 }, + { -0.0000000000000004, 0.0000000187889746 }, + { 0.0000000000000001, 0.0000055787431353 } + },{ + { 1, 1 },{ -1, -1 }, + { 1, -1 },{ -1, 1 }, + { 0.0000000000000000, 0.0000000000000002 }, + { 0.0000000000000000, 0.0000000000000000 }, + { 0.0000000000000000, 0.0000000000000000 }, + { -0.0000000000633173, 0.0000000000000003 }, + { -0.0000000000626537, -0.0000000000000000 }, + { 0.0000000187860994, 0.0000000000000001 }, + { 0.0000055778585615, -0.0000000000000000 } + },{ + { 0, 0 },{ 1, 1 }, + { 0, 1 },{ 1, 0 }, + { 0.5000000000000000, 0.5000573755188484 }, + { 0.5000000000000000, 0.5000573755188470 }, + { 0.5000000000000000, 0.5000573755109839 }, + { 0.5000000000316606, 0.5000573755188390 }, + { 0.5000000000313266, 0.5000573755188389 }, + { 0.4999999906069524, 0.5000573755152582 }, + { 0.4999972102164753, 0.5000573755151276 } + },{ + { 1, 1 },{ 0, 0 }, + { 0, 1 },{ 1, 0 }, + { 0.5000000000000000, 0.5000573755188484 }, + { 0.5000000000000000, 0.5000573755188470 }, + { 0.5000000000000000, 0.5000573755109839 }, + { 0.5000000000000000, 0.5000573755505008 }, + { 0.5000000000000000, 0.5000573755501669 }, + { 0.4999999999999996, 0.5000573661218464 }, + { 0.4999999999999999, 0.5000545856093679 } + },{ + { 0, 0 },{ 1, 1 }, + { 1, 0 },{ 0, 1 }, + { 0.5000000000000000, 0.5000573755188484 }, + { 0.5000000000000000, 0.5000573755188470 }, + { 0.5000000000000000, 0.5000573755109839 }, + { 0.5000000000000001, 0.5000573754871773 }, + { 0.4999999999999999, 0.5000573754875109 }, + { 0.4999999999999999, 0.5000573849086647 }, + { 0.5000000000000000, 0.5000601654208935 } + },{ + { 1, 1 },{ 0, 0 }, + { 1, 0 },{ 0, 1 }, + { 0.5000000000000000, 0.5000573755188484 }, + { 0.5000000000000000, 0.5000573755188470 }, + { 0.5000000000000000, 0.5000573755109839 }, + { 0.4999999999683394, 0.5000573755188390 }, + { 0.4999999999686731, 0.5000573755188389 }, + { 0.5000000093930521, 0.5000573755152582 }, + { 0.5000027897835244, 0.5000573755151276 } + } +}; + +size_t const expected_size = sizeof(expected) / sizeof(expected_results); + +#endif // BOOST_GEOMETRY_TEST_INTERSECTION_CASES_HPP diff --git a/test/formulas/inverse.cpp b/test/formulas/inverse.cpp new file mode 100644 index 000000000..4c33cae28 --- /dev/null +++ b/test/formulas/inverse.cpp @@ -0,0 +1,71 @@ +// Boost.Geometry +// Unit Test + +// Copyright (c) 2016 Oracle and/or its affiliates. + +// 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) + +#include "test_formula.hpp" +#include "inverse_cases.hpp" + +#include +#include +#include + +template +void check_inverse(Result const& result, expected_result const& expected, expected_result const& reference, double reference_error) +{ + check_one(result.distance, expected.distance, reference.distance, reference_error); + check_one(result.azimuth, expected.azimuth, reference.azimuth, reference_error, true); + check_one(result.reverse_azimuth, expected.reverse_azimuth, reference.reverse_azimuth, reference_error, true); + check_one(result.reduced_length, expected.reduced_length, reference.reduced_length, reference_error); + check_one(result.geodesic_scale, expected.geodesic_scale, reference.geodesic_scale, reference_error); +} + +void test_all(expected_results const& results) +{ + double const d2r = bg::math::d2r(); + double const r2d = bg::math::r2d(); + + double lon1r = results.p1.lon * d2r; + double lat1r = results.p1.lat * d2r; + double lon2r = results.p2.lon * d2r; + double lat2r = results.p2.lat * d2r; + + // WGS84 + bg::srs::spheroid spheroid(6378137.0, 6356752.3142451793); + + bg::formula::result_inverse result; + + typedef bg::formula::vincenty_inverse vi_t; + result = vi_t::apply(lon1r, lat1r, lon2r, lat2r, spheroid); + result.azimuth *= r2d; + result.reverse_azimuth *= r2d; + check_inverse(result, results.vincenty, results.karney, 0.00000001); + + typedef bg::formula::thomas_inverse th_t; + result = th_t::apply(lon1r, lat1r, lon2r, lat2r, spheroid); + result.azimuth *= r2d; + result.reverse_azimuth *= r2d; + check_inverse(result, results.thomas, results.karney, 0.0000001); + + typedef bg::formula::andoyer_inverse an_t; + result = an_t::apply(lon1r, lat1r, lon2r, lat2r, spheroid); + result.azimuth *= r2d; + result.reverse_azimuth *= r2d; + check_inverse(result, results.andoyer, results.karney, 0.0001); +} + +int test_main(int, char*[]) +{ + for (size_t i = 0; i < expected_size; ++i) + { + test_all(expected[i]); + } + + return 0; +} diff --git a/test/formulas/inverse_cases.hpp b/test/formulas/inverse_cases.hpp new file mode 100644 index 000000000..1abc01e85 --- /dev/null +++ b/test/formulas/inverse_cases.hpp @@ -0,0 +1,480 @@ +// Boost.Geometry +// Unit Test + +// Copyright (c) 2016 Oracle and/or its affiliates. + +// 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_TEST_INVERSE_CASES_HPP +#define BOOST_GEOMETRY_TEST_INVERSE_CASES_HPP + +struct coordinates +{ + double lon; + double lat; +}; + +struct expected_result +{ + double distance; + double azimuth; + double reverse_azimuth; + double reduced_length; + double geodesic_scale; +}; + +struct expected_results +{ + coordinates p1; + coordinates p2; + expected_result karney; + expected_result vincenty; + expected_result thomas; + expected_result andoyer; +}; + +expected_results expected[] = +{ + { + { 0, 0 },{ 2, 0 }, + { 222638.98158654713188298047, 90.00000000000000000000, 90.00000000000000000000, 222593.46652303214068524539, 0.99938672191946420487 }, + { 222638.98158645280636847019, 90.00000000000000000000, 90.00000000000000000000, 222593.46652303214068524539, 0.99938672191946420487 }, + { 222638.98158654122380539775, 90.00000000000000000000, 90.00000000000000000000, 222593.46652303214068524539, 0.99938672191946420487 }, + { 222638.98158654125290922821, 90.00000000000000000000, 90.00000000000000000000, 222593.46652303214068524539, 0.99938672191946420487 } + },{ + { 0, 0 },{ 2, 2 }, + { 313775.70942918420769274235, 45.17488858648466987233, 45.20980230803674970730, 313648.30600607168162241578, 0.99878199603375228399 }, + { 313775.70929574419278651476, 45.17488858646600391467, 45.20980230801805532792, 313648.30601466231746599078, 0.99878199603375328319 }, + { 313775.70869052573107182980, 45.17488750916628958976, 45.20980122940459722258, 313648.30008120078127831221, 0.99878199607986462016 }, + { 313772.17715740547282621264, 45.17456700769592004008, 45.20948072916769433505, 313646.54128309490624815226, 0.99878200978130526888 } + },{ + { 0, 0 },{ 0, 2 }, + { 221149.45337213488528504968, 0.00000000000000000000, 0.00000000000000000000, 221104.84592454897938296199, 0.99939490135383823866 }, + { 221149.45318342180689796805, 0.00000000000000000000, 0.00000000000000000000, 221104.84593068063259124756, 0.99939490135383812763 }, + { 221149.45337045041378587484, 0.00000000000000000000, 0.00000000000000000000, 221104.84593068063259124756, 0.99939490135383812763 }, + { 221146.95820782837108708918, 0.00000000000000002350, 0.00000000000000002350, 221104.84893554644077084959, 0.99939490135383812763 } + },{ + { 0, 0 },{ -2, 2 }, + { 313775.70942918420769274235, -45.17488858648466987233, -45.20980230803674970730, 313648.30600607168162241578, 0.99878199603375228399 }, + { 313775.70929574419278651476, -45.17488858646600391467, -45.20980230801805532792, 313648.30601466231746599078, 0.99878199603375328319 }, + { 313775.70869052573107182980, -45.17488750916629669518, -45.20980122940459722258, 313648.30008120078127831221, 0.99878199607986462016 }, + { 313772.17715740547282621264, -45.17456700769592004008, -45.20948072916767301876, 313646.54128309484804049134, 0.99878200978130526888 } + },{ + { 0, 0 },{ -2, 0 }, + { 222638.98158654713188298047, -90.00000000000000000000, -90.00000000000000000000, 222593.46652303214068524539, 0.99938672191946420487 }, + { 222638.98158645280636847019, -90.00000000000000000000, -90.00000000000000000000, 222593.46652303214068524539, 0.99938672191946420487 }, + { 222638.98158654122380539775, -90.00000000000000000000, -90.00000000000000000000, 222593.46652303214068524539, 0.99938672191946420487 }, + { 222638.98158654125290922821, -90.00000000000000000000, -90.00000000000000000000, 222593.46652303214068524539, 0.99938672191946420487 } + },{ + { 0, 0 },{ -2, -2 }, + { 313775.70942918420769274235, -134.82511141351534433852, -134.79019769196324318727, 313648.30600607168162241578, 0.99878199603375228399 }, + { 313775.70929574419278651476, -134.82511141353401740162, -134.79019769198197309379, 313648.30601466225925832987, 0.99878199603375317217 }, + { 313775.70869052573107182980, -134.82511249083370330482, -134.79019877059539567199, 313648.30008120083948597312, 0.99878199607986462016 }, + { 313772.17715740547282621264, -134.82543299230408706535, -134.79051927083230566495, 313646.54128309502266347408, 0.99878200978130537990 } + },{ + { 0, 0 },{ 0, -2 }, + { 221149.45337213488528504968, -180.00000000000000000000, -180.00000000000000000000, 221104.84592454897938296199, 0.99939490135383823866 }, + { 221149.45318342180689796805, 180.00000000000000000000, 180.00000000000000000000, 221104.84593068063259124756, 0.99939490135383812763 }, + { 221149.45337045041378587484, 180.00000000000000000000, 180.00000000000000000000, 221104.84593068063259124756, 0.99939490135383812763 }, + { 221146.95820782837108708918, 180.00000000000000000000, 180.00000000000000000000, 221104.84893554644077084959, 0.99939490135383812763 } + },{ + { 0, 0 },{ 2, -2 }, + { 313775.70942918420769274235, 134.82511141351534433852, 134.79019769196324318727, 313648.30600607168162241578, 0.99878199603375228399 }, + { 313775.70929574419278651476, 134.82511141353401740162, 134.79019769198197309379, 313648.30601466225925832987, 0.99878199603375317217 }, + { 313775.70869052573107182980, 134.82511249083370330482, 134.79019877059539567199, 313648.30008120083948597312, 0.99878199607986462016 }, + { 313772.17715740547282621264, 134.82543299230408706535, 134.79051927083230566495, 313646.54128309502266347408, 0.99878200978130537990 } + },{ + { -1, 0 },{ 2, 0 }, + { 333958.47237982071237638593, 90.00000000000000000000, 90.00000000000000000000, 333804.87081722758011892438, 0.99862030063297502203 }, + { 333958.47237967920955270529, 90.00000000000000000000, 90.00000000000000000000, 333804.87081722758011892438, 0.99862030063297502203 }, + { 333958.47237982566002756357, 90.00000000000000000000, 90.00000000000000000000, 333804.87081722758011892438, 0.99862030063297502203 }, + { 333958.47237982566002756357, 90.00000000000000000000, 90.00000000000000000000, 333804.87081722758011892438, 0.99862030063297502203 } + },{ + { -1, 0 },{ 2, 2 }, + { 400487.62166116386651992798, 56.46443555420994186989, 56.51681282834063324572, 400222.73679570353124290705, 0.99801604059094650712 }, + { 400487.62155657896073535085, 56.46443555419775606197, 56.51681282832842612152, 400222.73680666065774857998, 0.99801604059094761734 }, + { 400487.62116943788714706898, 56.46443456250134573793, 56.51681183466060787168, 400222.72635490150423720479, 0.99801604069467231284 }, + { 400484.31980028707766905427, 56.46436757836366382435, 56.51674485214859089410, 400222.02724612434394657612, 0.99801604768666130063 } + },{ + { -1, 0 },{ 0, 2 }, + { 247576.47264764847932383418, 26.70874628270370010341, 26.72620180544743817563, 247513.88750887679634615779, 0.99924166327570262958 }, + { 247576.47247877591871656477, 26.70874628267113948255, 26.72620180541484202763, 247513.88751566910650581121, 0.99924166327570307367 }, + { 247576.47204536388744600117, 26.70874541733553186873, 26.72620093942252594843, 247513.88563483985490165651, 0.99924166328723251773 }, + { 247573.34468778557493351400, 26.70817834948789482041, 26.72563387223648589952, 247512.65741612159763462842, 0.99924167083675718981 } + },{ + { -1, 0 },{ -2, 2 }, + { 247576.47264764847932383418, -26.70874628270370010341, -26.72620180544743817563, 247513.88750887679634615779, 0.99924166327570262958 }, + { 247576.47247877591871656477, -26.70874628267113948255, -26.72620180541484202763, 247513.88751566910650581121, 0.99924166327570307367 }, + { 247576.47204536388744600117, -26.70874541733554607958, -26.72620093942252594843, 247513.88563483985490165651, 0.99924166328723251773 }, + { 247573.34468778557493351400, -26.70817834948789482041, -26.72563387223651432123, 247512.65741612159763462842, 0.99924167083675718981 } + },{ + { -1, 0 },{ -2, 0 }, + { 111319.49079327356594149023, -90.00000000000000000000, -90.00000000000000000000, 111313.80114861292531713843, 0.99984666872462601983 }, + { 111319.49079322640318423510, -90.00000000000000000000, -90.00000000000000000000, 111313.80114861292531713843, 0.99984666872462601983 }, + { 111319.49079326246283017099, -90.00000000000000000000, -90.00000000000000000000, 111313.80114861292531713843, 0.99984666872462601983 }, + { 111319.49079326246283017099, -90.00000000000000000000, -90.00000000000000000000, 111313.80114861292531713843, 0.99984666872462601983 } + },{ + { -1, 0 },{ -2, -2 }, + { 247576.47264764847932383418, -153.29125371729628568573, -153.27379819455256892979, 247513.88750887679634615779, 0.99924166327570262958 }, + { 247576.47247877591871656477, -153.29125371732885696474, -153.27379819458516863051, 247513.88751566907740198076, 0.99924166327570307367 }, + { 247576.47204536388744600117, -153.29125458266443615685, -153.27379906057745984072, 247513.88563483985490165651, 0.99924166328723251773 }, + { 247573.34468778557493351400, -153.29182165051210517959, -153.27436612776349988962, 247512.65741612162673845887, 0.99924167083675718981 } + },{ + { -1, 0 },{ 0, -2 }, + { 247576.47264764847932383418, 153.29125371729628568573, 153.27379819455256892979, 247513.88750887679634615779, 0.99924166327570262958 }, + { 247576.47247877591871656477, 153.29125371732885696474, 153.27379819458516863051, 247513.88751566907740198076, 0.99924166327570307367 }, + { 247576.47204536388744600117, 153.29125458266446457856, 153.27379906057745984072, 247513.88563483985490165651, 0.99924166328723251773 }, + { 247573.34468778557493351400, 153.29182165051210517959, 153.27436612776349988962, 247512.65741612162673845887, 0.99924167083675718981 } + },{ + { -1, 0 },{ 2, -2 }, + { 400487.62166116386651992798, 123.53556444579005813011, 123.48318717165936675428, 400222.73679570353124290705, 0.99801604059094650712 }, + { 400487.62155657896073535085, 123.53556444580226525431, 123.48318717167158808934, 400222.73680666059954091907, 0.99801604059094761734 }, + { 400487.62116943788714706898, 123.53556543749867557835, 123.48318816533939923374, 400222.72635490150423720479, 0.99801604069467231284 }, + { 400484.31980028707766905427, 123.53563242163632196480, 123.48325514785142331675, 400222.02724612434394657612, 0.99801604768666130063 } + },{ + { 1, 0 },{ 2, 0 }, + { 111319.49079327356594149023, 90.00000000000000000000, 90.00000000000000000000, 111313.80114861292531713843, 0.99984666872462601983 }, + { 111319.49079322640318423510, 90.00000000000000000000, 90.00000000000000000000, 111313.80114861292531713843, 0.99984666872462601983 }, + { 111319.49079326246283017099, 90.00000000000000000000, 90.00000000000000000000, 111313.80114861292531713843, 0.99984666872462601983 }, + { 111319.49079326246283017099, 90.00000000000000000000, 90.00000000000000000000, 111313.80114861292531713843, 0.99984666872462601983 } + },{ + { 1, 0 },{ 2, 2 }, + { 247576.47264764847932383418, 26.70874628270370010341, 26.72620180544743817563, 247513.88750887679634615779, 0.99924166327570262958 }, + { 247576.47247877591871656477, 26.70874628267113948255, 26.72620180541484202763, 247513.88751566910650581121, 0.99924166327570307367 }, + { 247576.47204536388744600117, 26.70874541733553186873, 26.72620093942252594843, 247513.88563483985490165651, 0.99924166328723251773 }, + { 247573.34468778557493351400, 26.70817834948789482041, 26.72563387223648589952, 247512.65741612159763462842, 0.99924167083675718981 } + },{ + { 1, 0 },{ 0, 2 }, + { 247576.47264764847932383418, -26.70874628270370010341, -26.72620180544743817563, 247513.88750887679634615779, 0.99924166327570262958 }, + { 247576.47247877591871656477, -26.70874628267113948255, -26.72620180541484202763, 247513.88751566910650581121, 0.99924166327570307367 }, + { 247576.47204536388744600117, -26.70874541733554607958, -26.72620093942252594843, 247513.88563483985490165651, 0.99924166328723251773 }, + { 247573.34468778557493351400, -26.70817834948789482041, -26.72563387223651432123, 247512.65741612159763462842, 0.99924167083675718981 } + },{ + { 1, 0 },{ -2, 2 }, + { 400487.62166116386651992798, -56.46443555420994186989, -56.51681282834063324572, 400222.73679570353124290705, 0.99801604059094650712 }, + { 400487.62155657896073535085, -56.46443555419775606197, -56.51681282832842612152, 400222.73680666065774857998, 0.99801604059094761734 }, + { 400487.62116943788714706898, -56.46443456250133863250, -56.51681183466062918797, 400222.72635490167886018753, 0.99801604069467231284 }, + { 400484.31980028707766905427, -56.46436757836366382435, -56.51674485214855536697, 400222.02724612399470061064, 0.99801604768666130063 } + },{ + { 1, 0 },{ -2, 0 }, + { 333958.47237982071237638593, -90.00000000000000000000, -90.00000000000000000000, 333804.87081722758011892438, 0.99862030063297502203 }, + { 333958.47237967920955270529, -90.00000000000000000000, -90.00000000000000000000, 333804.87081722758011892438, 0.99862030063297502203 }, + { 333958.47237982566002756357, -90.00000000000000000000, -90.00000000000000000000, 333804.87081722758011892438, 0.99862030063297502203 }, + { 333958.47237982566002756357, -90.00000000000000000000, -90.00000000000000000000, 333804.87081722758011892438, 0.99862030063297502203 } + },{ + { 1, 0 },{ -2, -2 }, + { 400487.62166116386651992798, -123.53556444579005813011, -123.48318717165936675428, 400222.73679570353124290705, 0.99801604059094650712 }, + { 400487.62155657896073535085, -123.53556444580226525431, -123.48318717167158808934, 400222.73680666059954091907, 0.99801604059094761734 }, + { 400487.62116943788714706898, -123.53556543749867557835, -123.48318816533941344460, 400222.72635490121319890022, 0.99801604069467231284 }, + { 400484.31980028707766905427, -123.53563242163632196480, -123.48325514785139489504, 400222.02724612463498488069, 0.99801604768666130063 } + },{ + { 1, 0 },{ 0, -2 }, + { 247576.47264764847932383418, -153.29125371729628568573, -153.27379819455256892979, 247513.88750887679634615779, 0.99924166327570262958 }, + { 247576.47247877591871656477, -153.29125371732885696474, -153.27379819458516863051, 247513.88751566907740198076, 0.99924166327570307367 }, + { 247576.47204536388744600117, -153.29125458266443615685, -153.27379906057745984072, 247513.88563483985490165651, 0.99924166328723251773 }, + { 247573.34468778557493351400, -153.29182165051210517959, -153.27436612776349988962, 247512.65741612162673845887, 0.99924167083675718981 } + },{ + { 1, 0 },{ 2, -2 }, + { 247576.47264764847932383418, 153.29125371729628568573, 153.27379819455256892979, 247513.88750887679634615779, 0.99924166327570262958 }, + { 247576.47247877591871656477, 153.29125371732885696474, 153.27379819458516863051, 247513.88751566907740198076, 0.99924166327570307367 }, + { 247576.47204536388744600117, 153.29125458266446457856, 153.27379906057745984072, 247513.88563483985490165651, 0.99924166328723251773 }, + { 247573.34468778557493351400, 153.29182165051210517959, 153.27436612776349988962, 247512.65741612162673845887, 0.99924167083675718981 } + },{ + { 0, -1 },{ 2, 0 }, + { 248575.56516798117081634700, 63.59904041930798257454, 63.58158489649751743400, 248512.21908866314333863556, 0.99923553066716652715 }, + { 248575.56515735003631561995, 63.59904041929794260568, 63.58158489648748457057, 248512.21909045605571009219, 0.99923553066715220528 }, + { 248575.56501938513247296214, 63.59903955892717419829, 63.58158403677443004653, 248512.21158473053947091103, 0.99923553071334769715 }, + { 248574.11260137573117390275, 63.59909262487922632090, 63.58163710212382113696, 248512.67536870032199658453, 0.99923552785888392069 } + },{ + { 0, -1 },{ 2, 2 }, + { 399491.95531813317211344838, 33.86382331638844789268, 33.88128418166377286980, 399229.04036820423789322376, 0.99802588852441009859 }, + { 399491.95525925338733941317, 33.86382331636024645150, 33.88128418163555721776, 399229.04037646017968654633, 0.99802588850630413742 }, + { 399491.95420239900704473257, 33.86382231856556046523, 33.88128318318352683036, 399229.03571708954405039549, 0.99802588855242924115 }, + { 399486.91562757542124018073, 33.86329689027443379246, 33.88075775553439683563, 399226.58732164395041763783, 0.99802591281687313973 } + },{ + { 0, -1 },{ 0, 2 }, + { 331723.84192993369651958346, 0.00000000000000000000, 0.00000000000000000000, 331573.30333569750655442476, 0.99863870153788791839 }, + { 331723.84185956208966672421, 0.00000000000000000000, 0.00000000000000000000, 331573.30334328504977747798, 0.99863870152539924163 }, + { 331723.84192803525365889072, 0.00000000000000000000, 0.00000000000000000000, 331573.30334328504977747798, 0.99863870152539924163 }, + { 331720.09633564797695726156, 0.00000000000000002351, 0.00000000000000002350, 331573.30672345001948997378, 0.99863870151614875237 } + },{ + { 0, -1 },{ -2, 2 }, + { 399491.95531813317211344838, -33.86382331638844789268, -33.88128418166377286980, 399229.04036820423789322376, 0.99802588852441009859 }, + { 399491.95525925338733941317, -33.86382331636024645150, -33.88128418163555721776, 399229.04037646017968654633, 0.99802588850630413742 }, + { 399491.95420239900704473257, -33.86382231856555335980, -33.88128318318355525207, 399229.03571708960225805640, 0.99802588855242924115 }, + { 399486.91562757542124018073, -33.86329689027443379246, -33.88075775553439683563, 399226.58732164395041763783, 0.99802591281687313973 } + },{ + { 0, -1 },{ -2, 0 }, + { 248575.56516798117081634700, -63.59904041930798257454, -63.58158489649751743400, 248512.21908866314333863556, 0.99923553066716652715 }, + { 248575.56515735003631561995, -63.59904041929794260568, -63.58158489648748457057, 248512.21909045605571009219, 0.99923553066715220528 }, + { 248575.56501938513247296214, -63.59903955892717419829, -63.58158403677445846824, 248512.21158473053947091103, 0.99923553071334769715 }, + { 248574.11260137573117390275, -63.59909262487922632090, -63.58163710212379271525, 248512.67536870032199658453, 0.99923552785888392069 } + },{ + { 0, -1 },{ -2, -2 }, + { 248515.52773222429095767438, -116.44291541236518128244, -116.39055416434335654685, 248452.22805491264443844557, 0.99923590400821504787 }, + { 248515.52763759149820543826, -116.44291541237451781399, -116.39055416435273571096, 248452.22805559608968906105, 0.99923590407101092747 }, + { 248515.52758369332877919078, -116.44291626924928095832, -116.39055502319511958831, 248452.22057304141344502568, 0.99923590411705243142 }, + { 248514.07922688819235190749, -116.44286383106521043374, -116.39050258320843056481, 248452.68231273870333097875, 0.99923590134832673826 } + },{ + { 0, -1 },{ 0, -2 }, + { 110575.06481433614681009203, -180.00000000000000000000, -180.00000000000000000000, 110569.48860416181560140103, 0.99984871368918792900 }, + { 110575.06460189135395921767, 180.00000000000000000000, 180.00000000000000000000, 110569.48860883565794210881, 0.99984871370166705784 }, + { 110575.06481286860071122646, 180.00000000000000000000, 180.00000000000000000000, 110569.48860883565794210881, 0.99984871370166705784 }, + { 110573.82008000080531928688, 180.00000000000000000000, 180.00000000000000000000, 110569.49123749321734067053, 0.99984871370886085895 } + },{ + { 0, -1 },{ 2, -2 }, + { 248515.52773222429095767438, 116.44291541236518128244, 116.39055416434335654685, 248452.22805491264443844557, 0.99923590400821504787 }, + { 248515.52763759149820543826, 116.44291541237451781399, 116.39055416435273571096, 248452.22805559608968906105, 0.99923590407101092747 }, + { 248515.52758369332877919078, 116.44291626924930938003, 116.39055502319511958831, 248452.22057304164627566934, 0.99923590411705243142 }, + { 248514.07922688819235190749, 116.44286383106521043374, 116.39050258320843056481, 248452.68231273870333097875, 0.99923590134832673826 } + },{ + { 0, 1 },{ 2, 0 }, + { 248575.56516798117081634700, 116.40095958069201742546, 116.41841510350248256600, 248512.21908866314333863556, 0.99923553066716652715 }, + { 248575.56515735003631561995, 116.40095958070207871060, 116.41841510351252964028, 248512.21909045602660626173, 0.99923553066715220528 }, + { 248575.56501938513247296214, 116.40096044107282580171, 116.41841596322554153176, 248512.21158473062678240240, 0.99923553071334780817 }, + { 248574.11260137573117390275, 116.40090737512078078453, 116.41836289787615044133, 248512.67536870026378892362, 0.99923552785888392069 } + },{ + { 0, 1 },{ 2, 2 }, + { 248515.52773222429095767438, 63.55708458763482582299, 63.60944583565664345315, 248452.22805491264443844557, 0.99923590400821504787 }, + { 248515.52763759149820543826, 63.55708458762548218601, 63.60944583564726428904, 248452.22805559608968906105, 0.99923590407101092747 }, + { 248515.52758369332877919078, 63.55708373075069061997, 63.60944497680485909541, 248452.22057304115151055157, 0.99923590411705243142 }, + { 248514.07922688819235190749, 63.55713616893478246084, 63.60949741679156232976, 248452.68231273847050033510, 0.99923590134832684928 } + },{ + { 0, 1 },{ 0, 2 }, + { 110575.06481433614681009203, 0.00000000000000000000, 0.00000000000000000000, 110569.48860416181560140103, 0.99984871368918792900 }, + { 110575.06460189135395921767, 0.00000000000000000000, 0.00000000000000000000, 110569.48860883565794210881, 0.99984871370166705784 }, + { 110575.06481286860071122646, 0.00000000000000000000, 0.00000000000000000000, 110569.48860883565794210881, 0.99984871370166705784 }, + { 110573.82008000080531928688, 0.00000000000000002350, 0.00000000000000002350, 110569.49123749321734067053, 0.99984871370886085895 } + },{ + { 0, 1 },{ -2, 2 }, + { 248515.52773222429095767438, -63.55708458763482582299, -63.60944583565664345315, 248452.22805491264443844557, 0.99923590400821504787 }, + { 248515.52763759149820543826, -63.55708458762548218601, -63.60944583564726428904, 248452.22805559608968906105, 0.99923590407101092747 }, + { 248515.52758369332877919078, -63.55708373075070483083, -63.60944497680488041169, 248452.22057304150075651705, 0.99923590411705254244 }, + { 248514.07922688819235190749, -63.55713616893478246084, -63.60949741679156943519, 248452.68231273873243480921, 0.99923590134832684928 } + },{ + { 0, 1 },{ -2, 0 }, + { 248575.56516798117081634700, -116.40095958069201742546, -116.41841510350248256600, 248512.21908866314333863556, 0.99923553066716652715 }, + { 248575.56515735003631561995, -116.40095958070207871060, -116.41841510351252964028, 248512.21909045602660626173, 0.99923553066715220528 }, + { 248575.56501938513247296214, -116.40096044107282580171, -116.41841596322554153176, 248512.21158473062678240240, 0.99923553071334780817 }, + { 248574.11260137573117390275, -116.40090737512078078453, -116.41836289787615044133, 248512.67536870026378892362, 0.99923552785888392069 } + },{ + { 0, 1 },{ -2, -2 }, + { 399491.95531813317211344838, -146.13617668361155210732, -146.11871581833622713020, 399229.04036820423789322376, 0.99802588852441009859 }, + { 399491.95525925338733941317, -146.13617668363974644308, -146.11871581836444988767, 399229.04037646006327122450, 0.99802588850630413742 }, + { 399491.95420239900704473257, -146.13617768143444664020, -146.11871681681645895878, 399229.03571708971867337823, 0.99802588855242924115 }, + { 399486.91562757542124018073, -146.13670310972554489126, -146.11924224446559605894, 399226.58732164406683295965, 0.99802591281687325075 } + },{ + { 0, 1 },{ 0, -2 }, + { 331723.84192993369651958346, -180.00000000000000000000, -180.00000000000000000000, 331573.30333569750655442476, 0.99863870153788791839 }, + { 331723.84185956208966672421, 180.00000000000000000000, 180.00000000000000000000, 331573.30334328504977747798, 0.99863870152539924163 }, + { 331723.84192803525365889072, 180.00000000000000000000, 180.00000000000000000000, 331573.30334328504977747798, 0.99863870152539924163 }, + { 331720.09633564797695726156, 180.00000000000000000000, 180.00000000000000000000, 331573.30672345001948997378, 0.99863870151614875237 } + },{ + { 0, 1 },{ 2, -2 }, + { 399491.95531813317211344838, 146.13617668361155210732, 146.11871581833622713020, 399229.04036820423789322376, 0.99802588852441009859 }, + { 399491.95525925338733941317, 146.13617668363974644308, 146.11871581836444988767, 399229.04037646006327122450, 0.99802588850630413742 }, + { 399491.95420239900704473257, 146.13617768143444664020, 146.11871681681645895878, 399229.03571708971867337823, 0.99802588855242924115 }, + { 399486.91562757542124018073, 146.13670310972554489126, 146.11924224446559605894, 399226.58732164406683295965, 0.99802591281687325075 } + }, + { + { -1, -1 },{ 2, 0 }, + { 351772.23553088010521605611, 71.69677339271241578444, 71.67058676207953737958, 351592.72256732499226927757, 0.99846922689201267342 }, + { 351772.23552330053644254804, 71.69677339270522509196, 71.67058676207236089795, 351592.72256738768192008138, 0.99846922689200567902 }, + { 351772.23547190619865432382, 71.69677274795321864076, 71.67058611830732672843, 351592.71064292185474187136, 0.99846922699591911243 }, + { 351771.13000385620398446918, 71.69688960494077889507, 71.67070297450321447741, 351594.87308142206165939569, 0.99846920815167106156 } + }, { + { -1, -1 },{ 2, 2 }, + { 470675.27496387914288789034, 45.18799532476352709409, 45.21418997011227247640, 470245.32092262554215267301, 0.99726004843767979136 }, + { 470675.27491378918057307601, 45.18799532474472613330, 45.21418997009345730476, 470245.32093124865787103772, 0.99726004841255500022 }, + { 470675.27385581465205177665, 45.18799424651773222195, 45.21418889088008796762, 470245.31203990190988406539, 0.99726004851631100401 }, + { 470669.97387331607751548290, 45.18767381182056652733, 45.21386845703356982540, 470242.67608062457293272018, 0.99726007931332938394 } + }, { + { -1, -1 },{ 0, 2 }, + { 349898.53698544885264709592, 18.54804530050607525027, 18.55677506382081531910, 349721.87727315956726670265, 0.99848548653821667109 }, + { 349898.53691851865733042359, 18.54804530047409016902, 18.55677506378881247429, 349721.87728093314217403531, 0.99848548652432367323 }, + { 349898.53644461580552160740, 18.54804465014367664821, 18.55677441312981201804, 349721.87595040485030040145, 0.99848548653585678103 }, + { 349894.27001174906035885215, 18.54754137243966738424, 18.55627113576925424354, 349720.85020991315832361579, 0.99848549544738174344 } + }, { + { -1, -1 },{ -2, 2 }, + { 349898.53698544885264709592, -18.54804530050607525027, -18.55677506382081531910, 349721.87727315956726670265, 0.99848548653821667109 }, + { 349898.53691851865733042359, -18.54804530047409016902, -18.55677506378881247429, 349721.87728093314217403531, 0.99848548652432367323 }, + { 349898.53644461580552160740, -18.54804465014367664821, -18.55677441312981201804, 349721.87595040485030040145, 0.99848548653585678103 }, + { 349894.27001174906035885215, -18.54754137243966738424, -18.55627113576928266525, 349720.85020991315832361579, 0.99848549544738174344 } + }, { + { -1, -1 },{ -2, 0 }, + { 156899.56829134028521366417, -45.19676732164486310239, -45.18804022935886877121, 156883.63778222308610565960, 0.99969540695122460772 }, + { 156899.56827460310887545347, -45.19676732162573529195, -45.18804022933975517162, 156883.63778401838499121368, 0.99969540695121617002 }, + { 156899.56792193598812445998, -45.19676624219880523015, -45.18803915024161454994, 156883.63480984271154738963, 0.99969540696276681935 }, + { 156897.79947260793414898217, -45.19644594033049145310, -45.18771884804953486992, 156882.75281389255542308092, 0.99969541038810816325 } + }, { + { -1, -1 },{ -2, -2 }, + { 156876.14940188667969778180, -134.82952991582811819171, -134.80335129773999369718, 156860.22615479407249949872, 0.99969549952259184611 }, + { 156876.14925185780157335103, -134.82952991584656388113, -134.80335129775846780831, 156860.22615983051946386695, 0.99969549954768643918 }, + { 156876.14903264911845326424, -134.82953099167991695140, -134.80335237457535413341, 156860.22319510785746388137, 0.99969549955919845274 }, + { 156874.38594904550700448453, -134.82985169207830722371, -134.80367307400518939176, 156859.34477911840076558292, 0.99969550299904519353 } + }, { + { -1, -1 },{ 0, -2 }, + { 156876.14940188667969778180, 134.82952991582811819171, 134.80335129773999369718, 156860.22615479407249949872, 0.99969549952259184611 }, + { 156876.14925185780157335103, 134.82952991584656388113, 134.80335129775846780831, 156860.22615983051946386695, 0.99969549954768643918 }, + { 156876.14903264911845326424, 134.82953099167994537311, 134.80335237457538255512, 156860.22319510785746388137, 0.99969549955919856377 }, + { 156874.38594904550700448453, 134.82985169207830722371, 134.80367307400518939176, 156859.34477911840076558292, 0.99969550299904519353 } + }, { + { -1, -1 },{ 2, -2 }, + { 351676.50043935602298006415, 108.36087395536006283692, 108.28232205125480902552, 351497.13544799503870308399, 0.99847006808788085763 }, + { 351676.50037266127765178680, 108.36087395536665667350, 108.28232205126143128382, 351497.13543194788508117199, 0.99847006821303718738 }, + { 351676.50038040406070649624, 108.36087459655153963922, 108.28232269539883247944, 351497.12354394816793501377, 0.99847006831660412018 }, + { 351675.39839278126601129770, 108.36075825022818719390, 108.28220634670809374711, 351499.26940269087208434939, 0.99847004976658149111 } + }, { + { -1, 1 },{ 2, 0 }, + { 351772.23553088010521605611, 108.30322660728758421556, 108.32941323792046262042, 351592.72256732499226927757, 0.99846922689201267342 }, + { 351772.23552330053644254804, 108.30322660729477490804, 108.32941323792763910205, 351592.72256738756550475955, 0.99846922689200567902 }, + { 351772.23547190619865432382, 108.30322725204678135924, 108.32941388169267327157, 351592.71064292197115719318, 0.99846922699591911243 }, + { 351771.13000385620398446918, 108.30311039505922110493, 108.32929702549677131174, 351594.87308142217807471752, 0.99846920815167106156 } + }, { + { -1, 1 },{ 2, 2 }, + { 351676.50043935602298006415, 71.63912604463993716308, 71.71767794874519097448, 351497.13544799503870308399, 0.99847006808788085763 }, + { 351676.50037266127765178680, 71.63912604463332911564, 71.71767794873858292704, 351497.13543194829253479838, 0.99847006821303718738 }, + { 351676.50038040406070649624, 71.63912540344847457163, 71.71767730460115330970, 351497.12354394729482010007, 0.99847006831660423121 }, + { 351675.39839278126601129770, 71.63924174977181280610, 71.71779365329189204203, 351499.26940269029000774026, 0.99847004976658149111 } + }, { + { -1, 1 },{ 0, 2 }, + { 156876.14940188667969778180, 45.17047008417186759743, 45.19664870225999919739, 156860.22615479407249949872, 0.99969549952259184611 }, + { 156876.14925185780157335103, 45.17047008415342190801, 45.19664870224154640255, 156860.22615983063587918878, 0.99969549954768632816 }, + { 156876.14903264911845326424, 45.17046900832006883775, 45.19664762542461744488, 156860.22319510774104855955, 0.99969549955919845274 }, + { 156874.38594904550700448453, 45.17014830792169988172, 45.19632692599481060824, 156859.34477911831345409155, 0.99969550299904519353 } + }, { + { -1, 1 },{ -2, 2 }, + { 156876.14940188667969778180, -45.17047008417186759743, -45.19664870225999919739, 156860.22615479407249949872, 0.99969549952259184611 }, + { 156876.14925185780157335103, -45.17047008415342190801, -45.19664870224154640255, 156860.22615983063587918878, 0.99969549954768632816 }, + { 156876.14903264911845326424, -45.17046900832009015403, -45.19664762542463876116, 156860.22319510785746388137, 0.99969549955919856377 }, + { 156874.38594904550700448453, -45.17014830792169988172, -45.19632692599484613538, 156859.34477911848807707429, 0.99969550299904519353 } + }, { + { -1, 1 },{ -2, 0 }, + { 156899.56829134028521366417, -134.80323267835512979218, -134.81195977064112412336, 156883.63778222308610565960, 0.99969540695122460772 }, + { 156899.56827460310887545347, -134.80323267837425760263, -134.81195977066025193380, 156883.63778401838499121368, 0.99969540695121617002 }, + { 156899.56792193598812445998, -134.80323375780119476985, -134.81196084975837834463, 156883.63480984274065122008, 0.99969540696276681935 }, + { 156897.79947260793414898217, -134.80355405966952275776, -134.81228115195048644637, 156882.75281389255542308092, 0.99969541038810816325 } + }, { + { -1, 1 },{ -2, -2 }, + { 349898.53698544885264709592, -161.45195469949391053888, -161.44322493617917757547, 349721.87727315956726670265, 0.99848548653821667109 }, + { 349898.53691851865733042359, -161.45195469952594180540, -161.44322493621118042029, 349721.87728093314217403531, 0.99848548652432367323 }, + { 349898.53644461580552160740, -161.45195534985634822078, -161.44322558687019864010, 349721.87595040485030040145, 0.99848548653585678103 }, + { 349894.27001174906035885215, -161.45245862756033261576, -161.44372886423073509832, 349720.85020991315832361579, 0.99848549544738174344 } + }, { + { -1, 1 },{ 0, -2 }, + { 349898.53698544885264709592, 161.45195469949391053888, 161.44322493617917757547, 349721.87727315956726670265, 0.99848548653821667109 }, + { 349898.53691851865733042359, 161.45195469952594180540, 161.44322493621118042029, 349721.87728093314217403531, 0.99848548652432367323 }, + { 349898.53644461580552160740, 161.45195534985634822078, 161.44322558687019864010, 349721.87595040485030040145, 0.99848548653585678103 }, + { 349894.27001174906035885215, 161.45245862756033261576, 161.44372886423073509832, 349720.85020991315832361579, 0.99848549544738174344 } + }, { + { -1, 1 },{ 2, -2 }, + { 470675.27496387914288789034, 134.81200467523646580048, 134.78581002988772752360, 470245.32092262554215267301, 0.99726004843767979136 }, + { 470675.27491378918057307601, 134.81200467525528097212, 134.78581002990657111695, 470245.32093124854145571589, 0.99726004841255500022 }, + { 470675.27385581465205177665, 134.81200575348228198891, 134.78581110911991913781, 470245.31203990190988406539, 0.99726004851631100401 }, + { 470669.97387331607751548290, 134.81232618817941215639, 134.78613154296644438546, 470242.67608062474755570292, 0.99726007931332960599 } + }, { + { 1, 1 },{ 2, 0 }, + { 156899.56829134028521366417, 134.80323267835512979218, 134.81195977064112412336, 156883.63778222308610565960, 0.99969540695122460772 }, + { 156899.56827460310887545347, 134.80323267837425760263, 134.81195977066025193380, 156883.63778401838499121368, 0.99969540695121617002 }, + { 156899.56792193598812445998, 134.80323375780122319156, 134.81196084975840676634, 156883.63480984268244355917, 0.99969540696276681935 }, + { 156897.79947260793414898217, 134.80355405966952275776, 134.81228115195048644637, 156882.75281389255542308092, 0.99969541038810816325 } + }, { + { 1, 1 },{ 2, 2 }, + { 156876.14940188667969778180, 45.17047008417186759743, 45.19664870225999919739, 156860.22615479407249949872, 0.99969549952259184611 }, + { 156876.14925185780157335103, 45.17047008415342190801, 45.19664870224154640255, 156860.22615983063587918878, 0.99969549954768632816 }, + { 156876.14903264911845326424, 45.17046900832006883775, 45.19664762542461744488, 156860.22319510774104855955, 0.99969549955919845274 }, + { 156874.38594904550700448453, 45.17014830792169988172, 45.19632692599481060824, 156859.34477911831345409155, 0.99969550299904519353 } + }, { + { 1, 1 },{ 0, 2 }, + { 156876.14940188667969778180, -45.17047008417186759743, -45.19664870225999919739, 156860.22615479407249949872, 0.99969549952259184611 }, + { 156876.14925185780157335103, -45.17047008415342190801, -45.19664870224154640255, 156860.22615983063587918878, 0.99969549954768632816 }, + { 156876.14903264911845326424, -45.17046900832009015403, -45.19664762542463876116, 156860.22319510785746388137, 0.99969549955919856377 }, + { 156874.38594904550700448453, -45.17014830792169988172, -45.19632692599484613538, 156859.34477911848807707429, 0.99969550299904519353 } + }, { + { 1, 1 },{ -2, 2 }, + { 351676.50043935602298006415, -71.63912604463993716308, -71.71767794874519097448, 351497.13544799503870308399, 0.99847006808788085763 }, + { 351676.50037266127765178680, -71.63912604463332911564, -71.71767794873858292704, 351497.13543194829253479838, 0.99847006821303718738 }, + { 351676.50038040406070649624, -71.63912540344847457163, -71.71767730460118173141, 351497.12354394828435033560, 0.99847006831660412018 }, + { 351675.39839278126601129770, -71.63924174977181280610, -71.71779365329184940947, 351499.26940268895123153925, 0.99847004976658171316 } + }, { + { 1, 1 },{ -2, 0 }, + { 351772.23553088010521605611, -108.30322660728758421556, -108.32941323792046262042, 351592.72256732499226927757, 0.99846922689201267342 }, + { 351772.23552330053644254804, -108.30322660729477490804, -108.32941323792763910205, 351592.72256738756550475955, 0.99846922689200567902 }, + { 351772.23547190619865432382, -108.30322725204673872668, -108.32941388169263063901, 351592.71064292272785678506, 0.99846922699591933448 }, + { 351771.13000385620398446918, -108.30311039505922110493, -108.32929702549677131174, 351594.87308142217807471752, 0.99846920815167106156 } + }, { + { 1, 1 },{ -2, -2 }, + { 470675.27496387914288789034, -134.81200467523646580048, -134.78581002988772752360, 470245.32092262554215267301, 0.99726004843767979136 }, + { 470675.27491378918057307601, -134.81200467525528097212, -134.78581002990657111695, 470245.32093124854145571589, 0.99726004841255500022 }, + { 470675.27385581465205177665, -134.81200575348222514549, -134.78581110911991913781, 470245.31203990196809172630, 0.99726004851631100401 }, + { 470669.97387331607751548290, -134.81232618817941215639, -134.78613154296644438546, 470242.67608062474755570292, 0.99726007931332960599 } + }, { + { 1, 1 },{ 0, -2 }, + { 349898.53698544885264709592, -161.45195469949391053888, -161.44322493617917757547, 349721.87727315956726670265, 0.99848548653821667109 }, + { 349898.53691851865733042359, -161.45195469952594180540, -161.44322493621118042029, 349721.87728093314217403531, 0.99848548652432367323 }, + { 349898.53644461580552160740, -161.45195534985634822078, -161.44322558687019864010, 349721.87595040485030040145, 0.99848548653585678103 }, + { 349894.27001174906035885215, -161.45245862756033261576, -161.44372886423073509832, 349720.85020991315832361579, 0.99848549544738174344 } + }, { + { 1, 1 },{ 2, -2 }, + { 349898.53698544885264709592, 161.45195469949391053888, 161.44322493617917757547, 349721.87727315956726670265, 0.99848548653821667109 }, + { 349898.53691851865733042359, 161.45195469952594180540, 161.44322493621118042029, 349721.87728093314217403531, 0.99848548652432367323 }, + { 349898.53644461580552160740, 161.45195534985634822078, 161.44322558687019864010, 349721.87595040485030040145, 0.99848548653585678103 }, + { 349894.27001174906035885215, 161.45245862756033261576, 161.44372886423073509832, 349720.85020991315832361579, 0.99848549544738174344 } + }, { + { 1, -1 },{ 2, 0 }, + { 156899.56829134028521366417, 45.19676732164486310239, 45.18804022935886877121, 156883.63778222308610565960, 0.99969540695122460772 }, + { 156899.56827460310887545347, 45.19676732162573529195, 45.18804022933975517162, 156883.63778401838499121368, 0.99969540695121617002 }, + { 156899.56792193598812445998, 45.19676624219878391386, 45.18803915024158612823, 156883.63480984268244355917, 0.99969540696276681935 }, + { 156897.79947260793414898217, 45.19644594033049145310, 45.18771884804951355363, 156882.75281389255542308092, 0.99969541038810816325 } + }, { + { 1, -1 },{ 2, 2 }, + { 349898.53698544885264709592, 18.54804530050607525027, 18.55677506382081531910, 349721.87727315956726670265, 0.99848548653821667109 }, + { 349898.53691851865733042359, 18.54804530047409016902, 18.55677506378881247429, 349721.87728093314217403531, 0.99848548652432367323 }, + { 349898.53644461580552160740, 18.54804465014367664821, 18.55677441312981201804, 349721.87595040485030040145, 0.99848548653585678103 }, + { 349894.27001174906035885215, 18.54754137243966738424, 18.55627113576925424354, 349720.85020991315832361579, 0.99848549544738174344 } + }, { + { 1, -1 },{ 0, 2 }, + { 349898.53698544885264709592, -18.54804530050607525027, -18.55677506382081531910, 349721.87727315956726670265, 0.99848548653821667109 }, + { 349898.53691851865733042359, -18.54804530047409016902, -18.55677506378881247429, 349721.87728093314217403531, 0.99848548652432367323 }, + { 349898.53644461580552160740, -18.54804465014367664821, -18.55677441312981201804, 349721.87595040485030040145, 0.99848548653585678103 }, + { 349894.27001174906035885215, -18.54754137243966738424, -18.55627113576928266525, 349720.85020991315832361579, 0.99848549544738174344 } + }, { + { 1, -1 },{ -2, 2 }, + { 470675.27496387914288789034, -45.18799532476352709409, -45.21418997011227247640, 470245.32092262554215267301, 0.99726004843767979136 }, + { 470675.27491378918057307601, -45.18799532474472613330, -45.21418997009345730476, 470245.32093124865787103772, 0.99726004841255500022 }, + { 470675.27385581465205177665, -45.18799424651773932737, -45.21418889088011638933, 470245.31203990196809172630, 0.99726004851631100401 }, + { 470669.97387331607751548290, -45.18767381182056652733, -45.21386845703356271997, 470242.67608062445651739836, 0.99726007931332938394 } + }, { + { 1, -1 },{ -2, 0 }, + { 351772.23553088010521605611, -71.69677339271241578444, -71.67058676207953737958, 351592.72256732499226927757, 0.99846922689201267342 }, + { 351772.23552330053644254804, -71.69677339270522509196, -71.67058676207236089795, 351592.72256738768192008138, 0.99846922689200567902 }, + { 351772.23547190619865432382, -71.69677274795323285161, -71.67058611830736936099, 351592.71064292214578017592, 0.99846922699591911243 }, + { 351771.13000385620398446918, -71.69688960494077889507, -71.67070297450322868826, 351594.87308142206165939569, 0.99846920815167106156 } + }, { + { 1, -1 },{ -2, -2 }, + { 351676.50043935602298006415, -108.36087395536006283692, -108.28232205125480902552, 351497.13544799503870308399, 0.99847006808788085763 }, + { 351676.50037266127765178680, -108.36087395536665667350, -108.28232205126143128382, 351497.13543194788508117199, 0.99847006821303718738 }, + { 351676.50038040406070649624, -108.36087459655152542837, -108.28232269539881826859, 351497.12354394845897331834, 0.99847006831660412018 }, + { 351675.39839278126601129770, -108.36075825022818719390, -108.28220634670809374711, 351499.26940269087208434939, 0.99847004976658149111 } + }, { + { 1, -1 },{ 0, -2 }, + { 156876.14940188667969778180, -134.82952991582811819171, -134.80335129773999369718, 156860.22615479407249949872, 0.99969549952259184611 }, + { 156876.14925185780157335103, -134.82952991584656388113, -134.80335129775846780831, 156860.22615983051946386695, 0.99969549954768643918 }, + { 156876.14903264911845326424, -134.82953099167991695140, -134.80335237457535413341, 156860.22319510785746388137, 0.99969549955919845274 }, + { 156874.38594904550700448453, -134.82985169207830722371, -134.80367307400518939176, 156859.34477911840076558292, 0.99969550299904519353 } + }, { + { 1, -1 },{ 2, -2 }, + { 156876.14940188667969778180, 134.82952991582811819171, 134.80335129773999369718, 156860.22615479407249949872, 0.99969549952259184611 }, + { 156876.14925185780157335103, 134.82952991584656388113, 134.80335129775846780831, 156860.22615983051946386695, 0.99969549954768643918 }, + { 156876.14903264911845326424, 134.82953099167994537311, 134.80335237457538255512, 156860.22319510785746388137, 0.99969549955919856377 }, + { 156874.38594904550700448453, 134.82985169207830722371, 134.80367307400518939176, 156859.34477911840076558292, 0.99969550299904519353 } + } +}; + +size_t const expected_size = sizeof(expected) / sizeof(expected_results); + +#endif // BOOST_GEOMETRY_TEST_INVERSE_CASES_HPP diff --git a/test/formulas/test_formula.hpp b/test/formulas/test_formula.hpp new file mode 100644 index 000000000..92f690bd3 --- /dev/null +++ b/test/formulas/test_formula.hpp @@ -0,0 +1,59 @@ +// Boost.Geometry +// Unit Test + +// Copyright (c) 2016 Oracle and/or its affiliates. + +// 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_TEST_FORMULA_HPP +#define BOOST_GEOMETRY_TEST_FORMULA_HPP + +#include + +#include + +void normalize_deg(double & deg) +{ + while (deg > 180.0) + deg -= 360.0; + while (deg <= -180.0) + deg += 360.0; +} + +void check_one(double result, double expected, double reference, double reference_error, bool normalize = false) +{ + if (normalize) + { + normalize_deg(result); + normalize_deg(expected); + normalize_deg(reference); + } + + double res_max = (std::max)(bg::math::abs(result), bg::math::abs(expected)); + if (res_max > 100 * std::numeric_limits::epsilon()) + { + BOOST_CHECK_CLOSE(result, expected, 0.001); + } + else if (res_max > 10 * std::numeric_limits::epsilon()) + { + BOOST_CHECK_CLOSE(result, expected, 0.1); + } + else if (res_max > std::numeric_limits::epsilon()) + { + BOOST_CHECK_CLOSE(result, expected, 10); + } + + // NOTE: in some cases it probably will be necessary to normalize + // the differences between the result and expected result + double ref_diff = bg::math::abs(result - reference); + double ref_max = (std::max)(bg::math::abs(result), bg::math::abs(reference)); + bool is_ref_close = ref_diff <= reference_error || ref_diff <= reference_error * ref_max; + + BOOST_CHECK_MESSAGE((is_ref_close), std::setprecision(16) << "{" << result << "} and {" << reference << "} not close enough."); +} + +#endif // BOOST_GEOMETRY_TEST_FORMULA_HPP diff --git a/test/geometries/adapted.cpp b/test/geometries/adapted.cpp index 4dd8c8923..173314396 100644 --- a/test/geometries/adapted.cpp +++ b/test/geometries/adapted.cpp @@ -61,11 +61,11 @@ template void test_geometry(G const& geometry, std::size_t expected_size = 0) { #if defined(BOOST_GEOMETRY_TEST_RING) - BOOST_CONCEPT_ASSERT( (bg::concept::ConstRing) ); + BOOST_CONCEPT_ASSERT( (bg::concepts::ConstRing) ); #elif defined(BOOST_GEOMETRY_TEST_MULTI_POINT) - BOOST_CONCEPT_ASSERT( (bg::concept::ConstMultiPoint) ); + BOOST_CONCEPT_ASSERT( (bg::concepts::ConstMultiPoint) ); #else - BOOST_CONCEPT_ASSERT( (bg::concept::ConstLinestring) ); + BOOST_CONCEPT_ASSERT( (bg::concepts::ConstLinestring) ); #endif typedef typename bg::point_type::type P; diff --git a/test/geometries/boost_polygon.cpp b/test/geometries/boost_polygon.cpp index 42dc2c5a8..c535b22d1 100644 --- a/test/geometries/boost_polygon.cpp +++ b/test/geometries/boost_polygon.cpp @@ -73,7 +73,7 @@ template void test_coordinate_type() { // 1a: Check if Boost.Polygon's point fulfills Boost.Geometry's point concept - bg::concept::check >(); + bg::concepts::check >(); // 1b: use a Boost.Polygon point in Boost.Geometry, calc. distance with two point types boost::polygon::point_data boost_polygon_point(1, 2); @@ -84,7 +84,7 @@ void test_coordinate_type() 2 * std::sqrt(2.0)); // 2a: Check if Boost.Polygon's box fulfills Boost.Geometry's box concept - bg::concept::check >(); + bg::concepts::check >(); // 2b: use a Boost.Polygon rectangle in Boost.Geometry, compare with boxes boost::polygon::rectangle_data boost_polygon_box; @@ -99,7 +99,7 @@ void test_coordinate_type() BOOST_CHECK_EQUAL(boost_polygon_area, boost_polygon_area_by_boost_polygon); // 3a: Check if Boost.Polygon's polygon fulfills Boost.Geometry's ring concept - bg::concept::check >(); + bg::concepts::check >(); // 3b: use a Boost.Polygon polygon (ring) boost::polygon::polygon_data boost_polygon_ring; diff --git a/test/geometries/concepts/check.cpp b/test/geometries/concepts/check.cpp index c4996a7a5..07b344295 100644 --- a/test/geometries/concepts/check.cpp +++ b/test/geometries/concepts/check.cpp @@ -71,6 +71,6 @@ template <> struct access int main() { - bg::concept::check(); - bg::concept::check(); + bg::concepts::check(); + bg::concepts::check(); } diff --git a/test/geometries/custom_linestring.cpp b/test/geometries/custom_linestring.cpp index 35315503a..66feef665 100644 --- a/test/geometries/custom_linestring.cpp +++ b/test/geometries/custom_linestring.cpp @@ -80,8 +80,8 @@ namespace boost { namespace geometry { namespace traits { template void test_linestring() { - BOOST_CONCEPT_ASSERT( (bg::concept::Linestring) ); - BOOST_CONCEPT_ASSERT( (bg::concept::ConstLinestring) ); + BOOST_CONCEPT_ASSERT( (bg::concepts::Linestring) ); + BOOST_CONCEPT_ASSERT( (bg::concepts::ConstLinestring) ); G geometry; typedef typename bg::point_type::type P; diff --git a/test/geometries/segment.cpp b/test/geometries/segment.cpp index c6cef3e10..dcbb2ed18 100644 --- a/test/geometries/segment.cpp +++ b/test/geometries/segment.cpp @@ -49,8 +49,8 @@ void test_all() BOOST_CHECK_EQUAL(&s.second, &p2); // Compilation tests, all things should compile. - BOOST_CONCEPT_ASSERT( (bg::concept::ConstSegment) ); - BOOST_CONCEPT_ASSERT( (bg::concept::Segment) ); + BOOST_CONCEPT_ASSERT( (bg::concepts::ConstSegment) ); + BOOST_CONCEPT_ASSERT( (bg::concepts::Segment) ); typedef typename bg::coordinate_type::type T; typedef typename bg::point_type::type SP; @@ -59,7 +59,7 @@ void test_all() //std::cout << sizeof(typename coordinate_type::type) << std::endl; typedef bg::model::referring_segment

refseg_t; - //BOOST_CONCEPT_ASSERT( (concept::ConstSegment) ); + //BOOST_CONCEPT_ASSERT( (concepts::ConstSegment) ); refseg_t seg(p1, p2); diff --git a/test/strategies/andoyer.cpp b/test/strategies/andoyer.cpp index 271d593c5..01b31c73d 100644 --- a/test/strategies/andoyer.cpp +++ b/test/strategies/andoyer.cpp @@ -79,7 +79,7 @@ void test_distance(double lon1, double lat1, double lon2, double lat2, double ex BOOST_CONCEPT_ASSERT ( - (bg::concept::PointDistanceStrategy) + (bg::concepts::PointDistanceStrategy) ); andoyer_type andoyer; diff --git a/test/strategies/cross_track.cpp b/test/strategies/cross_track.cpp index 1b02c8835..861251e4e 100644 --- a/test/strategies/cross_track.cpp +++ b/test/strategies/cross_track.cpp @@ -83,7 +83,7 @@ void test_distance( BOOST_CONCEPT_ASSERT ( - (bg::concept::PointSegmentDistanceStrategy) + (bg::concepts::PointSegmentDistanceStrategy) ); diff --git a/test/strategies/haversine.cpp b/test/strategies/haversine.cpp index 9aaae3386..b6853954d 100644 --- a/test/strategies/haversine.cpp +++ b/test/strategies/haversine.cpp @@ -43,7 +43,7 @@ struct test_distance BOOST_CONCEPT_ASSERT ( - (bg::concept::PointDistanceStrategy) + (bg::concepts::PointDistanceStrategy) ); diff --git a/test/strategies/pythagoras.cpp b/test/strategies/pythagoras.cpp index 3b81bf144..de1101e46 100644 --- a/test/strategies/pythagoras.cpp +++ b/test/strategies/pythagoras.cpp @@ -145,7 +145,7 @@ void test_services() typedef bgsd::pythagoras strategy_type; - BOOST_CONCEPT_ASSERT( (bg::concept::PointDistanceStrategy) ); + BOOST_CONCEPT_ASSERT( (bg::concepts::PointDistanceStrategy) ); typedef typename bgsd::services::return_type::type return_type; diff --git a/test/strategies/pythagoras_point_box.cpp b/test/strategies/pythagoras_point_box.cpp index 9b1e817f3..31810e1cb 100644 --- a/test/strategies/pythagoras_point_box.cpp +++ b/test/strategies/pythagoras_point_box.cpp @@ -206,7 +206,7 @@ inline void test_services() typedef bgsd::pythagoras_point_box strategy_type; BOOST_CONCEPT_ASSERT - ( (bg::concept::PointDistanceStrategy) ); + ( (bg::concepts::PointDistanceStrategy) ); typedef typename bgsd::services::return_type < diff --git a/test/strategies/test_projected_point.hpp b/test/strategies/test_projected_point.hpp index 0abde3ced..72a0d906d 100644 --- a/test/strategies/test_projected_point.hpp +++ b/test/strategies/test_projected_point.hpp @@ -81,7 +81,7 @@ void test_services() typedef bgsd::projected_point strategy_type; - BOOST_CONCEPT_ASSERT( (bg::concept::PointSegmentDistanceStrategy) ); + BOOST_CONCEPT_ASSERT( (bg::concepts::PointSegmentDistanceStrategy) ); typedef typename services::return_type::type return_type; @@ -140,11 +140,11 @@ void test_2d(std::string const& wkt_p, BOOST_CONCEPT_ASSERT ( - (bg::concept::PointSegmentDistanceStrategy) + (bg::concepts::PointSegmentDistanceStrategy) ); BOOST_CONCEPT_ASSERT ( - (bg::concept::PointSegmentDistanceStrategy) + (bg::concepts::PointSegmentDistanceStrategy) ); { diff --git a/test/strategies/test_within.hpp b/test/strategies/test_within.hpp index 4ceb2608e..d47080ccf 100644 --- a/test/strategies/test_within.hpp +++ b/test/strategies/test_within.hpp @@ -72,7 +72,7 @@ void test_point_in_polygon(std::string const& case_id, bool expected, bool use_within = true) { - BOOST_CONCEPT_ASSERT( (bg::concept::WithinStrategyPolygonal) ); + BOOST_CONCEPT_ASSERT( (bg::concepts::WithinStrategyPolygonal) ); bool detected = use_within ? bg::within(point, polygon, strategy) : bg::covered_by(point, polygon, strategy); diff --git a/test/strategies/thomas.cpp b/test/strategies/thomas.cpp index cac10ac51..5770dc0b1 100644 --- a/test/strategies/thomas.cpp +++ b/test/strategies/thomas.cpp @@ -52,7 +52,7 @@ void test_distance(double lon1, double lat1, double lon2, double lat2, double ex BOOST_CONCEPT_ASSERT ( - (bg::concept::PointDistanceStrategy) + (bg::concepts::PointDistanceStrategy) ); thomas_type thomas; diff --git a/test/strategies/vincenty.cpp b/test/strategies/vincenty.cpp index 64f150f1d..b3b17936b 100644 --- a/test/strategies/vincenty.cpp +++ b/test/strategies/vincenty.cpp @@ -169,7 +169,7 @@ void test_vincenty(double lon1, double lat1, double lon2, double lat2, BOOST_CONCEPT_ASSERT( ( - bg::concept::PointDistanceStrategy) + bg::concepts::PointDistanceStrategy) ); vincenty_type vincenty(spheroid); From 7234ce7cabebfc7d2be46f99072ea4ff316b4eff Mon Sep 17 00:00:00 2001 From: Vissarion Fysikopoulos Date: Tue, 16 Aug 2016 18:28:50 +0300 Subject: [PATCH 10/89] [area] [test] Tests for different strategies of geographic area. --- test/algorithms/area/Jamfile.v2 | 4 +- test/algorithms/area/area.cpp | 397 ++----------------------- test/algorithms/area/area_geo.cpp | 310 ++++++++++++++++++++ test/algorithms/area/area_sph_geo.cpp | 403 ++++++++++++++++++++++++++ 4 files changed, 747 insertions(+), 367 deletions(-) create mode 100644 test/algorithms/area/area_geo.cpp create mode 100644 test/algorithms/area/area_sph_geo.cpp diff --git a/test/algorithms/area/Jamfile.v2 b/test/algorithms/area/Jamfile.v2 index 0e2fa53e7..f3c868da7 100644 --- a/test/algorithms/area/Jamfile.v2 +++ b/test/algorithms/area/Jamfile.v2 @@ -8,9 +8,11 @@ # Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) -test-suite boost-geometry-algorithms-length +test-suite boost-geometry-algorithms-area : [ run area.cpp : : : : algorithms_area ] + [ run area_sph_geo.cpp : : : : algorithms_area_sph_geo ] + [ run area_geo.cpp : : : : algorithms_area_geo ] [ run area_multi.cpp : : : : algorithms_area_multi ] ; diff --git a/test/algorithms/area/area.cpp b/test/algorithms/area/area.cpp index d92d9e41c..8488765d7 100644 --- a/test/algorithms/area/area.cpp +++ b/test/algorithms/area/area.cpp @@ -82,369 +82,6 @@ void test_all() } } -template -void test_spherical_geo() -{ - typedef CT ct; - - //Geographic - - typedef typename bg::model::point< - ct, - 2, - bg::cs::geographic - > pt_geo; - - typedef typename bg::point_type::type pt_geo_type; - - typedef typename bg::formula::vincenty_inverse - < - ct, - false, - true, - true - > geo_strategy; - - bg::strategy::area::area_geographic - < - pt_geo_type, - geo_strategy, - 5, - true - > area_geographic; - - bg::model::polygon geometry_geo; - - //Spherical - - typedef typename bg::model::point< - ct, - 2, - bg::cs::spherical_equatorial - > pt; - bg::model::polygon geometry; - - // unit-sphere has area of 4-PI. Polygon covering 1/8 of it: - // calculations splitted for ttmath - std::string poly = "POLYGON((0 0,0 90,90 0,0 0))"; - - ct const four = 4.0; - ct const eight = 8.0; - ct expected = four * boost::geometry::math::pi() / eight; - bg::read_wkt(poly, geometry); - ct area = bg::area(geometry); - BOOST_CHECK_CLOSE(area, expected, 0.0001); - - // With strategy, radius 2 -> 4 pi r^2 - bg::strategy::area::area_spherical - < - typename bg::point_type::type - > strategy(2.0); - - area = bg::area(geometry, strategy); - ct const two = 2.0; - BOOST_CHECK_CLOSE(area, two * two * expected, 0.0001); - - // Geographic total area of earth is about 510072000 - // (https://en.wikipedia.org/wiki/Earth) - // So the 1/8 is 63759000 and here we get something close to it - bg::read_wkt(poly, geometry_geo); - area = bg::area(geometry_geo, area_geographic); - //GeoGraphicLib gives: 63758202715511.055 - BOOST_CHECK_CLOSE(area, 63758202715509.859, 0.0001); - - - // Wrangel Island (dateline crossing) - // With (spherical) Earth strategy - poly = "POLYGON((-178.7858 70.7852, 177.4758 71.2333, 179.7436 71.5733, -178.7858 70.7852))"; - - bg::strategy::area::area_spherical - < - typename bg::point_type::type - > spherical_earth(6373); - bg::read_wkt(poly, geometry); - area = bg::area(geometry, spherical_earth); - // SQL Server gives: 4537.9654419375 - // PostGIS gives: 4537.9311668307 - // Note: those are Geographic, this test is Spherical - BOOST_CHECK_CLOSE(area, 4506.6389, 0.001); - - bg::read_wkt(poly, geometry_geo); - area = bg::area(geometry_geo, area_geographic); - BOOST_CHECK_CLOSE(area, 4537974350.6843719, 0.0001); - - // Wrangel, more in detail - poly = "POLYGON((-178.568604 71.564148,-178.017548 71.449692,-177.833313 71.3461,\ - -177.502838 71.277466 ,-177.439453 71.226929,-177.620026 71.116638,\ - -177.9389 71.037491,-178.8186 70.979965,-179.274445 70.907761,\ - -180 70.9972,179.678314 70.895538,179.272766 70.888596,\ - 178.791016 70.7964,178.617737 71.035538,178.872192 71.217484,\ - 179.530273 71.4383 ,-180 71.535843 ,-179.628601 71.577194,\ - -179.305298 71.551361,-179.03421 71.597748,-178.568604 71.564148))"; - bg::read_wkt(poly, geometry); - area = bg::area(geometry, spherical_earth); - // SQL Server gives: 7669.10402181435 - // PostGIS gives: 7669.55565459832 - BOOST_CHECK_CLOSE(area, 7616.523769, 0.001); - - bg::read_wkt(poly, geometry_geo); - area = bg::area(geometry_geo, area_geographic); - BOOST_CHECK_CLOSE(area, 7669498457.4130802, 0.0001); - - // Check more at the equator - /* - select 1,geography::STGeomFromText('POLYGON((-178.7858 10.7852 , 179.7436 11.5733 , 177.4758 11.2333 , -178.7858 10.7852))',4326) .STArea()/1000000.0 - union select 2,geography::STGeomFromText('POLYGON((-178.7858 20.7852 , 179.7436 21.5733 , 177.4758 21.2333 , -178.7858 20.7852))',4326) .STArea()/1000000.0 - union select 3,geography::STGeomFromText('POLYGON((-178.7858 30.7852 , 179.7436 31.5733 , 177.4758 31.2333 , -178.7858 30.7852))',4326) .STArea()/1000000.0 - union select 0,geography::STGeomFromText('POLYGON((-178.7858 0.7852 , 179.7436 1.5733 , 177.4758 1.2333 , -178.7858 0.7852))',4326) .STArea()/1000000.0 - union select 4,geography::STGeomFromText('POLYGON((-178.7858 40.7852 , 179.7436 41.5733 , 177.4758 41.2333 , -178.7858 40.7852))',4326) .STArea()/1000000.0 - */ - - poly = "POLYGON((-178.7858 0.7852, 177.4758 1.2333, 179.7436 1.5733, -178.7858 0.7852))"; - bg::read_wkt(poly, geometry); - area = bg::area(geometry, spherical_earth); - BOOST_CHECK_CLOSE(area, 14136.09946, 0.001); // SQL Server gives: 14064.1902284513 - bg::read_wkt(poly, geometry_geo); - area = bg::area(geometry_geo, area_geographic); - BOOST_CHECK_CLOSE(area, 14064196647.560314, 0.0001); - - poly = "POLYGON((-178.7858 10.7852, 177.4758 11.2333, 179.7436 11.5733, -178.7858 10.7852))"; - bg::read_wkt(poly, geometry); - area = bg::area(geometry, spherical_earth); - BOOST_CHECK_CLOSE(area, 13760.2456, 0.001); // SQL Server gives: 13697.0941155193 - bg::read_wkt(poly, geometry_geo); - area = bg::area(geometry_geo, area_geographic); - BOOST_CHECK_CLOSE(area, 13697095227.008451, 0.0001); - - poly = "POLYGON((-178.7858 20.7852, 177.4758 21.2333, 179.7436 21.5733, -178.7858 20.7852))"; - bg::read_wkt(poly, geometry); - area = bg::area(geometry, spherical_earth); - BOOST_CHECK_CLOSE(area, 12987.8682, 0.001); // SQL Server gives: 12944.3970990317 -> -39m^2 - bg::read_wkt(poly, geometry_geo); - area = bg::area(geometry_geo, area_geographic); - BOOST_CHECK_CLOSE(area, 12944392155.546635, 0.0001); - - poly = "POLYGON((-178.7858 30.7852, 177.4758 31.2333, 179.7436 31.5733, -178.7858 30.7852))"; - bg::read_wkt(poly, geometry); - area = bg::area(geometry, spherical_earth); - BOOST_CHECK_CLOSE(area, 11856.3935, 0.001); // SQL Server gives: 11838.5338423574 -> -18m^2 - bg::read_wkt(poly, geometry_geo); - area = bg::area(geometry_geo, area_geographic); - BOOST_CHECK_CLOSE(area, 11838524075.970982, 0.0001); - - poly = "POLYGON((-178.7858 40.7852, 177.4758 41.2333, 179.7436 41.5733, -178.7858 40.7852))"; - bg::read_wkt(poly, geometry); - area = bg::area(geometry, spherical_earth); - BOOST_CHECK_CLOSE(area, 10404.627685523914, 0.001); // SQL Server gives: 10412.0607137119, -> +8m^2 - bg::read_wkt(poly, geometry_geo); - area = bg::area(geometry_geo, area_geographic); - BOOST_CHECK_CLOSE(area, 10412049661.81769, 0.0001); - - // Concave - poly = "POLYGON((0 40,1 42,0 44,2 43,4 44,3 42,4 40,2 41,0 40))"; - bg::read_wkt(poly, geometry); - area = bg::area(geometry, spherical_earth); - BOOST_CHECK_CLOSE(area, 73538.2958, 0.001); // SQL Server gives: 73604.2047689719 - bg::read_wkt(poly, geometry_geo); - area = bg::area(geometry_geo, area_geographic); - BOOST_CHECK_CLOSE(area, 73604208172.719223, 0.0001); - - // With hole POLYGON((0 40,4 40,4 44,0 44,0 40),(1 41,2 43,3 42,1 41)) - poly = "POLYGON((0 40,0 44,4 44,4 40,0 40),(1 41,3 42,2 43,1 41))"; - bg::read_wkt(poly, geometry); - area = bg::area(geometry, spherical_earth); - BOOST_CHECK_CLOSE(area, 133233.844876, 0.001); // SQL Server gives: 133353.335 - bg::read_wkt(poly, geometry_geo); - area = bg::area(geometry_geo, area_geographic); - BOOST_CHECK_CLOSE(area, 133353331647.58241, 0.0001); - - // around 0 meridian - { - std::string poly1 = "POLYGON((-10 0,-10 10,0 10,0 0,-10 0))"; - std::string poly2 = "POLYGON((0 0,0 10,10 10,10 0,0 0))"; - std::string poly3 = "POLYGON((-5 0,-5 10,5 10,5 0,-5 0))"; - bg::read_wkt(poly1, geometry); - ct area1 = bg::area(geometry); - bg::read_wkt(poly2, geometry); - ct area2 = bg::area(geometry); - bg::read_wkt(poly3, geometry); - ct area3 = bg::area(geometry); - BOOST_CHECK_CLOSE(area1, area2, 0.001); - BOOST_CHECK_CLOSE(area2, area3, 0.001); - BOOST_CHECK_CLOSE(area1, 0.0303822, 0.001); - //geographic - bg::read_wkt(poly1, geometry_geo); - area1 = bg::area(geometry_geo, area_geographic); - bg::read_wkt(poly2, geometry_geo); - area2 = bg::area(geometry_geo, area_geographic); - bg::read_wkt(poly3, geometry_geo); - area3 = bg::area(geometry_geo, area_geographic); - BOOST_CHECK_CLOSE(area1, area2, 0.001); - BOOST_CHECK_CLOSE(area2, area3, 0.001); - BOOST_CHECK_CLOSE(area1, 1227857282668.3145, 0.001); - } - { - std::string poly1 = "POLYGON((-10 -5,-10 5,0 5,0 -5,-10 -5))"; - std::string poly2 = "POLYGON((0 -5,0 5,10 5,10 -5,0 -5))"; - std::string poly3 = "POLYGON((-5 -5,-5 5,5 5,5 -5,-5 -5))"; - bg::read_wkt(poly1, geometry); - ct area1 = bg::area(geometry); - bg::read_wkt(poly2, geometry); - ct area2 = bg::area(geometry); - bg::read_wkt(poly3, geometry); - ct area3 = bg::area(geometry); - BOOST_CHECK_CLOSE(area1, area2, 0.001); - BOOST_CHECK_CLOSE(area2, area3, 0.001); - BOOST_CHECK_CLOSE(area1, 0.0305, 0.001); - //geographic - bg::read_wkt(poly1, geometry_geo); - area1 = bg::area(geometry_geo, area_geographic); - bg::read_wkt(poly2, geometry_geo); - area2 = bg::area(geometry_geo, area_geographic); - bg::read_wkt(poly3, geometry_geo); - area3 = bg::area(geometry_geo, area_geographic); - BOOST_CHECK_CLOSE(area1, area2, 0.001); - BOOST_CHECK_CLOSE(area2, area3, 0.001); - BOOST_CHECK_CLOSE(area1, 1232493707152.2292, 0.001); - } - // around 180 meridian - { - std::string poly1 = "POLYGON((-180 0,-180 10,-170 10,-170 0,-180 0))"; - std::string poly2 = "POLYGON((175 0,175 10,-175 10,-175 0,175 0))"; - std::string poly3 = "POLYGON((170 0,170 10,180 10,180 0,170 0))"; - std::string poly4 = "POLYGON((170 0,170 10,-180 10,-180 0,170 0))"; - std::string poly5 = "POLYGON((180 0,180 10,-170 10,-170 0,180 0))"; - bg::read_wkt(poly1, geometry); - ct area1 = bg::area(geometry); - bg::read_wkt(poly2, geometry); - ct area2 = bg::area(geometry); - bg::read_wkt(poly3, geometry); - ct area3 = bg::area(geometry); - bg::read_wkt(poly4, geometry); - ct area4 = bg::area(geometry); - bg::read_wkt(poly5, geometry); - ct area5 = bg::area(geometry); - BOOST_CHECK_CLOSE(area1, area2, 0.001); - BOOST_CHECK_CLOSE(area2, area3, 0.001); - BOOST_CHECK_CLOSE(area3, area4, 0.001); - BOOST_CHECK_CLOSE(area4, area5, 0.001); - BOOST_CHECK_CLOSE(area1, 0.0303822, 0.001); - //geographic - bg::read_wkt(poly1, geometry_geo); - area1 = bg::area(geometry_geo, area_geographic); - bg::read_wkt(poly2, geometry_geo); - area2 = bg::area(geometry_geo, area_geographic); - bg::read_wkt(poly3, geometry_geo); - area3 = bg::area(geometry_geo, area_geographic); - bg::read_wkt(poly4, geometry_geo); - area4 = bg::area(geometry_geo, area_geographic); - bg::read_wkt(poly5, geometry_geo); - area5 = bg::area(geometry_geo, area_geographic); - BOOST_CHECK_CLOSE(area1, area2, 0.001); - BOOST_CHECK_CLOSE(area2, area3, 0.001); - BOOST_CHECK_CLOSE(area3, area4, 0.001); - BOOST_CHECK_CLOSE(area4, area5, 0.001); - BOOST_CHECK_CLOSE(area1, 1227857282668.313, 0.001); - } - { - std::string poly1 = "POLYGON((-180 -5,-180 5,-170 5,-170 -5,-180 -5))"; - std::string poly2 = "POLYGON((175 -5,175 5,-175 5,-175 -5,175 -5))"; - std::string poly3 = "POLYGON((170 -5,170 5,180 5,180 -5,170 -5))"; - std::string poly4 = "POLYGON((170 -5,170 5,180 5,180 -5,170 -5))"; - std::string poly5 = "POLYGON((180 -5,180 5,-170 5,-170 -5,180 -5))"; - bg::read_wkt(poly1, geometry); - ct area1 = bg::area(geometry); - bg::read_wkt(poly2, geometry); - ct area2 = bg::area(geometry); - bg::read_wkt(poly3, geometry); - ct area3 = bg::area(geometry); - bg::read_wkt(poly4, geometry); - ct area4 = bg::area(geometry); - bg::read_wkt(poly5, geometry); - ct area5 = bg::area(geometry); - BOOST_CHECK_CLOSE(area1, area2, 0.001); - BOOST_CHECK_CLOSE(area2, area3, 0.001); - BOOST_CHECK_CLOSE(area3, area4, 0.001); - BOOST_CHECK_CLOSE(area4, area5, 0.001); - BOOST_CHECK_CLOSE(area1, 0.0305, 0.001); - //geographic - bg::read_wkt(poly1, geometry_geo); - area1 = bg::area(geometry_geo, area_geographic); - bg::read_wkt(poly2, geometry_geo); - area2 = bg::area(geometry_geo, area_geographic); - bg::read_wkt(poly3, geometry_geo); - area3 = bg::area(geometry_geo, area_geographic); - bg::read_wkt(poly4, geometry_geo); - area4 = bg::area(geometry_geo, area_geographic); - bg::read_wkt(poly5, geometry_geo); - area5 = bg::area(geometry_geo, area_geographic); - BOOST_CHECK_CLOSE(area1, area2, 0.001); - BOOST_CHECK_CLOSE(area2, area3, 0.001); - BOOST_CHECK_CLOSE(area3, area4, 0.001); - BOOST_CHECK_CLOSE(area4, area5, 0.001); - BOOST_CHECK_CLOSE(area1, 1232493707152.2278, 0.001); - } - // around poles - { - std::string poly1 = "POLYGON((0 80,-90 80,-180 80,90 80,0 80))"; - std::string poly2 = "POLYGON((0 80,-90 80,180 80,90 80,0 80))"; - std::string poly3 = "POLYGON((0 -80,90 -80,-180 -80,-90 -80,0 -80))"; - std::string poly4 = "POLYGON((0 -80,90 -80,180 -80,-90 -80,0 -80))"; - bg::read_wkt(poly1, geometry); - ct area1 = bg::area(geometry); - bg::read_wkt(poly2, geometry); - ct area2 = bg::area(geometry); - bg::read_wkt(poly3, geometry); - ct area3 = bg::area(geometry); - bg::read_wkt(poly4, geometry); - ct area4 = bg::area(geometry); - BOOST_CHECK_CLOSE(area1, area2, 0.001); - BOOST_CHECK_CLOSE(area2, area3, 0.001); - BOOST_CHECK_CLOSE(area3, area4, 0.001); - //geographic - bg::read_wkt(poly1, geometry_geo); - area1 = bg::area(geometry_geo, area_geographic); - bg::read_wkt(poly2, geometry_geo); - area2 = bg::area(geometry_geo, area_geographic); - bg::read_wkt(poly3, geometry_geo); - area3 = bg::area(geometry_geo, area_geographic); - bg::read_wkt(poly4, geometry_geo); - area4 = bg::area(geometry_geo, area_geographic); - BOOST_CHECK_CLOSE(area1, area2, 0.001); - BOOST_CHECK_CLOSE(area2, area3, 0.001); - BOOST_CHECK_CLOSE(area3, area4, 0.001); - } - - { - bg::model::ring aurha; // a'dam-utr-rott.-den haag-a'dam - std::string poly = "POLYGON((4.892 52.373,5.119 52.093,4.479 51.930,4.23 52.08,4.892 52.373))"; - bg::read_wkt(poly, aurha); - /*if (polar) - { - // Create colatitudes (measured from pole) - BOOST_FOREACH(pt& p, aurha) - { - bg::set<1>(p, ct(90) - bg::get<1>(p)); - } - bg::correct(aurha); - }*/ - bg::strategy::area::area_spherical - < - typename bg::point_type::type - > area_spherical(6372.795); - area = bg::area(aurha, area_spherical); - BOOST_CHECK_CLOSE(area, 1476.645675, 0.0001); - //geographic - bg::read_wkt(poly, geometry_geo); - area = bg::area(geometry_geo, area_geographic); - BOOST_CHECK_CLOSE(area, 1481555970.0765088, 0.001); - - // SQL Server gives: 1481.55595960659 - // for select geography::STGeomFromText('POLYGON((4.892 52.373,4.23 52.08,4.479 51.930,5.119 52.093,4.892 52.373))',4326).STArea()/1000000.0 - } - -} - template void test_ccw() { @@ -484,6 +121,29 @@ void test_open_ccw(CT expected_area) // Note the triangular testcase used in CCW is not sensible for open/close } +template +void test_poles_ccw() +{ + typedef typename bg::coordinate_type

::type ct; + bg::model::polygon polygon; + + std::string poly1 = "POLYGON((45 45,45 95,95 45,45 45))"; + std::string poly2 = "POLYGON((45 45,95 45,45 95,45 45))"; + std::string poly3 = "POLYGON((45 -45,45 -95,95 -45,45 -45))"; + std::string poly4 = "POLYGON((45 -45,95 -45,45 -95,45 -45))"; + + bg::read_wkt(poly1, polygon); + ct area1 = bg::area(polygon); + bg::read_wkt(poly2, polygon); + ct area2 = bg::area(polygon); + bg::read_wkt(poly3, polygon); + ct area3 = bg::area(polygon); + bg::read_wkt(poly4, polygon); + ct area4 = bg::area(polygon); + BOOST_CHECK_CLOSE(area1, -1 * area2, 0.001); + BOOST_CHECK_CLOSE(area3, -1 * area4, 0.001); +} + template void test_empty_input() { @@ -502,7 +162,10 @@ void test_large_integers() bg::model::polygon int_poly; bg::model::polygon double_poly; - std::string const polygon_li = "POLYGON((1872000 528000,1872000 192000,1536119 192000,1536000 528000,1200000 528000,1200000 863880,1536000 863880,1872000 863880,1872000 528000))"; + std::string const polygon_li = "POLYGON((1872000 528000,1872000 192000,\ + 1536119 192000,1536000 528000,1200000 528000,\ + 1200000 863880,1536000 863880,1872000 863880,\ + 1872000 528000))"; bg::read_wkt(polygon_li, int_poly); bg::read_wkt(polygon_li, double_poly); @@ -541,8 +204,6 @@ int test_main(int, char* []) test_all >(); test_all >(); - test_spherical_geo(); - typedef bg::model::point pt_crt; typedef bg::model::point > pt_sph; typedef bg::model::point > pt_geo; @@ -559,6 +220,10 @@ int test_main(int, char* []) test_open_ccw(0.00060917296206278821); test_open_ccw(24615760871.487991); + test_poles_ccw(); + test_poles_ccw(); + test_poles_ccw(); + #ifdef HAVE_TTMATH test_all >(); test_spherical_geo(); diff --git a/test/algorithms/area/area_geo.cpp b/test/algorithms/area/area_geo.cpp new file mode 100644 index 000000000..9fc8bd26b --- /dev/null +++ b/test/algorithms/area/area_geo.cpp @@ -0,0 +1,310 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) +// Unit Test + +// This file was modified by Oracle on 2015, 2016. +// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates. + +// Contributed and/or modified by Vissarion Fysikopoulos, 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) + +#include +#include + +namespace bg = boost::geometry; + +//Testing geographic strategies +template +void test_geo_strategies() +{ + std::string poly = "POLYGON((52 0, 41 -74, -23 -43, -26 28, 52 0))"; + + typedef bg::model::point > pt_geo; + + typedef typename bg::point_type::type pt_geo_type; + + typedef typename bg::formula::andoyer_inverse + < + CT, + false, + true, + true + > strategy_andoyer; + + typedef typename bg::formula::thomas_inverse + < + CT, + false, + true, + true + > strategy_thomas; + + typedef typename bg::formula::vincenty_inverse + < + CT, + false, + true, + true + > strategy_vincenty; + + + bg::srs::spheroid spheroid; + + bg::strategy::area::area_geographic + geographic_default; + + bg::strategy::area::area_geographic + < + pt_geo_type, + strategy_andoyer, + 1, + true + > geographic_andoyer1; + bg::strategy::area::area_geographic + < + pt_geo_type, + strategy_andoyer, + 2, + true + > geographic_andoyer2; + bg::strategy::area::area_geographic + < + pt_geo_type, + strategy_andoyer, + 3, + true + > geographic_andoyer3; + bg::strategy::area::area_geographic + < + pt_geo_type, + strategy_andoyer, + 4, + true + > geographic_andoyer4; + bg::strategy::area::area_geographic + < + pt_geo_type, + strategy_andoyer, + 5, + true + > geographic_andoyer5; + + bg::strategy::area::area_geographic + < + pt_geo_type, + strategy_thomas, + 1, + true + > geographic_thomas1; + bg::strategy::area::area_geographic + < + pt_geo_type, + strategy_thomas, + 2, + true + > geographic_thomas2; + bg::strategy::area::area_geographic + < + pt_geo_type, + strategy_thomas, + 3, + true + > geographic_thomas3; + bg::strategy::area::area_geographic + < + pt_geo_type, + strategy_thomas, + 4, + true + > geographic_thomas4; + bg::strategy::area::area_geographic + < + pt_geo_type, + strategy_thomas, + 5, + true + > geographic_thomas5; + + bg::strategy::area::area_geographic + < + pt_geo_type, + strategy_vincenty, + 1, + true + > geographic_vincenty1; + bg::strategy::area::area_geographic + < + pt_geo_type, + strategy_vincenty, + 2, + true + > geographic_vincenty2; + bg::strategy::area::area_geographic + < + pt_geo_type, + strategy_vincenty, + 3, + true + > geographic_vincenty3; + bg::strategy::area::area_geographic + < + pt_geo_type, + strategy_vincenty, + 4, + true + > geographic_vincenty4; + bg::strategy::area::area_geographic + < + pt_geo_type, + strategy_vincenty, + 5, + true + > geographic_vincenty5; + + bg::strategy::area::area_geographic + < + pt_geo_type, + strategy_vincenty, + 5 + > geographic_vincenty5_default; + + bg::strategy::area::area_geographic + < + pt_geo_type, + strategy_vincenty + > geographic_vincenty_default; + + bg::model::polygon geometry_geo; + + //GeographicLib 63316536351834.289 + //PostGIS (v2.2.2) 6.33946+13 + //MS SQL SERVER 632930207487035 + + bg::read_wkt(poly, geometry_geo); + CT area; + CT err = 0.0000001; + + CT area_default = bg::area(geometry_geo); + BOOST_CHECK_CLOSE(area_default, 63292982057581.711, err); + area = bg::area(geometry_geo, geographic_default); + BOOST_CHECK_CLOSE(area, 63292982057581.711, err); + + CT area_less_accurate = bg::area(geometry_geo, geographic_andoyer1); + BOOST_CHECK_CLOSE(area_less_accurate, 63292982421447.312, err); + area = bg::area(geometry_geo, geographic_andoyer2); + BOOST_CHECK_CLOSE(area, 63292982299473.633, err); + area = bg::area(geometry_geo, geographic_andoyer3); + BOOST_CHECK_CLOSE(area, 63292982299578.328, err); + area = bg::area(geometry_geo, geographic_andoyer4); + BOOST_CHECK_CLOSE(area, 63292982299578.227, err); + area = bg::area(geometry_geo, geographic_andoyer5); + BOOST_CHECK_CLOSE(area, 63292982299578.227, err); + + area = bg::area(geometry_geo, geographic_thomas1); + BOOST_CHECK_CLOSE(area, 63292982179555.766, err); + area = bg::area(geometry_geo, geographic_thomas2); + BOOST_CHECK_CLOSE(area, 63292982057581.711, err); + area = bg::area(geometry_geo, geographic_thomas3); + BOOST_CHECK_CLOSE(area, 63292982057686.406, err); + area = bg::area(geometry_geo, geographic_thomas4); + BOOST_CHECK_CLOSE(area, 63292982057686.305, err); + area = bg::area(geometry_geo, geographic_thomas5); + BOOST_CHECK_CLOSE(area, 63292982057686.305, err); + + area = bg::area(geometry_geo, geographic_vincenty1); + BOOST_CHECK_CLOSE(area, 63292982178432.859, err); + area = bg::area(geometry_geo, geographic_vincenty2); + BOOST_CHECK_CLOSE(area, 63292982056458.805, err); + area = bg::area(geometry_geo, geographic_vincenty3); + BOOST_CHECK_CLOSE(area, 63292982056563.5, err); + area = bg::area(geometry_geo, geographic_vincenty4); + BOOST_CHECK_CLOSE(area, 63292982056563.398, err); + CT area_most_accurate = bg::area(geometry_geo, geographic_vincenty5); + BOOST_CHECK_CLOSE(area, 63292982056563.398, err); + + area = bg::area(geometry_geo, geographic_vincenty5_default); + BOOST_CHECK_CLOSE(area, 63292982056563.398, err); + area = bg::area(geometry_geo, geographic_vincenty_default); + BOOST_CHECK_CLOSE(area, 63292982056458.805, err); + + BOOST_CHECK_CLOSE(area_most_accurate, area_less_accurate, .000001); + BOOST_CHECK_CLOSE(area_most_accurate, area_default, .00000001); + + /* timings and accuracy + std::cout.precision(32); + { clock_t startTime = clock(); + for (int j=0; j < 100000; j++) area = bg::area(geometry_geo, geographic_andoyer1); + std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds." << std::endl; + std::cout << "area=" << area << std::endl;} + { clock_t startTime = clock(); + for (int j=0; j < 100000; j++) area = bg::area(geometry_geo, geographic_andoyer2); + std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds." << std::endl; + std::cout << "area=" << area << std::endl;} + { clock_t startTime = clock(); + for (int j=0; j < 100000; j++) area = bg::area(geometry_geo, geographic_andoyer3); + std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds." << std::endl; + std::cout << "area=" << area << std::endl;} + { clock_t startTime = clock(); + for (int j=0; j < 100000; j++) area = bg::area(geometry_geo, geographic_andoyer4); + std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds." << std::endl; + std::cout << "area=" << area << std::endl;} + { clock_t startTime = clock(); + for (int j=0; j < 100000; j++) area = bg::area(geometry_geo, geographic_andoyer5); + std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds." << std::endl; + std::cout << "area=" << area << std::endl;} + { clock_t startTime = clock(); + for (int j=0; j < 100000; j++) area = bg::area(geometry_geo, geographic_thomas1); + std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds." << std::endl; + std::cout << "area=" << area << std::endl;} + { clock_t startTime = clock(); + for (int j=0; j < 100000; j++) area = bg::area(geometry_geo, geographic_thomas2); + std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds." << std::endl; + std::cout << "area=" << area << std::endl;} + { clock_t startTime = clock(); + for (int j=0; j < 100000; j++) area = bg::area(geometry_geo, geographic_thomas3); + std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds." << std::endl; + std::cout << "area=" << area << std::endl;} + { clock_t startTime = clock(); + for (int j=0; j < 100000; j++) area = bg::area(geometry_geo, geographic_thomas4); + std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds." << std::endl; + std::cout << "area=" << area << std::endl;} + { clock_t startTime = clock(); + for (int j=0; j < 100000; j++) area = bg::area(geometry_geo, geographic_thomas5); + std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds." << std::endl; + std::cout << "area=" << area << std::endl;} + { clock_t startTime = clock(); + for (int j=0; j < 100000; j++) area = bg::area(geometry_geo, geographic_vincenty1); + std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds." << std::endl; + std::cout << "area=" << area << std::endl;} + { clock_t startTime = clock(); + for (int j=0; j < 100000; j++) area = bg::area(geometry_geo, geographic_vincenty2); + std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds." << std::endl; + std::cout << "area=" << area << std::endl;} + { clock_t startTime = clock(); + for (int j=0; j < 100000; j++) area = bg::area(geometry_geo, geographic_vincenty3); + std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds." << std::endl; + std::cout << "area=" << area << std::endl;} + { clock_t startTime = clock(); + for (int j=0; j < 100000; j++) area = bg::area(geometry_geo, geographic_vincenty4); + std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds." << std::endl; + std::cout << "area=" << area << std::endl;} + { clock_t startTime = clock(); + for (int j=0; j < 100000; j++) area = bg::area(geometry_geo, geographic_vincenty5); + std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds." << std::endl; + std::cout << "area=" << area << std::endl;} + */ +} + +int test_main(int, char* []) +{ + + test_geo_strategies(); + + return 0; +} diff --git a/test/algorithms/area/area_sph_geo.cpp b/test/algorithms/area/area_sph_geo.cpp new file mode 100644 index 000000000..a21c6b20e --- /dev/null +++ b/test/algorithms/area/area_sph_geo.cpp @@ -0,0 +1,403 @@ +// 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. + +// This file was modified by Oracle on 2015, 2016. +// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates. + +// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle +// Contributed and/or modified by Adam Wulkiewicz, 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) + +#include +#include + +namespace bg = boost::geometry; + +//Testing spherical and geographic strategies +template +void test_spherical_geo() +{ + typedef CT ct; + + //Geographic + + typedef typename bg::model::point< + ct, + 2, + bg::cs::geographic + > pt_geo; + + typedef typename bg::point_type::type pt_geo_type; + + typedef typename bg::formula::vincenty_inverse + < + ct, + false, + true, + true + > geo_strategy; + + bg::strategy::area::area_geographic + < + pt_geo_type, + geo_strategy, + 5, + true + > area_geographic; + + bg::model::polygon geometry_geo; + + //Spherical + + typedef typename bg::model::point< + ct, + 2, + bg::cs::spherical_equatorial + > pt; + bg::model::polygon geometry; + + // unit-sphere has area of 4-PI. Polygon covering 1/8 of it: + // calculations splitted for ttmath + std::string poly = "POLYGON((0 0,0 90,90 0,0 0))"; + + ct const four = 4.0; + ct const eight = 8.0; + ct expected = four * boost::geometry::math::pi() / eight; + bg::read_wkt(poly, geometry); + ct area = bg::area(geometry); + BOOST_CHECK_CLOSE(area, expected, 0.0001); + + // With strategy, radius 2 -> 4 pi r^2 + bg::strategy::area::area_spherical + < + typename bg::point_type::type + > strategy(2.0); + + area = bg::area(geometry, strategy); + ct const two = 2.0; + BOOST_CHECK_CLOSE(area, two * two * expected, 0.0001); + + // Geographic total area of earth is about 510072000 + // (https://en.wikipedia.org/wiki/Earth) + // So the 1/8 is 63759000 and here we get something close to it + bg::read_wkt(poly, geometry_geo); + area = bg::area(geometry_geo, area_geographic); + //GeoGraphicLib gives: 63758202715511.055 + BOOST_CHECK_CLOSE(area, 63758202715509.859, 0.0001); + + + // Wrangel Island (dateline crossing) + // With (spherical) Earth strategy + poly = "POLYGON((-178.7858 70.7852, 177.4758 71.2333, 179.7436 71.5733, -178.7858 70.7852))"; + + bg::strategy::area::area_spherical + < + typename bg::point_type::type + > spherical_earth(6373); + bg::read_wkt(poly, geometry); + area = bg::area(geometry, spherical_earth); + // SQL Server gives: 4537.9654419375 + // PostGIS gives: 4537.9311668307 + // Note: those are Geographic, this test is Spherical + BOOST_CHECK_CLOSE(area, 4506.6389, 0.001); + + bg::read_wkt(poly, geometry_geo); + area = bg::area(geometry_geo, area_geographic); + BOOST_CHECK_CLOSE(area, 4537974350.6843719, 0.0001); + + // Wrangel, more in detail + poly = "POLYGON((-178.568604 71.564148,-178.017548 71.449692,-177.833313 71.3461,\ + -177.502838 71.277466 ,-177.439453 71.226929,-177.620026 71.116638,\ + -177.9389 71.037491,-178.8186 70.979965,-179.274445 70.907761,\ + -180 70.9972,179.678314 70.895538,179.272766 70.888596,\ + 178.791016 70.7964,178.617737 71.035538,178.872192 71.217484,\ + 179.530273 71.4383 ,-180 71.535843 ,-179.628601 71.577194,\ + -179.305298 71.551361,-179.03421 71.597748,-178.568604 71.564148))"; + bg::read_wkt(poly, geometry); + area = bg::area(geometry, spherical_earth); + // SQL Server gives: 7669.10402181435 + // PostGIS gives: 7669.55565459832 + BOOST_CHECK_CLOSE(area, 7616.523769, 0.001); + + bg::read_wkt(poly, geometry_geo); + area = bg::area(geometry_geo, area_geographic); + BOOST_CHECK_CLOSE(area, 7669498457.4130802, 0.0001); + + // Check more at the equator + /* + select 1,geography::STGeomFromText('POLYGON((-178.7858 10.7852 , 179.7436 11.5733 , \ + 177.4758 11.2333 , -178.7858 10.7852))',4326) .STArea()/1000000.0 + union select 2,geography::STGeomFromText('POLYGON((-178.7858 20.7852 , 179.7436 21.5733 ,\ + 177.4758 21.2333 , -178.7858 20.7852))',4326) .STArea()/1000000.0 + union select 3,geography::STGeomFromText('POLYGON((-178.7858 30.7852 , 179.7436 31.5733 , \ + 177.4758 31.2333 , -178.7858 30.7852))',4326) .STArea()/1000000.0 + union select 0,geography::STGeomFromText('POLYGON((-178.7858 0.7852 , 179.7436 1.5733 , \ + 177.4758 1.2333 , -178.7858 0.7852))',4326) .STArea()/1000000.0 + union select 4,geography::STGeomFromText('POLYGON((-178.7858 40.7852 , 179.7436 41.5733 , \ + 177.4758 41.2333 , -178.7858 40.7852))',4326) .STArea()/1000000.0 + */ + + poly = "POLYGON((-178.7858 0.7852, 177.4758 1.2333, 179.7436 1.5733, -178.7858 0.7852))"; + bg::read_wkt(poly, geometry); + area = bg::area(geometry, spherical_earth); + BOOST_CHECK_CLOSE(area, 14136.09946, 0.001); // SQL Server gives: 14064.1902284513 + bg::read_wkt(poly, geometry_geo); + area = bg::area(geometry_geo, area_geographic); + BOOST_CHECK_CLOSE(area, 14064196647.560314, 0.0001); + + poly = "POLYGON((-178.7858 10.7852, 177.4758 11.2333, 179.7436 11.5733, -178.7858 10.7852))"; + bg::read_wkt(poly, geometry); + area = bg::area(geometry, spherical_earth); + BOOST_CHECK_CLOSE(area, 13760.2456, 0.001); // SQL Server gives: 13697.0941155193 + bg::read_wkt(poly, geometry_geo); + area = bg::area(geometry_geo, area_geographic); + BOOST_CHECK_CLOSE(area, 13697095227.008451, 0.0001); + + poly = "POLYGON((-178.7858 20.7852, 177.4758 21.2333, 179.7436 21.5733, -178.7858 20.7852))"; + bg::read_wkt(poly, geometry); + area = bg::area(geometry, spherical_earth); + BOOST_CHECK_CLOSE(area, 12987.8682, 0.001); // SQL Server gives: 12944.3970990317 -> -39m^2 + bg::read_wkt(poly, geometry_geo); + area = bg::area(geometry_geo, area_geographic); + BOOST_CHECK_CLOSE(area, 12944392155.546635, 0.0001); + + poly = "POLYGON((-178.7858 30.7852, 177.4758 31.2333, 179.7436 31.5733, -178.7858 30.7852))"; + bg::read_wkt(poly, geometry); + area = bg::area(geometry, spherical_earth); + BOOST_CHECK_CLOSE(area, 11856.3935, 0.001); // SQL Server gives: 11838.5338423574 -> -18m^2 + bg::read_wkt(poly, geometry_geo); + area = bg::area(geometry_geo, area_geographic); + BOOST_CHECK_CLOSE(area, 11838524075.970982, 0.0001); + + poly = "POLYGON((-178.7858 40.7852, 177.4758 41.2333, 179.7436 41.5733, -178.7858 40.7852))"; + bg::read_wkt(poly, geometry); + area = bg::area(geometry, spherical_earth); + BOOST_CHECK_CLOSE(area, 10404.627685523914, 0.001); + // SQL Server gives: 10412.0607137119, -> +8m^2 + bg::read_wkt(poly, geometry_geo); + area = bg::area(geometry_geo, area_geographic); + BOOST_CHECK_CLOSE(area, 10412049661.81769, 0.0001); + + // Concave + poly = "POLYGON((0 40,1 42,0 44,2 43,4 44,3 42,4 40,2 41,0 40))"; + bg::read_wkt(poly, geometry); + area = bg::area(geometry, spherical_earth); + BOOST_CHECK_CLOSE(area, 73538.2958, 0.001); // SQL Server gives: 73604.2047689719 + bg::read_wkt(poly, geometry_geo); + area = bg::area(geometry_geo, area_geographic); + BOOST_CHECK_CLOSE(area, 73604208172.719223, 0.0001); + + // With hole POLYGON((0 40,4 40,4 44,0 44,0 40),(1 41,2 43,3 42,1 41)) + poly = "POLYGON((0 40,0 44,4 44,4 40,0 40),(1 41,3 42,2 43,1 41))"; + bg::read_wkt(poly, geometry); + area = bg::area(geometry, spherical_earth); + BOOST_CHECK_CLOSE(area, 133233.844876, 0.001); // SQL Server gives: 133353.335 + bg::read_wkt(poly, geometry_geo); + area = bg::area(geometry_geo, area_geographic); + BOOST_CHECK_CLOSE(area, 133353331647.58241, 0.0001); + + // around 0 meridian + { + std::string poly1 = "POLYGON((-10 0,-10 10,0 10,0 0,-10 0))"; + std::string poly2 = "POLYGON((0 0,0 10,10 10,10 0,0 0))"; + std::string poly3 = "POLYGON((-5 0,-5 10,5 10,5 0,-5 0))"; + bg::read_wkt(poly1, geometry); + ct area1 = bg::area(geometry); + bg::read_wkt(poly2, geometry); + ct area2 = bg::area(geometry); + bg::read_wkt(poly3, geometry); + ct area3 = bg::area(geometry); + BOOST_CHECK_CLOSE(area1, area2, 0.001); + BOOST_CHECK_CLOSE(area2, area3, 0.001); + BOOST_CHECK_CLOSE(area1, 0.0303822, 0.001); + //geographic + bg::read_wkt(poly1, geometry_geo); + area1 = bg::area(geometry_geo, area_geographic); + bg::read_wkt(poly2, geometry_geo); + area2 = bg::area(geometry_geo, area_geographic); + bg::read_wkt(poly3, geometry_geo); + area3 = bg::area(geometry_geo, area_geographic); + BOOST_CHECK_CLOSE(area1, area2, 0.001); + BOOST_CHECK_CLOSE(area2, area3, 0.001); + BOOST_CHECK_CLOSE(area1, 1227857282668.3145, 0.001); + } + { + std::string poly1 = "POLYGON((-10 -5,-10 5,0 5,0 -5,-10 -5))"; + std::string poly2 = "POLYGON((0 -5,0 5,10 5,10 -5,0 -5))"; + std::string poly3 = "POLYGON((-5 -5,-5 5,5 5,5 -5,-5 -5))"; + bg::read_wkt(poly1, geometry); + ct area1 = bg::area(geometry); + bg::read_wkt(poly2, geometry); + ct area2 = bg::area(geometry); + bg::read_wkt(poly3, geometry); + ct area3 = bg::area(geometry); + BOOST_CHECK_CLOSE(area1, area2, 0.001); + BOOST_CHECK_CLOSE(area2, area3, 0.001); + BOOST_CHECK_CLOSE(area1, 0.0305, 0.001); + //geographic + bg::read_wkt(poly1, geometry_geo); + area1 = bg::area(geometry_geo, area_geographic); + bg::read_wkt(poly2, geometry_geo); + area2 = bg::area(geometry_geo, area_geographic); + bg::read_wkt(poly3, geometry_geo); + area3 = bg::area(geometry_geo, area_geographic); + BOOST_CHECK_CLOSE(area1, area2, 0.001); + BOOST_CHECK_CLOSE(area2, area3, 0.001); + BOOST_CHECK_CLOSE(area1, 1232493707152.2292, 0.001); + } + // around 180 meridian + { + std::string poly1 = "POLYGON((-180 0,-180 10,-170 10,-170 0,-180 0))"; + std::string poly2 = "POLYGON((175 0,175 10,-175 10,-175 0,175 0))"; + std::string poly3 = "POLYGON((170 0,170 10,180 10,180 0,170 0))"; + std::string poly4 = "POLYGON((170 0,170 10,-180 10,-180 0,170 0))"; + std::string poly5 = "POLYGON((180 0,180 10,-170 10,-170 0,180 0))"; + bg::read_wkt(poly1, geometry); + ct area1 = bg::area(geometry); + bg::read_wkt(poly2, geometry); + ct area2 = bg::area(geometry); + bg::read_wkt(poly3, geometry); + ct area3 = bg::area(geometry); + bg::read_wkt(poly4, geometry); + ct area4 = bg::area(geometry); + bg::read_wkt(poly5, geometry); + ct area5 = bg::area(geometry); + BOOST_CHECK_CLOSE(area1, area2, 0.001); + BOOST_CHECK_CLOSE(area2, area3, 0.001); + BOOST_CHECK_CLOSE(area3, area4, 0.001); + BOOST_CHECK_CLOSE(area4, area5, 0.001); + BOOST_CHECK_CLOSE(area1, 0.0303822, 0.001); + //geographic + bg::read_wkt(poly1, geometry_geo); + area1 = bg::area(geometry_geo, area_geographic); + bg::read_wkt(poly2, geometry_geo); + area2 = bg::area(geometry_geo, area_geographic); + bg::read_wkt(poly3, geometry_geo); + area3 = bg::area(geometry_geo, area_geographic); + bg::read_wkt(poly4, geometry_geo); + area4 = bg::area(geometry_geo, area_geographic); + bg::read_wkt(poly5, geometry_geo); + area5 = bg::area(geometry_geo, area_geographic); + BOOST_CHECK_CLOSE(area1, area2, 0.001); + BOOST_CHECK_CLOSE(area2, area3, 0.001); + BOOST_CHECK_CLOSE(area3, area4, 0.001); + BOOST_CHECK_CLOSE(area4, area5, 0.001); + BOOST_CHECK_CLOSE(area1, 1227857282668.313, 0.001); + } + { + std::string poly1 = "POLYGON((-180 -5,-180 5,-170 5,-170 -5,-180 -5))"; + std::string poly2 = "POLYGON((175 -5,175 5,-175 5,-175 -5,175 -5))"; + std::string poly3 = "POLYGON((170 -5,170 5,180 5,180 -5,170 -5))"; + std::string poly4 = "POLYGON((170 -5,170 5,180 5,180 -5,170 -5))"; + std::string poly5 = "POLYGON((180 -5,180 5,-170 5,-170 -5,180 -5))"; + bg::read_wkt(poly1, geometry); + ct area1 = bg::area(geometry); + bg::read_wkt(poly2, geometry); + ct area2 = bg::area(geometry); + bg::read_wkt(poly3, geometry); + ct area3 = bg::area(geometry); + bg::read_wkt(poly4, geometry); + ct area4 = bg::area(geometry); + bg::read_wkt(poly5, geometry); + ct area5 = bg::area(geometry); + BOOST_CHECK_CLOSE(area1, area2, 0.001); + BOOST_CHECK_CLOSE(area2, area3, 0.001); + BOOST_CHECK_CLOSE(area3, area4, 0.001); + BOOST_CHECK_CLOSE(area4, area5, 0.001); + BOOST_CHECK_CLOSE(area1, 0.0305, 0.001); + //geographic + bg::read_wkt(poly1, geometry_geo); + area1 = bg::area(geometry_geo, area_geographic); + bg::read_wkt(poly2, geometry_geo); + area2 = bg::area(geometry_geo, area_geographic); + bg::read_wkt(poly3, geometry_geo); + area3 = bg::area(geometry_geo, area_geographic); + bg::read_wkt(poly4, geometry_geo); + area4 = bg::area(geometry_geo, area_geographic); + bg::read_wkt(poly5, geometry_geo); + area5 = bg::area(geometry_geo, area_geographic); + BOOST_CHECK_CLOSE(area1, area2, 0.001); + BOOST_CHECK_CLOSE(area2, area3, 0.001); + BOOST_CHECK_CLOSE(area3, area4, 0.001); + BOOST_CHECK_CLOSE(area4, area5, 0.001); + BOOST_CHECK_CLOSE(area1, 1232493707152.2278, 0.001); + } + // around poles + { + std::string poly1 = "POLYGON((0 80,-90 80,-180 80,90 80,0 80))"; + std::string poly2 = "POLYGON((0 80,-90 80,180 80,90 80,0 80))"; + std::string poly3 = "POLYGON((0 -80,90 -80,-180 -80,-90 -80,0 -80))"; + std::string poly4 = "POLYGON((0 -80,90 -80,180 -80,-90 -80,0 -80))"; + bg::read_wkt(poly1, geometry); + ct area1 = bg::area(geometry); + bg::read_wkt(poly2, geometry); + ct area2 = bg::area(geometry); + bg::read_wkt(poly3, geometry); + ct area3 = bg::area(geometry); + bg::read_wkt(poly4, geometry); + ct area4 = bg::area(geometry); + BOOST_CHECK_CLOSE(area1, area2, 0.001); + BOOST_CHECK_CLOSE(area2, area3, 0.001); + BOOST_CHECK_CLOSE(area3, area4, 0.001); + //geographic + bg::read_wkt(poly1, geometry_geo); + area1 = bg::area(geometry_geo, area_geographic); + bg::read_wkt(poly2, geometry_geo); + area2 = bg::area(geometry_geo, area_geographic); + bg::read_wkt(poly3, geometry_geo); + area3 = bg::area(geometry_geo, area_geographic); + bg::read_wkt(poly4, geometry_geo); + area4 = bg::area(geometry_geo, area_geographic); + BOOST_CHECK_CLOSE(area1, area2, 0.001); + BOOST_CHECK_CLOSE(area2, area3, 0.001); + BOOST_CHECK_CLOSE(area3, area4, 0.001); + } + + { + bg::model::ring aurha; // a'dam-utr-rott.-den haag-a'dam + std::string poly = "POLYGON((4.892 52.373,5.119 52.093,4.479 51.930,\ + 4.23 52.08,4.892 52.373))"; + bg::read_wkt(poly, aurha); + /*if (polar) + { + // Create colatitudes (measured from pole) + BOOST_FOREACH(pt& p, aurha) + { + bg::set<1>(p, ct(90) - bg::get<1>(p)); + } + bg::correct(aurha); + }*/ + bg::strategy::area::area_spherical + < + typename bg::point_type::type + > area_spherical(6372.795); + area = bg::area(aurha, area_spherical); + BOOST_CHECK_CLOSE(area, 1476.645675, 0.0001); + //geographic + bg::read_wkt(poly, geometry_geo); + area = bg::area(geometry_geo, area_geographic); + BOOST_CHECK_CLOSE(area, 1481555970.0765088, 0.001); + + // SQL Server gives: 1481.55595960659 + // for select geography::STGeomFromText('POLYGON((4.892 52.373,4.23 52.08, + // 4.479 51.930,5.119 52.093,4.892 52.373))',4326).STArea()/1000000.0 + } +} + +int test_main(int, char* []) +{ + + test_spherical_geo(); + + return 0; +} From 8b555cf1cd2118b834c3622d02aa174a1d0494a8 Mon Sep 17 00:00:00 2001 From: Vissarion Fysikopoulos Date: Wed, 17 Aug 2016 15:06:30 +0300 Subject: [PATCH 11/89] [area] LongSegment support --- include/boost/geometry/formulas/area_formulas.hpp | 9 ++++++--- .../geometry/strategies/geographic/area_geographic.hpp | 3 ++- .../geometry/strategies/spherical/area_spherical.hpp | 3 ++- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/include/boost/geometry/formulas/area_formulas.hpp b/include/boost/geometry/formulas/area_formulas.hpp index 6b742f693..07d654143 100644 --- a/include/boost/geometry/formulas/area_formulas.hpp +++ b/include/boost/geometry/formulas/area_formulas.hpp @@ -21,6 +21,8 @@ namespace boost { namespace geometry { namespace formula The current class computes the area of the trapezoid defined by a segment the two meridians passing by the endpoints and the equator. \author See +- Danielsen JS, The area under the geodesic. Surv Rev 30(232): +61–66, 1989 - Charles F.F Karney, Algorithms for geodesics, 2011 https://arxiv.org/pdf/1109.4448.pdf */ @@ -28,8 +30,7 @@ https://arxiv.org/pdf/1109.4448.pdf template < typename CT, const std::size_t SeriesOrder = 2, - bool ExpandEpsN = true, - bool LongSegment = false + bool ExpandEpsN = true > class area_formulas { @@ -332,6 +333,7 @@ public: Compute the spherical excess of a geodesic (or shperical) segment */ template < + bool LongSegment, typename PointOfSegment > static inline CT spherical_excess(PointOfSegment const& p1, @@ -339,12 +341,13 @@ public: { CT excess; - if(LongSegment) + if(LongSegment) // not for segments parallel to equator { CT cbet1 = cos(geometry::get_as_radian<1>(p1)); CT sbet1 = sin(geometry::get_as_radian<1>(p1)); CT cbet2 = cos(geometry::get_as_radian<1>(p2)); CT sbet2 = sin(geometry::get_as_radian<1>(p2)); + CT omg12 = geometry::get_as_radian<0>(p1) - geometry::get_as_radian<0>(p2); CT comg12 = cos(omg12); diff --git a/include/boost/geometry/strategies/geographic/area_geographic.hpp b/include/boost/geometry/strategies/geographic/area_geographic.hpp index ddc715124..2375ec401 100644 --- a/include/boost/geometry/strategies/geographic/area_geographic.hpp +++ b/include/boost/geometry/strategies/geographic/area_geographic.hpp @@ -34,6 +34,7 @@ template typename Strategy = void, const std::size_t SeriesOrder = 2, bool ExpandEpsN = true, + bool LongSegment = false, typename Spheroid = void, typename CalculationType = void > @@ -161,7 +162,7 @@ public : //Compute the trapezoidal area state.m_excess_sum += geometry::formula::area_formulas - ::spherical_excess(p1, p2); + ::template spherical_excess(p1, p2); state.m_correction_sum += geometry::formula::area_formulas diff --git a/include/boost/geometry/strategies/spherical/area_spherical.hpp b/include/boost/geometry/strategies/spherical/area_spherical.hpp index 218c78f7e..226fa348d 100644 --- a/include/boost/geometry/strategies/spherical/area_spherical.hpp +++ b/include/boost/geometry/strategies/spherical/area_spherical.hpp @@ -27,6 +27,7 @@ namespace strategy { namespace area template < typename PointOfSegment, + bool LongSegment = false, typename CalculationType = void > class area_spherical @@ -101,7 +102,7 @@ public : { state.m_sum += geometry::formula::area_formulas - ::spherical_excess(p1, p2); + ::template spherical_excess(p1, p2); // Keep track whenever a segment crosses the prime meridian geometry::formula::area_formulas From 64725caeda0c4460557de5e4649e772d43a0fa78 Mon Sep 17 00:00:00 2001 From: Vissarion Fysikopoulos Date: Thu, 18 Aug 2016 14:01:26 +0300 Subject: [PATCH 12/89] [area] first round of changes --- .../extensions/contrib/ttmath_stub.hpp | 15 +++++++++++++++ .../boost/geometry/formulas/area_formulas.hpp | 19 ++++++++++++------- .../strategies/geographic/area_geographic.hpp | 14 ++++++++------ .../strategies/spherical/area_huiller.hpp | 15 +++++++++------ 4 files changed, 44 insertions(+), 19 deletions(-) diff --git a/include/boost/geometry/extensions/contrib/ttmath_stub.hpp b/include/boost/geometry/extensions/contrib/ttmath_stub.hpp index 353803bf4..e20138618 100644 --- a/include/boost/geometry/extensions/contrib/ttmath_stub.hpp +++ b/include/boost/geometry/extensions/contrib/ttmath_stub.hpp @@ -51,12 +51,27 @@ namespace ttmath return tmp; } + template + inline Big log(Big const& v, + int n = 10) + { + Big tmp; + tmp.Log(v, n); + return tmp; + } + template inline Big abs(Big const& v) { return Abs(v); } + template + inline Big fabs(Big const& v) + { + return Abs(v); + } + template inline Big ceil(Big const& v) { diff --git a/include/boost/geometry/formulas/area_formulas.hpp b/include/boost/geometry/formulas/area_formulas.hpp index 07d654143..541a8ebc0 100644 --- a/include/boost/geometry/formulas/area_formulas.hpp +++ b/include/boost/geometry/formulas/area_formulas.hpp @@ -12,6 +12,7 @@ #define BOOST_GEOMETRY_FORMULAS_AREA_FORMULAS_HPP #include +#include namespace boost { namespace geometry { namespace formula { @@ -29,7 +30,7 @@ https://arxiv.org/pdf/1109.4448.pdf template < typename CT, - const std::size_t SeriesOrder = 2, + std::size_t SeriesOrder = 2, bool ExpandEpsN = true > class area_formulas @@ -49,9 +50,11 @@ public: { NT result(0); IteratorType it = end; - do{ + do + { result = result * x + *--it; - }while(it != begin); + } + while (it != begin); return result; } @@ -65,15 +68,17 @@ public: IteratorType end) { IteratorType it = end; - bool odd(true); + bool odd = true; CT b_k, b_k1(0), b_k2(0); - do{ + do + { CT c_k = odd ? *--it : NT(0); b_k = c_k + NT(2) * cosx * b_k1 - b_k2; b_k2 = b_k1; b_k1 = b_k; odd = !odd; - }while(it != begin); + } + while (it != begin); return *begin + b_k1 * cosx - b_k2; } @@ -81,7 +86,7 @@ public: template static inline void normalize(T& x, T& y) { - T h = hypot(x, y); + T h = boost::math::hypot(x, y); x /= h; y /= h; } diff --git a/include/boost/geometry/strategies/geographic/area_geographic.hpp b/include/boost/geometry/strategies/geographic/area_geographic.hpp index 2375ec401..7131ac019 100644 --- a/include/boost/geometry/strategies/geographic/area_geographic.hpp +++ b/include/boost/geometry/strategies/geographic/area_geographic.hpp @@ -12,7 +12,7 @@ #include #include -//#include +#include namespace boost { namespace geometry { @@ -32,7 +32,7 @@ template < typename PointOfSegment, typename Strategy = void, - const std::size_t SeriesOrder = 2, + std::size_t SeriesOrder = 2, bool ExpandEpsN = true, bool LongSegment = false, typename Spheroid = void, @@ -93,7 +93,7 @@ protected : , m_ep2(m_e2 / (CT(1.0) - m_e2)) , m_ep(math::sqrt(m_ep2)) , m_c2((m_a2 / CT(2.0)) + - ((math::sqr(get_radius<2>(spheroid)) * atanh(math::sqrt(m_e2))) + ((math::sqr(get_radius<2>(spheroid)) * boost::math::atanh(math::sqrt(m_e2))) / (CT(2.0) * math::sqrt(m_e2)))) {} }; @@ -119,7 +119,7 @@ protected : + spheroid_const.m_e2 * spheroid_const.m_a2 * m_correction_sum; // If encircles some pole - if(m_crosses_prime_meridian % 2 == 1) + if (m_crosses_prime_meridian % 2 == 1) { std::size_t times_crosses_prime_meridian = 1 + (m_crosses_prime_meridian / 2); @@ -130,12 +130,14 @@ protected : * CT(times_crosses_prime_meridian) - geometry::math::abs(sum); - if(geometry::math::sign(sum) == 1) + if (geometry::math::sign(sum) == 1) { result = - result; } - } else { + } + else + { result = sum; } diff --git a/include/boost/geometry/strategies/spherical/area_huiller.hpp b/include/boost/geometry/strategies/spherical/area_huiller.hpp index 139bed489..6bb6fb05e 100644 --- a/include/boost/geometry/strategies/spherical/area_huiller.hpp +++ b/include/boost/geometry/strategies/spherical/area_huiller.hpp @@ -117,21 +117,22 @@ protected : calculation_type result; // Encircles pole - if((crosses_prime_meridian % 2 == 1 && south) || south_vertex) + if ((crosses_prime_meridian % 2 == 1 && south) || south_vertex) { calculation_type constant; //if(south_vertex) //{ - constant = 2.0 * (max_lon - min_lon) / geometry::math::pi(); + constant = calculation_type(2) * (max_lon - min_lon) + / geometry::math::pi(); //} else { // constant = 4.0; //} - if(crosses_prime_meridian % 2 == 0 && crosses_prime_meridian > 1) + if (crosses_prime_meridian % 2 == 0 && crosses_prime_meridian > 1) { - constant = 4.0 - constant; + constant = calculation_type(4) - constant; } std::cout << "(const=" << constant << ")"; @@ -141,12 +142,14 @@ protected : * geometry::math::pi() - std::abs(sum); - if(geometry::math::sign(sum) == -1) + if (geometry::math::sign(sum) == -1) { result = - result; } - } else { + } + else + { result = - sum; } From 93b70ace536ffa8ba5c077bbb3a5613b52529d93 Mon Sep 17 00:00:00 2001 From: Vissarion Fysikopoulos Date: Fri, 19 Aug 2016 13:58:47 +0300 Subject: [PATCH 13/89] [area] Second round of changes. Spherical area gets srs sphere as parameter and keep a constructor with radius for backward compatibility. --- .../strategies/geographic/area_geographic.hpp | 3 +-- .../strategies/spherical/area_spherical.hpp | 23 +++++++++++++------ test/algorithms/area/area.cpp | 4 ++-- test/algorithms/area/area_multi.cpp | 2 +- test/algorithms/area/area_sph_geo.cpp | 15 ++++++++---- 5 files changed, 30 insertions(+), 17 deletions(-) diff --git a/include/boost/geometry/strategies/geographic/area_geographic.hpp b/include/boost/geometry/strategies/geographic/area_geographic.hpp index 7131ac019..6cf81adf1 100644 --- a/include/boost/geometry/strategies/geographic/area_geographic.hpp +++ b/include/boost/geometry/strategies/geographic/area_geographic.hpp @@ -41,8 +41,7 @@ template class area_geographic { - //Select default types for Strategy, Spheroid and CalculationType - //in case they are not set + //Select default types in case they are not set typedef typename boost::mpl::if_c < diff --git a/include/boost/geometry/strategies/spherical/area_spherical.hpp b/include/boost/geometry/strategies/spherical/area_spherical.hpp index 226fa348d..b71348d11 100644 --- a/include/boost/geometry/strategies/spherical/area_spherical.hpp +++ b/include/boost/geometry/strategies/spherical/area_spherical.hpp @@ -11,6 +11,7 @@ #define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_AREA_SPHERICAL_HPP #include +#include namespace boost { namespace geometry { @@ -55,9 +56,11 @@ protected : : m_sum(0) , m_crosses_prime_meridian(0) {} - inline CT area(CT radius) const + template + inline CT area(SphereType sphere) const { CT result; + CT radius = sphere.get_radius<0>(); // Encircles pole if(m_crosses_prime_meridian % 2 == 1) @@ -89,11 +92,18 @@ public : typedef CT return_type; typedef PointOfSegment segment_point_type; typedef excess_sum state_type; + typedef geometry::srs::sphere sphere_type; - inline area_spherical(CT radius = 1.0) - : m_radius(radius) + inline area_spherical(sphere_type sphere = sphere_type()) + : m_sphere(sphere) {} + inline area_spherical(CT radius) //backward compatibility + : m_sphere() + { + m_sphere.set_radius<0>(radius); + } + inline void apply(PointOfSegment const& p1, PointOfSegment const& p2, excess_sum& state) const @@ -113,13 +123,12 @@ public : inline return_type result(excess_sum const& state) const { - //std::cout << "(tpole=" << state.crosses_prime_meridian << ")"; - return state.area(m_radius); + return state.area(m_sphere); } private : - /// Radius of the sphere - CT m_radius; + /// srs Sphere + sphere_type m_sphere; }; #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS diff --git a/test/algorithms/area/area.cpp b/test/algorithms/area/area.cpp index 8488765d7..e35e8f709 100644 --- a/test/algorithms/area/area.cpp +++ b/test/algorithms/area/area.cpp @@ -213,11 +213,11 @@ int test_main(int, char* []) test_ccw(); test_open(2.0); - test_open(0.00060917296206278821); + test_open(24726179921.523518); test_open(24615760871.487991); test_open_ccw(2.0); - test_open_ccw(0.00060917296206278821); + test_open_ccw(24726179921.523518); test_open_ccw(24615760871.487991); test_poles_ccw(); diff --git a/test/algorithms/area/area_multi.cpp b/test/algorithms/area/area_multi.cpp index b57148532..89f0fbd4f 100644 --- a/test/algorithms/area/area_multi.cpp +++ b/test/algorithms/area/area_multi.cpp @@ -36,7 +36,7 @@ void test_all() std::string poly = "MULTIPOLYGON(((0 0,0 7,4 2,2 0,0 0)))"; test_geometry(poly, 16.0); - test_geometry(poly, 0.0048755521103139238); + test_geometry(poly, 197897454752.69489); test_geometry(poly, 197020675141.16785); } diff --git a/test/algorithms/area/area_sph_geo.cpp b/test/algorithms/area/area_sph_geo.cpp index a21c6b20e..75da9cb91 100644 --- a/test/algorithms/area/area_sph_geo.cpp +++ b/test/algorithms/area/area_sph_geo.cpp @@ -70,11 +70,16 @@ void test_spherical_geo() // calculations splitted for ttmath std::string poly = "POLYGON((0 0,0 90,90 0,0 0))"; + bg::strategy::area::area_spherical + < + typename bg::point_type::type + > strategy_unary(1.0); + ct const four = 4.0; ct const eight = 8.0; ct expected = four * boost::geometry::math::pi() / eight; bg::read_wkt(poly, geometry); - ct area = bg::area(geometry); + ct area = bg::area(geometry, strategy_unary); BOOST_CHECK_CLOSE(area, expected, 0.0001); // With strategy, radius 2 -> 4 pi r^2 @@ -219,7 +224,7 @@ void test_spherical_geo() ct area3 = bg::area(geometry); BOOST_CHECK_CLOSE(area1, area2, 0.001); BOOST_CHECK_CLOSE(area2, area3, 0.001); - BOOST_CHECK_CLOSE(area1, 0.0303822, 0.001); + BOOST_CHECK_CLOSE(area1, 1233204227903.1848, 0.001); //geographic bg::read_wkt(poly1, geometry_geo); area1 = bg::area(geometry_geo, area_geographic); @@ -243,7 +248,7 @@ void test_spherical_geo() ct area3 = bg::area(geometry); BOOST_CHECK_CLOSE(area1, area2, 0.001); BOOST_CHECK_CLOSE(area2, area3, 0.001); - BOOST_CHECK_CLOSE(area1, 0.0305, 0.001); + BOOST_CHECK_CLOSE(area1, 1237986107636.0261, 0.001); //geographic bg::read_wkt(poly1, geometry_geo); area1 = bg::area(geometry_geo, area_geographic); @@ -276,7 +281,7 @@ void test_spherical_geo() BOOST_CHECK_CLOSE(area2, area3, 0.001); BOOST_CHECK_CLOSE(area3, area4, 0.001); BOOST_CHECK_CLOSE(area4, area5, 0.001); - BOOST_CHECK_CLOSE(area1, 0.0303822, 0.001); + BOOST_CHECK_CLOSE(area1, 1233204227903.1833, 0.001); //geographic bg::read_wkt(poly1, geometry_geo); area1 = bg::area(geometry_geo, area_geographic); @@ -314,7 +319,7 @@ void test_spherical_geo() BOOST_CHECK_CLOSE(area2, area3, 0.001); BOOST_CHECK_CLOSE(area3, area4, 0.001); BOOST_CHECK_CLOSE(area4, area5, 0.001); - BOOST_CHECK_CLOSE(area1, 0.0305, 0.001); + BOOST_CHECK_CLOSE(area1, 1237986107636.0247, 0.001); //geographic bg::read_wkt(poly1, geometry_geo); area1 = bg::area(geometry_geo, area_geographic); From 2fdf75333ef3f93e32c2c31968153717f57ac57a Mon Sep 17 00:00:00 2001 From: Vissarion Fysikopoulos Date: Tue, 30 Aug 2016 16:58:26 +0300 Subject: [PATCH 14/89] [formulas] Algorithm for vertex latitude. --- .../geometry/formulas/vertex_latitude.hpp | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 include/boost/geometry/formulas/vertex_latitude.hpp diff --git a/include/boost/geometry/formulas/vertex_latitude.hpp b/include/boost/geometry/formulas/vertex_latitude.hpp new file mode 100644 index 000000000..9e3c6b80b --- /dev/null +++ b/include/boost/geometry/formulas/vertex_latitude.hpp @@ -0,0 +1,99 @@ +// Boost.Geometry + +// Copyright (c) 2016 Oracle and/or its affiliates. + +// Contributed and/or modified by Vissarion Fysikopoulos, 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_FORMULAS_MAXIMUM_LATITUDE_HPP +#define BOOST_GEOMETRY_FORMULAS_MAXIMUM_LATITUDE_HPP + +namespace boost { namespace geometry { namespace formula +{ + +/*! +\brief Algorithm to compute the vertex latitude of a geodesic segment. Vertex is +a point on the geodesic that maximizes (or minimizes) the latitude. +\author See + Wood - Vertex Latitudes on Ellipsoid Geodesics, SIAM Rev., 38(4), 637–644, + 1996 +*/ + +template < + typename CT, + template class Inverse +> +class vertex_latitude +{ + + typedef Inverse inverse_type; + typedef typename inverse_type::result_type inverse_result; + +public: + + template + static inline CT apply(T1 const& lon1, + T1 const& lat1, + T2 const& lon2, + T2 const& lat2, + Spheroid const& spheroid, + bool north) + { + CT const a = get_radius<0>(spheroid); + CT const f = detail::flattening(spheroid); + CT const e2 = f * (CT(2) - f); + CT const half_pi = math::pi() / CT(2); + + // signbit returns a non-zero value (true) if the sign is negative; + // and zero (false) otherwise. + bool sign = std::signbit(std::abs(lat1) > std::abs(lat2) ? lat1 : lat2); + + inverse_result i_res = inverse_type::apply(lon1, lat1, lon2, lat2, + spheroid); + + CT const alp1 = i_res.azimuth; + CT const alp2 = i_res.reverse_azimuth; + + std::cout << "a1=" << alp1 * 180 / math::pi() + << " a2=" + << alp2 * 180 / math::pi() + << std::endl; + + // if the segment does not contain the vertex of the geodesic + // then the vertex is one of the endpoints + if ((alp1 < half_pi && alp2 < half_pi) + || (alp1 > half_pi && alp2 > half_pi) + || (north == sign)) + { + return north ? std::max(lat1, lat2) : std::min(lat1, lat2); + } + + CT const sin_alp1 = sin(alp1); + CT const sin_lat1 = sin(lat1); + //CT const sin_lat2 = sin(lat2); + CT const cos_lat1 = math::sqrt(CT(1) - math::sqr(sin_lat1)); + //CT const cos_lat2 = math::sqrt(CT(1) - math::sqr(sin_lat2)); + + //normal radius at point p1(lon1,lat1) + CT const n_b1 = a / (math::sqrt(CT(1) - e2 * math::sqr(sin_lat1))); + //CT const n_b2 = a / (math::sqrt(CT(1) - e2 * math::sqr(sin_lat2))); + + //the invariant of the geodesic + CT const c = n_b1 * cos_lat1 * sin_alp1; + + //CT const alp2b = std::asin(c / (n_b2 * cos_lat2)); + + CT const a_c2 = math::sqr(a / c); + CT const max_lat = std::asin(math::sqrt((a_c2 - 1) / (a_c2 - e2))); + + return (sign ? max_lat * CT(-1) : max_lat); + } +}; + + +}}} // namespace boost::geometry::formula + +#endif // BOOST_GEOMETRY_FORMULAS_MAXIMUM_LATITUDE_HPP From 87516b04954ff915f6508fd99eb31b9aff66a4a5 Mon Sep 17 00:00:00 2001 From: Vissarion Fysikopoulos Date: Wed, 31 Aug 2016 12:47:40 +0300 Subject: [PATCH 15/89] [test] [formulas] Tests for vertex latitude algorithm. --- .../geometry/formulas/vertex_latitude.hpp | 23 ++--- test/algorithms/Jamfile.v2 | 1 + test/algorithms/vertex_latitude.cpp | 95 +++++++++++++++++++ 3 files changed, 105 insertions(+), 14 deletions(-) create mode 100644 test/algorithms/vertex_latitude.cpp diff --git a/include/boost/geometry/formulas/vertex_latitude.hpp b/include/boost/geometry/formulas/vertex_latitude.hpp index 9e3c6b80b..cb0a745ac 100644 --- a/include/boost/geometry/formulas/vertex_latitude.hpp +++ b/include/boost/geometry/formulas/vertex_latitude.hpp @@ -54,16 +54,16 @@ public: inverse_result i_res = inverse_type::apply(lon1, lat1, lon2, lat2, spheroid); - CT const alp1 = i_res.azimuth; - CT const alp2 = i_res.reverse_azimuth; + CT const alp1 = std::abs(i_res.azimuth); + CT const alp2 = std::abs(i_res.reverse_azimuth); - std::cout << "a1=" << alp1 * 180 / math::pi() - << " a2=" - << alp2 * 180 / math::pi() - << std::endl; + //std::cout << "a1=" << alp1 * 180 / math::pi() + // << " a2=" + // << alp2 * 180 / math::pi() + // << std::endl; // if the segment does not contain the vertex of the geodesic - // then the vertex is one of the endpoints + // then return the endpoint of max (min) latitude if ((alp1 < half_pi && alp2 < half_pi) || (alp1 > half_pi && alp2 > half_pi) || (north == sign)) @@ -73,19 +73,14 @@ public: CT const sin_alp1 = sin(alp1); CT const sin_lat1 = sin(lat1); - //CT const sin_lat2 = sin(lat2); CT const cos_lat1 = math::sqrt(CT(1) - math::sqr(sin_lat1)); - //CT const cos_lat2 = math::sqrt(CT(1) - math::sqr(sin_lat2)); - //normal radius at point p1(lon1,lat1) + // normal radius at point p1(lon1,lat1) CT const n_b1 = a / (math::sqrt(CT(1) - e2 * math::sqr(sin_lat1))); - //CT const n_b2 = a / (math::sqrt(CT(1) - e2 * math::sqr(sin_lat2))); - //the invariant of the geodesic + // the invariant of the geodesic CT const c = n_b1 * cos_lat1 * sin_alp1; - //CT const alp2b = std::asin(c / (n_b2 * cos_lat2)); - CT const a_c2 = math::sqr(a / c); CT const max_lat = std::asin(math::sqrt((a_c2 - 1) / (a_c2 - e2))); diff --git a/test/algorithms/Jamfile.v2 b/test/algorithms/Jamfile.v2 index 63f218504..c3a636e8a 100644 --- a/test/algorithms/Jamfile.v2 +++ b/test/algorithms/Jamfile.v2 @@ -58,6 +58,7 @@ test-suite boost-geometry-algorithms [ run transform_multi.cpp : : : : algorithms_transform_multi ] [ run unique.cpp : : : : algorithms_unique ] [ run unique_multi.cpp : : : : algorithms_unique_multi ] + [ run vertex_latitude.cpp : : : : algorithms_vertex_latitude ] ; build-project buffer ; diff --git a/test/algorithms/vertex_latitude.cpp b/test/algorithms/vertex_latitude.cpp new file mode 100644 index 000000000..96a80cd33 --- /dev/null +++ b/test/algorithms/vertex_latitude.cpp @@ -0,0 +1,95 @@ +// Boost.Geometry + +// Copyright (c) 2016 Oracle and/or its affiliates. + +// Contributed and/or modified by Vissarion Fysikopoulos, 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) + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include + +#include + +template < + template class Inverse, + typename P, + typename CT +> +void test_vertex_lat(P p1, P p2, CT expected_max, CT expected_min, CT error = 0.0001) +{ + CT p10 = bg::get_as_radian<0>(p1), + p11 = bg::get_as_radian<1>(p1), + p20 = bg::get_as_radian<0>(p2), + p21 = bg::get_as_radian<1>(p2); + + bg::formula::vertex_latitude vrt_lat; + + CT p_max = vrt_lat.apply(p10, p11, p20, p21, + bg::srs::spheroid(), true); + CT p_max_degree = p_max * 180 / bg::math::pi(); + BOOST_CHECK_CLOSE(p_max_degree, expected_max, error); + + CT p_min = vrt_lat.apply(p10, p11, p20, p21, + bg::srs::spheroid(), false); + CT p_min_degree = p_min * 180 / bg::math::pi(); + BOOST_CHECK_CLOSE(p_min_degree, expected_min, error); +} + +template +void test_all() +{ + typedef bg::model::point > Pg; + + // Short segments + test_vertex_lat(Pg(1, 1), Pg(10, 5), 5.0, 1.0); + test_vertex_lat(Pg(1, 1), Pg(10, 1), 1.0031124506594733, 1.0); + test_vertex_lat(Pg(-5, 1), Pg(4, 1), 1.0031124506594733, 1.0); + test_vertex_lat(Pg(175, 1), Pg(184, 1), 1.0031124506594733, 1.0); + test_vertex_lat(Pg(355, 1), Pg(4, 1), 1.0031124506594733, 1.0); + + // Reverse direction + test_vertex_lat(Pg(1, 2), Pg(70, 1), 2.02397, 1.0); + test_vertex_lat(Pg(70, 1), Pg(1, 2), 2.02397, 1.0); + + // Long segments + test_vertex_lat(Pg(0, 1), Pg(170, 1), 11.975026023950877, 1.0); + test_vertex_lat(Pg(0, 1), Pg(179, 1), 68.452669316418039, 1.0); + test_vertex_lat(Pg(0, 1), Pg(179.5, 1), 78.84050225214871, 1.0); + test_vertex_lat(Pg(0, 1), Pg(180.5, 1), 78.84050225214871, 1.0); + test_vertex_lat(Pg(0, 1), Pg(180, 1), 90.0, 1.0); + + // South hemisphere + test_vertex_lat(Pg(1, -1), Pg(10, -5), -1.0, -5.0); + test_vertex_lat(Pg(1, -1), Pg(10, -1), -1.0, -1.0031124506594733); + test_vertex_lat(Pg(1, -1), Pg(170, -1), -1.0, -10.85834257048573); + + // Different strategies for inverse + test_vertex_lat + (Pg(1, 1), Pg(10, 1), 1.0031124506594733, 1.0, 0.00000001); + test_vertex_lat + (Pg(1, 1), Pg(10, 1), 1.0031124504591062, 1.0, 0.00000001); + test_vertex_lat + (Pg(1, 1), Pg(10, 1), 1.0031124508942098, 1.0, 0.00000001); +} + +int test_main( int , char* [] ) +{ + test_all(); + + return 0; +} + From c74ddfd4d698c9f978eab95790897e9d314b5d31 Mon Sep 17 00:00:00 2001 From: Vissarion Fysikopoulos Date: Wed, 31 Aug 2016 18:41:48 +0300 Subject: [PATCH 16/89] [area] Change interface; inverse formula as template template parameter --- .../boost/geometry/formulas/area_formulas.hpp | 19 +++++- .../strategies/geographic/area_geographic.hpp | 10 +-- test/algorithms/area/area_geo.cpp | 61 ++++++------------- test/algorithms/area/area_sph_geo.cpp | 13 +--- 4 files changed, 40 insertions(+), 63 deletions(-) diff --git a/include/boost/geometry/formulas/area_formulas.hpp b/include/boost/geometry/formulas/area_formulas.hpp index 541a8ebc0..a202e5fd8 100644 --- a/include/boost/geometry/formulas/area_formulas.hpp +++ b/include/boost/geometry/formulas/area_formulas.hpp @@ -391,7 +391,8 @@ public: Compute the ellipsoidal correction of a geodesic (or shperical) segment */ template < - typename AzimuthStrategy, + template class Inverse, + //typename AzimuthStrategy, typename PointOfSegment, typename SpheroidConst > @@ -401,8 +402,20 @@ public: { - // Azimuth Approximation + typedef Inverse inverse_type; + typedef typename inverse_type::result_type inverse_result; + inverse_result i_res = inverse_type::apply(get_as_radian<0>(p1), + get_as_radian<1>(p1), + get_as_radian<0>(p2), + get_as_radian<1>(p2), + spheroid_const.m_spheroid); + + CT alp1 = i_res.azimuth; + CT alp2 = i_res.reverse_azimuth; + + // Azimuth Approximation +/* CT alp1, alp2; alp1 = AzimuthStrategy::apply(get_as_radian<0>(p1), @@ -416,7 +429,7 @@ public: get_as_radian<0>(p2), get_as_radian<1>(p2), spheroid_const.m_spheroid).reverse_azimuth; - +*/ // Integral approximation CT const ep = spheroid_const.m_ep; diff --git a/include/boost/geometry/strategies/geographic/area_geographic.hpp b/include/boost/geometry/strategies/geographic/area_geographic.hpp index 6cf81adf1..4f210dfb8 100644 --- a/include/boost/geometry/strategies/geographic/area_geographic.hpp +++ b/include/boost/geometry/strategies/geographic/area_geographic.hpp @@ -31,7 +31,8 @@ approximation that gives the ellipsoidal correction template < typename PointOfSegment, - typename Strategy = void, + template class Inverse = + geometry::formula::thomas_inverse, std::size_t SeriesOrder = 2, bool ExpandEpsN = true, bool LongSegment = false, @@ -53,7 +54,7 @@ class area_geographic >::type, CalculationType >::type CT; - +/* typedef typename boost::mpl::if_c < boost::is_void::type::value, @@ -66,7 +67,7 @@ class area_geographic >, Strategy >::type AzimuthStrategy; - +*/ typedef typename boost::mpl::if_c < boost::is_void::type::value, @@ -167,8 +168,7 @@ public : state.m_correction_sum += geometry::formula::area_formulas - ::template ellipsoidal_correction - + ::template ellipsoidal_correction (p1, p2, spheroid_const); // Keep track whenever a segment crosses the prime meridian diff --git a/test/algorithms/area/area_geo.cpp b/test/algorithms/area/area_geo.cpp index 9fc8bd26b..f9134a87f 100644 --- a/test/algorithms/area/area_geo.cpp +++ b/test/algorithms/area/area_geo.cpp @@ -29,68 +29,41 @@ void test_geo_strategies() typedef typename bg::point_type::type pt_geo_type; - typedef typename bg::formula::andoyer_inverse - < - CT, - false, - true, - true - > strategy_andoyer; - - typedef typename bg::formula::thomas_inverse - < - CT, - false, - true, - true - > strategy_thomas; - - typedef typename bg::formula::vincenty_inverse - < - CT, - false, - true, - true - > strategy_vincenty; - - - bg::srs::spheroid spheroid; - bg::strategy::area::area_geographic geographic_default; bg::strategy::area::area_geographic < pt_geo_type, - strategy_andoyer, + bg::formula::andoyer_inverse, 1, true > geographic_andoyer1; bg::strategy::area::area_geographic < pt_geo_type, - strategy_andoyer, + bg::formula::andoyer_inverse, 2, true > geographic_andoyer2; bg::strategy::area::area_geographic < pt_geo_type, - strategy_andoyer, + bg::formula::andoyer_inverse, 3, true > geographic_andoyer3; bg::strategy::area::area_geographic < pt_geo_type, - strategy_andoyer, + bg::formula::andoyer_inverse, 4, true > geographic_andoyer4; bg::strategy::area::area_geographic < pt_geo_type, - strategy_andoyer, + bg::formula::andoyer_inverse, 5, true > geographic_andoyer5; @@ -98,35 +71,35 @@ void test_geo_strategies() bg::strategy::area::area_geographic < pt_geo_type, - strategy_thomas, + bg::formula::thomas_inverse, 1, true > geographic_thomas1; bg::strategy::area::area_geographic < pt_geo_type, - strategy_thomas, + bg::formula::thomas_inverse, 2, true > geographic_thomas2; bg::strategy::area::area_geographic < pt_geo_type, - strategy_thomas, + bg::formula::thomas_inverse, 3, true > geographic_thomas3; bg::strategy::area::area_geographic < pt_geo_type, - strategy_thomas, + bg::formula::thomas_inverse, 4, true > geographic_thomas4; bg::strategy::area::area_geographic < pt_geo_type, - strategy_thomas, + bg::formula::thomas_inverse, 5, true > geographic_thomas5; @@ -134,35 +107,35 @@ void test_geo_strategies() bg::strategy::area::area_geographic < pt_geo_type, - strategy_vincenty, + bg::formula::vincenty_inverse, 1, true > geographic_vincenty1; bg::strategy::area::area_geographic < pt_geo_type, - strategy_vincenty, + bg::formula::vincenty_inverse, 2, true > geographic_vincenty2; bg::strategy::area::area_geographic < pt_geo_type, - strategy_vincenty, + bg::formula::vincenty_inverse, 3, true > geographic_vincenty3; bg::strategy::area::area_geographic < pt_geo_type, - strategy_vincenty, + bg::formula::vincenty_inverse, 4, true > geographic_vincenty4; bg::strategy::area::area_geographic < pt_geo_type, - strategy_vincenty, + bg::formula::vincenty_inverse, 5, true > geographic_vincenty5; @@ -170,14 +143,14 @@ void test_geo_strategies() bg::strategy::area::area_geographic < pt_geo_type, - strategy_vincenty, + bg::formula::vincenty_inverse, 5 > geographic_vincenty5_default; bg::strategy::area::area_geographic < pt_geo_type, - strategy_vincenty + bg::formula::vincenty_inverse > geographic_vincenty_default; bg::model::polygon geometry_geo; diff --git a/test/algorithms/area/area_sph_geo.cpp b/test/algorithms/area/area_sph_geo.cpp index 75da9cb91..06f8aedeb 100644 --- a/test/algorithms/area/area_sph_geo.cpp +++ b/test/algorithms/area/area_sph_geo.cpp @@ -39,20 +39,11 @@ void test_spherical_geo() typedef typename bg::point_type::type pt_geo_type; - typedef typename bg::formula::vincenty_inverse - < - ct, - false, - true, - true - > geo_strategy; - bg::strategy::area::area_geographic < pt_geo_type, - geo_strategy, - 5, - true + bg::formula::vincenty_inverse, + 5 > area_geographic; bg::model::polygon geometry_geo; From 3aaef83dee90b197f41833b26cb5f60ecce7c1c1 Mon Sep 17 00:00:00 2001 From: Vissarion Fysikopoulos Date: Thu, 1 Sep 2016 12:17:28 +0300 Subject: [PATCH 17/89] [test] [formulas] [vertex_latitude] Fixes and more tests. --- .../geometry/formulas/vertex_latitude.hpp | 14 +++----- test/algorithms/vertex_latitude.cpp | 32 +++++++++---------- 2 files changed, 19 insertions(+), 27 deletions(-) diff --git a/include/boost/geometry/formulas/vertex_latitude.hpp b/include/boost/geometry/formulas/vertex_latitude.hpp index cb0a745ac..7f78b69af 100644 --- a/include/boost/geometry/formulas/vertex_latitude.hpp +++ b/include/boost/geometry/formulas/vertex_latitude.hpp @@ -24,7 +24,8 @@ a point on the geodesic that maximizes (or minimizes) the latitude. template < typename CT, - template class Inverse + template class Inverse, + bool north > class vertex_latitude { @@ -39,8 +40,7 @@ public: T1 const& lat1, T2 const& lon2, T2 const& lat2, - Spheroid const& spheroid, - bool north) + Spheroid const& spheroid) { CT const a = get_radius<0>(spheroid); CT const f = detail::flattening(spheroid); @@ -51,17 +51,11 @@ public: // and zero (false) otherwise. bool sign = std::signbit(std::abs(lat1) > std::abs(lat2) ? lat1 : lat2); - inverse_result i_res = inverse_type::apply(lon1, lat1, lon2, lat2, - spheroid); + inverse_result i_res = inverse_type::apply(lon1, lat1, lon2, lat2, spheroid); CT const alp1 = std::abs(i_res.azimuth); CT const alp2 = std::abs(i_res.reverse_azimuth); - //std::cout << "a1=" << alp1 * 180 / math::pi() - // << " a2=" - // << alp2 * 180 / math::pi() - // << std::endl; - // if the segment does not contain the vertex of the geodesic // then return the endpoint of max (min) latitude if ((alp1 < half_pi && alp2 < half_pi) diff --git a/test/algorithms/vertex_latitude.cpp b/test/algorithms/vertex_latitude.cpp index 96a80cd33..63cff28fa 100644 --- a/test/algorithms/vertex_latitude.cpp +++ b/test/algorithms/vertex_latitude.cpp @@ -8,22 +8,13 @@ // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#include -#include -#include - -#include - -#include +#include +#include #include #include #include #include -#include - -#include - template < template class Inverse, typename P, @@ -36,15 +27,13 @@ void test_vertex_lat(P p1, P p2, CT expected_max, CT expected_min, CT error = 0. p20 = bg::get_as_radian<0>(p2), p21 = bg::get_as_radian<1>(p2); - bg::formula::vertex_latitude vrt_lat; - - CT p_max = vrt_lat.apply(p10, p11, p20, p21, - bg::srs::spheroid(), true); + CT p_max = bg::formula::vertex_latitude + ::apply(p10, p11, p20, p21, bg::srs::spheroid()); CT p_max_degree = p_max * 180 / bg::math::pi(); BOOST_CHECK_CLOSE(p_max_degree, expected_max, error); - CT p_min = vrt_lat.apply(p10, p11, p20, p21, - bg::srs::spheroid(), false); + CT p_min = bg::formula::vertex_latitude + ::apply(p10, p11, p20, p21, bg::srs::spheroid()); CT p_min_degree = p_min * 180 / bg::math::pi(); BOOST_CHECK_CLOSE(p_min_degree, expected_min, error); } @@ -84,6 +73,15 @@ void test_all() (Pg(1, 1), Pg(10, 1), 1.0031124504591062, 1.0, 0.00000001); test_vertex_lat (Pg(1, 1), Pg(10, 1), 1.0031124508942098, 1.0, 0.00000001); + + // Meridian and equator + test_vertex_lat(Pg(1, 10), Pg(1, -10), 10.0, -10.0); + test_vertex_lat(Pg(1, 0), Pg(10, 0), 0.0, 0.0); + + // One endpoint in northern hemisphere and the other in southern hemisphere + test_vertex_lat(Pg(1, 1), Pg(150, -5), 1.0, -8.1825389632359933); + test_vertex_lat(Pg(150, -5), Pg(1, 1), 1.0, -8.1825389632359933); + test_vertex_lat(Pg(150, 5), Pg(1, -1), 8.1825389632359933, -1.0); } int test_main( int , char* [] ) From 2ba4c0b23a3b5c19a08507027b48f59590c71691 Mon Sep 17 00:00:00 2001 From: Vissarion Fysikopoulos Date: Thu, 1 Sep 2016 17:08:15 +0300 Subject: [PATCH 18/89] [formulas] Vertex latitude in spherical using spherical_azimuth formulas --- .../geometry/algorithms/detail/azimuth.hpp | 20 ++----- include/boost/geometry/formulas/spherical.hpp | 51 ++++++++++++++++++ .../geometry/formulas/vertex_latitude.hpp | 54 ++++++++++++++----- 3 files changed, 95 insertions(+), 30 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/azimuth.hpp b/include/boost/geometry/algorithms/detail/azimuth.hpp index 7e0d1691e..f62c64f9f 100644 --- a/include/boost/geometry/algorithms/detail/azimuth.hpp +++ b/include/boost/geometry/algorithms/detail/azimuth.hpp @@ -5,6 +5,7 @@ // This file was modified by Oracle on 2014, 2016. // Modifications copyright (c) 2014-2016, Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fysikopoulos, 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, @@ -69,22 +70,9 @@ struct azimuth template static inline ReturnType apply(P1 const& p1, P2 const& p2, Sphere const& /*unused*/) { - // http://williams.best.vwh.net/avform.htm#Crs - ReturnType dlon = get_as_radian<0>(p2) - get_as_radian<0>(p1); - ReturnType cos_p2lat = cos(get_as_radian<1>(p2)); - - // An optimization which should kick in often for Boxes - //if ( math::equals(dlon, ReturnType(0)) ) - //if ( get<0>(p1) == get<0>(p2) ) - //{ - // return - sin(get_as_radian<1>(p1)) * cos_p2lat); - //} - - // "An alternative formula, not requiring the pre-computation of d" - // In the formula below dlon is used as "d" - return atan2(sin(dlon) * cos_p2lat, - cos(get_as_radian<1>(p1)) * sin(get_as_radian<1>(p2)) - - sin(get_as_radian<1>(p1)) * cos_p2lat * cos(dlon)); + return geometry::formula::spherical_azimuth + ( get_as_radian<0>(p1), get_as_radian<1>(p1), + get_as_radian<0>(p2), get_as_radian<1>(p2)).azimuth; } template diff --git a/include/boost/geometry/formulas/spherical.hpp b/include/boost/geometry/formulas/spherical.hpp index 2195bbbe1..640105f37 100644 --- a/include/boost/geometry/formulas/spherical.hpp +++ b/include/boost/geometry/formulas/spherical.hpp @@ -1,6 +1,7 @@ // Boost.Geometry // Copyright (c) 2016, Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fysikopoulos, 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, @@ -27,6 +28,18 @@ namespace boost { namespace geometry { namespace formula { +template +struct result_spherical +{ + result_spherical() + : azimuth(0) + , reverse_azimuth(0) + {} + + T azimuth; + T reverse_azimuth; +}; + template static inline Point3d sph_to_cart3d(PointSph const& point_sph) { @@ -89,6 +102,44 @@ static inline int sph_side_value(Point3d1 const& norm, Point3d2 const& pt) : -1; // d < 0 } +template +static inline result_spherical spherical_azimuth(T1 const& lon1, + T1 const& lat1, + T2 const& lon2, + T2 const& lat2, + bool reverse_azimuth = false) +{ + typedef result_spherical result_type; + result_type result; + + // http://williams.best.vwh.net/avform.htm#Crs + // https://en.wikipedia.org/wiki/Great-circle_navigation + CT dlon = lon2 - lon1; + CT cos_dlon = cos(dlon); + CT sin_dlon = sin(dlon); + CT cos_lat1 = cos(lat1); + CT cos_lat2 = cos(lat2); + CT sin_lat1 = sin(lat1); + CT sin_lat2 = sin(lat2); + + // An optimization which should kick in often for Boxes + //if ( math::equals(dlon, ReturnType(0)) ) + //if ( get<0>(p1) == get<0>(p2) ) + //{ + // return - sin(get_as_radian<1>(p1)) * cos_p2lat); + //} + + // "An alternative formula, not requiring the pre-computation of d" + // In the formula below dlon is used as "d" + result.azimuth = atan2(sin_dlon * cos_lat2, + cos_lat1 * sin_lat2 - sin_lat1 * cos_lat2 * cos_dlon); + + result.reverse_azimuth = atan2(sin_dlon * cos_lat1, + sin_lat2 * cos_lat1 * cos_dlon - cos_lat2 * sin_lat1); + + return result; +} + } // namespace formula }} // namespace boost::geometry diff --git a/include/boost/geometry/formulas/vertex_latitude.hpp b/include/boost/geometry/formulas/vertex_latitude.hpp index 7f78b69af..ce7765c17 100644 --- a/include/boost/geometry/formulas/vertex_latitude.hpp +++ b/include/boost/geometry/formulas/vertex_latitude.hpp @@ -11,6 +11,8 @@ #ifndef BOOST_GEOMETRY_FORMULAS_MAXIMUM_LATITUDE_HPP #define BOOST_GEOMETRY_FORMULAS_MAXIMUM_LATITUDE_HPP +#include + namespace boost { namespace geometry { namespace formula { @@ -25,7 +27,8 @@ a point on the geodesic that maximizes (or minimizes) the latitude. template < typename CT, template class Inverse, - bool north + bool north, + bool spherical = false > class vertex_latitude { @@ -51,10 +54,22 @@ public: // and zero (false) otherwise. bool sign = std::signbit(std::abs(lat1) > std::abs(lat2) ? lat1 : lat2); - inverse_result i_res = inverse_type::apply(lon1, lat1, lon2, lat2, spheroid); + CT alp1, alp2; - CT const alp1 = std::abs(i_res.azimuth); - CT const alp2 = std::abs(i_res.reverse_azimuth); + if (spherical) + { + geometry::formula::result_spherical result = geometry::formula:: + spherical_azimuth(lon1, lat1, lon2, lat2); + alp1 = std::abs(result.azimuth); + alp2 = std::abs(result.reverse_azimuth); + } + else + { + inverse_result i_res = inverse_type::apply(lon1, lat1, lon2, lat2, spheroid); + + alp1 = std::abs(i_res.azimuth); + alp2 = std::abs(i_res.reverse_azimuth); + } // if the segment does not contain the vertex of the geodesic // then return the endpoint of max (min) latitude @@ -65,20 +80,31 @@ public: return north ? std::max(lat1, lat2) : std::min(lat1, lat2); } - CT const sin_alp1 = sin(alp1); - CT const sin_lat1 = sin(lat1); - CT const cos_lat1 = math::sqrt(CT(1) - math::sqr(sin_lat1)); + CT vertex_lat; - // normal radius at point p1(lon1,lat1) - CT const n_b1 = a / (math::sqrt(CT(1) - e2 * math::sqr(sin_lat1))); + if (spherical) + { + CT const cos2_lat1 = math::sqr(cos(lat1)); + CT const sin2_alp2 = math::sqr(sin(alp2)); + vertex_lat = std::asin(math::sqrt(1 - cos2_lat1 * sin2_alp2)); + } + else + { + CT const sin_alp1 = sin(alp1); + CT const sin2_lat1 = math::sqr(sin(lat1)); + CT const cos_lat1 = math::sqrt(CT(1) - sin2_lat1); - // the invariant of the geodesic - CT const c = n_b1 * cos_lat1 * sin_alp1; + // normal radius at point p1(lon1,lat1) + CT const n_b1 = a / (math::sqrt(CT(1) - e2 * sin2_lat1)); - CT const a_c2 = math::sqr(a / c); - CT const max_lat = std::asin(math::sqrt((a_c2 - 1) / (a_c2 - e2))); + // the invariant of the geodesic + CT const c = n_b1 * cos_lat1 * sin_alp1; - return (sign ? max_lat * CT(-1) : max_lat); + CT const a_c2 = math::sqr(a / c); + vertex_lat = std::asin(math::sqrt((a_c2 - 1) / (a_c2 - e2))); + } + + return (sign ? vertex_lat * CT(-1) : vertex_lat); } }; From 12d99a182769d516f004148c4ce2cf49707d03a8 Mon Sep 17 00:00:00 2001 From: Vissarion Fysikopoulos Date: Fri, 2 Sep 2016 15:01:37 +0300 Subject: [PATCH 19/89] [formulas] [vertex_latitude] Fix a typo in spehrical and add spherical tests --- .../geometry/algorithms/detail/azimuth.hpp | 2 +- include/boost/geometry/formulas/spherical.hpp | 15 ++- .../geometry/formulas/vertex_latitude.hpp | 121 ++++++++++-------- test/algorithms/vertex_latitude.cpp | 111 +++++++++++----- 4 files changed, 155 insertions(+), 94 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/azimuth.hpp b/include/boost/geometry/algorithms/detail/azimuth.hpp index f62c64f9f..db37c7d79 100644 --- a/include/boost/geometry/algorithms/detail/azimuth.hpp +++ b/include/boost/geometry/algorithms/detail/azimuth.hpp @@ -70,7 +70,7 @@ struct azimuth template static inline ReturnType apply(P1 const& p1, P2 const& p2, Sphere const& /*unused*/) { - return geometry::formula::spherical_azimuth + return geometry::formula::spherical_azimuth ( get_as_radian<0>(p1), get_as_radian<1>(p1), get_as_radian<0>(p2), get_as_radian<1>(p2)).azimuth; } diff --git a/include/boost/geometry/formulas/spherical.hpp b/include/boost/geometry/formulas/spherical.hpp index 640105f37..23269d644 100644 --- a/include/boost/geometry/formulas/spherical.hpp +++ b/include/boost/geometry/formulas/spherical.hpp @@ -102,12 +102,11 @@ static inline int sph_side_value(Point3d1 const& norm, Point3d2 const& pt) : -1; // d < 0 } -template +template static inline result_spherical spherical_azimuth(T1 const& lon1, T1 const& lat1, T2 const& lon2, - T2 const& lat2, - bool reverse_azimuth = false) + T2 const& lat2) { typedef result_spherical result_type; result_type result; @@ -132,10 +131,14 @@ static inline result_spherical spherical_azimuth(T1 const& lon1, // "An alternative formula, not requiring the pre-computation of d" // In the formula below dlon is used as "d" result.azimuth = atan2(sin_dlon * cos_lat2, - cos_lat1 * sin_lat2 - sin_lat1 * cos_lat2 * cos_dlon); + cos_lat1 * sin_lat2 - sin_lat1 * cos_lat2 * cos_dlon); - result.reverse_azimuth = atan2(sin_dlon * cos_lat1, - sin_lat2 * cos_lat1 * cos_dlon - cos_lat2 * sin_lat1); + if (ReverseAzimuth) + { + result.reverse_azimuth = + atan2(sin_dlon * cos_lat1, + sin_lat2 * cos_lat1 * cos_dlon - cos_lat2 * sin_lat1); + } return result; } diff --git a/include/boost/geometry/formulas/vertex_latitude.hpp b/include/boost/geometry/formulas/vertex_latitude.hpp index ce7765c17..bbd67841f 100644 --- a/include/boost/geometry/formulas/vertex_latitude.hpp +++ b/include/boost/geometry/formulas/vertex_latitude.hpp @@ -24,27 +24,67 @@ a point on the geodesic that maximizes (or minimizes) the latitude. 1996 */ -template < - typename CT, - template class Inverse, - bool north, - bool spherical = false -> +template class vertex_latitude { - typedef Inverse inverse_type; - typedef typename inverse_type::result_type inverse_result; - public: - template - static inline CT apply(T1 const& lon1, - T1 const& lat1, - T2 const& lon2, - T2 const& lat2, - Spheroid const& spheroid) + template < + bool north, + typename T1, + typename T2 + > + static inline CT spherical(T1 const& lon1, + T1 const& lat1, + T2 const& lon2, + T2 const& lat2) { + CT const half_pi = math::pi() / CT(2); + + // signbit returns a non-zero value (true) if the sign is negative; + // and zero (false) otherwise. + bool sign = std::signbit(std::abs(lat1) > std::abs(lat2) ? lat1 : lat2); + + geometry::formula::result_spherical result = geometry::formula:: + spherical_azimuth(lon1, lat1, lon2, lat2); + + CT const alp1 = std::abs(result.azimuth); + CT const alp2 = std::abs(result.reverse_azimuth); + + // if the segment does not contain the vertex of the geodesic + // then return the endpoint of max (min) latitude + if ((alp1 < half_pi && alp2 < half_pi) + || (alp1 > half_pi && alp2 > half_pi) + || (north == sign)) + { + return north ? std::max(lat1, lat2) : std::min(lat1, lat2); + } + + CT const cos2_lat1 = math::sqr(cos(lat1)); + CT const sin2_alp1 = math::sqr(sin(alp1)); + CT const vertex_lat = std::asin(math::sqrt(1 - cos2_lat1 * sin2_alp1)); + + return (sign ? vertex_lat * CT(-1) : vertex_lat); + } + + + template < + template class Inverse, + bool north, + typename T1, + typename T2, + typename Spheroid + > + static inline CT geographic(T1 const& lon1, + T1 const& lat1, + T2 const& lon2, + T2 const& lat2, + Spheroid const& spheroid) + { + typedef Inverse inverse_type; + typedef typename inverse_type::result_type inverse_result; + CT const a = get_radius<0>(spheroid); CT const f = detail::flattening(spheroid); CT const e2 = f * (CT(2) - f); @@ -54,55 +94,32 @@ public: // and zero (false) otherwise. bool sign = std::signbit(std::abs(lat1) > std::abs(lat2) ? lat1 : lat2); - CT alp1, alp2; + inverse_result i_res = inverse_type::apply(lon1, lat1, lon2, lat2, spheroid); - if (spherical) - { - geometry::formula::result_spherical result = geometry::formula:: - spherical_azimuth(lon1, lat1, lon2, lat2); - alp1 = std::abs(result.azimuth); - alp2 = std::abs(result.reverse_azimuth); - } - else - { - inverse_result i_res = inverse_type::apply(lon1, lat1, lon2, lat2, spheroid); - - alp1 = std::abs(i_res.azimuth); - alp2 = std::abs(i_res.reverse_azimuth); - } + CT const alp1 = std::abs(i_res.azimuth); + CT const alp2 = std::abs(i_res.reverse_azimuth); // if the segment does not contain the vertex of the geodesic // then return the endpoint of max (min) latitude if ((alp1 < half_pi && alp2 < half_pi) - || (alp1 > half_pi && alp2 > half_pi) - || (north == sign)) + || (alp1 > half_pi && alp2 > half_pi) + || (north == sign)) { return north ? std::max(lat1, lat2) : std::min(lat1, lat2); } - CT vertex_lat; + CT const sin_alp1 = sin(alp1); + CT const sin2_lat1 = math::sqr(sin(lat1)); + CT const cos_lat1 = math::sqrt(CT(1) - sin2_lat1); - if (spherical) - { - CT const cos2_lat1 = math::sqr(cos(lat1)); - CT const sin2_alp2 = math::sqr(sin(alp2)); - vertex_lat = std::asin(math::sqrt(1 - cos2_lat1 * sin2_alp2)); - } - else - { - CT const sin_alp1 = sin(alp1); - CT const sin2_lat1 = math::sqr(sin(lat1)); - CT const cos_lat1 = math::sqrt(CT(1) - sin2_lat1); + // normal radius at point p1(lon1,lat1) + CT const n_b1 = a / (math::sqrt(CT(1) - e2 * sin2_lat1)); - // normal radius at point p1(lon1,lat1) - CT const n_b1 = a / (math::sqrt(CT(1) - e2 * sin2_lat1)); + // the invariant of the geodesic + CT const c = n_b1 * cos_lat1 * sin_alp1; - // the invariant of the geodesic - CT const c = n_b1 * cos_lat1 * sin_alp1; - - CT const a_c2 = math::sqr(a / c); - vertex_lat = std::asin(math::sqrt((a_c2 - 1) / (a_c2 - e2))); - } + CT const a_c2 = math::sqr(a / c); + CT const vertex_lat = std::asin(math::sqrt((a_c2 - 1) / (a_c2 - e2))); return (sign ? vertex_lat * CT(-1) : vertex_lat); } diff --git a/test/algorithms/vertex_latitude.cpp b/test/algorithms/vertex_latitude.cpp index 63cff28fa..e5951085a 100644 --- a/test/algorithms/vertex_latitude.cpp +++ b/test/algorithms/vertex_latitude.cpp @@ -16,74 +16,115 @@ #include template < - template class Inverse, - typename P, - typename CT -> -void test_vertex_lat(P p1, P p2, CT expected_max, CT expected_min, CT error = 0.0001) + template class Inverse, + typename P, + typename CT + > +void test_vertex_lat(P p1, P p2, CT expected_max, CT expected_min, + CT expected_max_sph, CT expected_min_sph, CT error = 0.0001) { CT p10 = bg::get_as_radian<0>(p1), - p11 = bg::get_as_radian<1>(p1), - p20 = bg::get_as_radian<0>(p2), - p21 = bg::get_as_radian<1>(p2); + p11 = bg::get_as_radian<1>(p1), + p20 = bg::get_as_radian<0>(p2), + p21 = bg::get_as_radian<1>(p2); - CT p_max = bg::formula::vertex_latitude - ::apply(p10, p11, p20, p21, bg::srs::spheroid()); + CT p_max = bg::formula::vertex_latitude + ::template geographic + (p10, p11, p20, p21, bg::srs::spheroid()); CT p_max_degree = p_max * 180 / bg::math::pi(); BOOST_CHECK_CLOSE(p_max_degree, expected_max, error); - CT p_min = bg::formula::vertex_latitude - ::apply(p10, p11, p20, p21, bg::srs::spheroid()); + CT p_min = bg::formula::vertex_latitude + ::template geographic + (p10, p11, p20, p21, bg::srs::spheroid()); CT p_min_degree = p_min * 180 / bg::math::pi(); BOOST_CHECK_CLOSE(p_min_degree, expected_min, error); + + CT p_max_sph = bg::formula::vertex_latitude + ::template spherical(p10, p11, p20, p21); + CT p_max_degree_sph = p_max_sph * 180 / bg::math::pi(); + BOOST_CHECK_CLOSE(p_max_degree_sph, expected_max_sph, error); + + CT p_min_sph = bg::formula::vertex_latitude + ::template spherical(p10, p11, p20, p21); + CT p_min_degree_sph = p_min_sph * 180 / bg::math::pi(); + BOOST_CHECK_CLOSE(p_min_degree_sph, expected_min_sph, error); + } + template void test_all() { typedef bg::model::point > Pg; // Short segments - test_vertex_lat(Pg(1, 1), Pg(10, 5), 5.0, 1.0); - test_vertex_lat(Pg(1, 1), Pg(10, 1), 1.0031124506594733, 1.0); - test_vertex_lat(Pg(-5, 1), Pg(4, 1), 1.0031124506594733, 1.0); - test_vertex_lat(Pg(175, 1), Pg(184, 1), 1.0031124506594733, 1.0); - test_vertex_lat(Pg(355, 1), Pg(4, 1), 1.0031124506594733, 1.0); + test_vertex_lat + (Pg(1, 1), Pg(10, 5), 5.0, 1.0, 5.0, 1.0); + test_vertex_lat + (Pg(1, 1), Pg(10, 1), 1.0031124506594733, 1.0, 1.0030915676477881, 1.0); + test_vertex_lat + (Pg(-5, 1), Pg(4, 1), 1.0031124506594733, 1.0, 1.0030915676477881, 1.0); + test_vertex_lat + (Pg(175, 1), Pg(184, 1), 1.0031124506594733, 1.0, 1.0030915676477881, 1.0); + test_vertex_lat + (Pg(355, 1), Pg(4, 1), 1.0031124506594733, 1.0, 1.0030915676477881, 1.0); // Reverse direction - test_vertex_lat(Pg(1, 2), Pg(70, 1), 2.02397, 1.0); - test_vertex_lat(Pg(70, 1), Pg(1, 2), 2.02397, 1.0); + test_vertex_lat + (Pg(1, 2), Pg(70, 1), 2.0239716998355468, 1.0, 2.0228167431951536, 1.0); + test_vertex_lat + (Pg(70, 1), Pg(1, 2), 2.0239716998351849, 1.0, 2.022816743195063, 1.0); // Long segments - test_vertex_lat(Pg(0, 1), Pg(170, 1), 11.975026023950877, 1.0); - test_vertex_lat(Pg(0, 1), Pg(179, 1), 68.452669316418039, 1.0); - test_vertex_lat(Pg(0, 1), Pg(179.5, 1), 78.84050225214871, 1.0); - test_vertex_lat(Pg(0, 1), Pg(180.5, 1), 78.84050225214871, 1.0); - test_vertex_lat(Pg(0, 1), Pg(180, 1), 90.0, 1.0); + test_vertex_lat + (Pg(0, 1), Pg(170, 1), 11.975026023950877, 1.0, 11.325049479775814, 1.0); + test_vertex_lat + (Pg(0, 1), Pg(179, 1), 68.452669316418039, 1.0, 63.437566893227093, 1.0); + test_vertex_lat + (Pg(0, 1), Pg(179.5, 1), 78.84050225214871, 1.0, 75.96516822754981, 1.0); + test_vertex_lat + (Pg(0, 1), Pg(180.5, 1), 78.84050225214871, 1.0, 75.965168227550194, 1.0); + test_vertex_lat + (Pg(0, 1), Pg(180, 1), 90.0, 1.0, 90.0, 1.0); // South hemisphere - test_vertex_lat(Pg(1, -1), Pg(10, -5), -1.0, -5.0); - test_vertex_lat(Pg(1, -1), Pg(10, -1), -1.0, -1.0031124506594733); - test_vertex_lat(Pg(1, -1), Pg(170, -1), -1.0, -10.85834257048573); + test_vertex_lat + (Pg(1, -1), Pg(10, -5), -1.0, -5.0, -1.0, -5.0); + test_vertex_lat + (Pg(1, -1), Pg(10, -1), -1.0, -1.0031124506594733, -1.0, -1.0030915676477881); + test_vertex_lat + (Pg(1, -1), Pg(170, -1), -1.0, -10.85834257048573, -1.0, -10.321374780571153); // Different strategies for inverse test_vertex_lat - (Pg(1, 1), Pg(10, 1), 1.0031124506594733, 1.0, 0.00000001); + (Pg(1, 1), Pg(10, 1), 1.0031124506594733, 1.0, + 1.0030915676477881, 1.0, 0.00000001); test_vertex_lat - (Pg(1, 1), Pg(10, 1), 1.0031124504591062, 1.0, 0.00000001); + (Pg(1, 1), Pg(10, 1), 1.0031124504591062, 1.0, + 1.0030915676477881, 1.0, 0.00000001); test_vertex_lat - (Pg(1, 1), Pg(10, 1), 1.0031124508942098, 1.0, 0.00000001); + (Pg(1, 1), Pg(10, 1), 1.0031124508942098, 1.0, + 1.0030915676477881, 1.0, 0.00000001); // Meridian and equator - test_vertex_lat(Pg(1, 10), Pg(1, -10), 10.0, -10.0); - test_vertex_lat(Pg(1, 0), Pg(10, 0), 0.0, 0.0); + test_vertex_lat + (Pg(1, 10), Pg(1, -10), 10.0, -10.0, 10.0, -10.0); + test_vertex_lat + (Pg(1, 0), Pg(10, 0), 0.0, 0.0, 0.0, 0.0); // One endpoint in northern hemisphere and the other in southern hemisphere - test_vertex_lat(Pg(1, 1), Pg(150, -5), 1.0, -8.1825389632359933); - test_vertex_lat(Pg(150, -5), Pg(1, 1), 1.0, -8.1825389632359933); - test_vertex_lat(Pg(150, 5), Pg(1, -1), 8.1825389632359933, -1.0); + test_vertex_lat + (Pg(1, 1), Pg(150, -5), 1.0, -8.1825389632359933, 1.0, -8.0761230625567588); + test_vertex_lat + (Pg(150, -5), Pg(1, 1), 1.0, -8.1825389632359933, 1.0, -8.0761230625568015); + test_vertex_lat + (Pg(150, 5), Pg(1, -1), 8.1825389632359933, -1.0, 8.0761230625568015, -1.0); + } + + int test_main( int , char* [] ) { test_all(); From 86fbf6a204016f4b0909451d58f3f5f19c44ef39 Mon Sep 17 00:00:00 2001 From: Vissarion Fysikopoulos Date: Fri, 2 Sep 2016 17:40:30 +0300 Subject: [PATCH 20/89] [formulas] [vertex_latitude] Method returns both min and max vertex latitude at once. --- .../geometry/formulas/vertex_latitude.hpp | 122 ++++++++++-------- test/algorithms/vertex_latitude.cpp | 43 +++--- 2 files changed, 90 insertions(+), 75 deletions(-) diff --git a/include/boost/geometry/formulas/vertex_latitude.hpp b/include/boost/geometry/formulas/vertex_latitude.hpp index bbd67841f..97b55985b 100644 --- a/include/boost/geometry/formulas/vertex_latitude.hpp +++ b/include/boost/geometry/formulas/vertex_latitude.hpp @@ -30,21 +30,26 @@ class vertex_latitude public: + struct vertex_lat_result + { + vertex_lat_result() + : north(0), + south(0) + {} + + CT north, south; + }; + template < - bool north, typename T1, typename T2 > - static inline CT spherical(T1 const& lon1, - T1 const& lat1, - T2 const& lon2, - T2 const& lat2) + static inline vertex_lat_result spherical(T1 const& lon1, + T1 const& lat1, + T2 const& lon2, + T2 const& lat2) { - CT const half_pi = math::pi() / CT(2); - - // signbit returns a non-zero value (true) if the sign is negative; - // and zero (false) otherwise. - bool sign = std::signbit(std::abs(lat1) > std::abs(lat2) ? lat1 : lat2); + vertex_lat_result vrt_result; geometry::formula::result_spherical result = geometry::formula:: spherical_azimuth(lon1, lat1, lon2, lat2); @@ -52,76 +57,89 @@ public: CT const alp1 = std::abs(result.azimuth); CT const alp2 = std::abs(result.reverse_azimuth); - // if the segment does not contain the vertex of the geodesic - // then return the endpoint of max (min) latitude - if ((alp1 < half_pi && alp2 < half_pi) - || (alp1 > half_pi && alp2 > half_pi) - || (north == sign)) + if(vertex_on_segment(alp1, alp2, lat1, lat2, vrt_result)) { - return north ? std::max(lat1, lat2) : std::min(lat1, lat2); + CT const cos2_lat1 = math::sqr(cos(lat1)); + CT const sin2_alp1 = math::sqr(sin(alp1)); + CT const vertex_lat = std::asin(math::sqrt(1 - cos2_lat1 * sin2_alp1)); + + sign_adjastment(lat1, lat2, vertex_lat, vrt_result); } - - CT const cos2_lat1 = math::sqr(cos(lat1)); - CT const sin2_alp1 = math::sqr(sin(alp1)); - CT const vertex_lat = std::asin(math::sqrt(1 - cos2_lat1 * sin2_alp1)); - - return (sign ? vertex_lat * CT(-1) : vertex_lat); + return vrt_result; } template < template class Inverse, - bool north, typename T1, typename T2, typename Spheroid > - static inline CT geographic(T1 const& lon1, + static inline vertex_lat_result geographic(T1 const& lon1, T1 const& lat1, T2 const& lon2, T2 const& lat2, Spheroid const& spheroid) { + vertex_lat_result vrt_result; + typedef Inverse inverse_type; typedef typename inverse_type::result_type inverse_result; - - CT const a = get_radius<0>(spheroid); - CT const f = detail::flattening(spheroid); - CT const e2 = f * (CT(2) - f); - CT const half_pi = math::pi() / CT(2); - - // signbit returns a non-zero value (true) if the sign is negative; - // and zero (false) otherwise. - bool sign = std::signbit(std::abs(lat1) > std::abs(lat2) ? lat1 : lat2); - inverse_result i_res = inverse_type::apply(lon1, lat1, lon2, lat2, spheroid); CT const alp1 = std::abs(i_res.azimuth); CT const alp2 = std::abs(i_res.reverse_azimuth); + if(vertex_on_segment(alp1, alp2, lat1, lat2, vrt_result)) + { + CT const a = get_radius<0>(spheroid); + CT const f = detail::flattening(spheroid); + CT const e2 = f * (CT(2) - f); + + CT const sin_alp1 = sin(alp1); + CT const sin2_lat1 = math::sqr(sin(lat1)); + CT const cos_lat1 = math::sqrt(CT(1) - sin2_lat1); + + // normal radius at point p1(lon1,lat1) + CT const n_b1 = a / (math::sqrt(CT(1) - e2 * sin2_lat1)); + + // the invariant of the geodesic + CT const c = n_b1 * cos_lat1 * sin_alp1; + + CT const a_c2 = math::sqr(a / c); + CT const vertex_lat = std::asin(math::sqrt((a_c2 - 1) / (a_c2 - e2))); + + sign_adjastment(lat1, lat2, vertex_lat, vrt_result); + } + return vrt_result; + } + + template + inline static void sign_adjastment(CT lat1, CT lat2, CT vertex_lat, T& vrt_result) + { + // signbit returns a non-zero value (true) if the sign is negative; + // and zero (false) otherwise. + bool sign = std::signbit(std::abs(lat1) > std::abs(lat2) ? lat1 : lat2); + + vrt_result.north = sign ? std::max(lat1, lat2) : vertex_lat; + vrt_result.south = sign ? vertex_lat * CT(-1) : std::min(lat1, lat2); + } + + template + inline static bool vertex_on_segment(CT alp1, CT alp2, CT lat1, CT lat2, T& vrt_result) + { + CT const half_pi = math::pi() / CT(2); + // if the segment does not contain the vertex of the geodesic // then return the endpoint of max (min) latitude if ((alp1 < half_pi && alp2 < half_pi) - || (alp1 > half_pi && alp2 > half_pi) - || (north == sign)) + || (alp1 > half_pi && alp2 > half_pi)) { - return north ? std::max(lat1, lat2) : std::min(lat1, lat2); + vrt_result.north = std::max(lat1, lat2); + vrt_result.south = std::min(lat1, lat2); + return false; } - - CT const sin_alp1 = sin(alp1); - CT const sin2_lat1 = math::sqr(sin(lat1)); - CT const cos_lat1 = math::sqrt(CT(1) - sin2_lat1); - - // normal radius at point p1(lon1,lat1) - CT const n_b1 = a / (math::sqrt(CT(1) - e2 * sin2_lat1)); - - // the invariant of the geodesic - CT const c = n_b1 * cos_lat1 * sin_alp1; - - CT const a_c2 = math::sqr(a / c); - CT const vertex_lat = std::asin(math::sqrt((a_c2 - 1) / (a_c2 - e2))); - - return (sign ? vertex_lat * CT(-1) : vertex_lat); + return true; } }; diff --git a/test/algorithms/vertex_latitude.cpp b/test/algorithms/vertex_latitude.cpp index e5951085a..1a3fe7027 100644 --- a/test/algorithms/vertex_latitude.cpp +++ b/test/algorithms/vertex_latitude.cpp @@ -19,37 +19,34 @@ template < template class Inverse, typename P, typename CT - > +> void test_vertex_lat(P p1, P p2, CT expected_max, CT expected_min, CT expected_max_sph, CT expected_min_sph, CT error = 0.0001) { CT p10 = bg::get_as_radian<0>(p1), - p11 = bg::get_as_radian<1>(p1), - p20 = bg::get_as_radian<0>(p2), - p21 = bg::get_as_radian<1>(p2); + p11 = bg::get_as_radian<1>(p1), + p20 = bg::get_as_radian<0>(p2), + p21 = bg::get_as_radian<1>(p2); - CT p_max = bg::formula::vertex_latitude - ::template geographic - (p10, p11, p20, p21, bg::srs::spheroid()); - CT p_max_degree = p_max * 180 / bg::math::pi(); + typename bg::formula::vertex_latitude::vertex_lat_result p_max + = bg::formula::vertex_latitude::template geographic + (p10, p11, p20, p21, bg::srs::spheroid()); + + CT p_max_degree = p_max.north * 180 / bg::math::pi(); BOOST_CHECK_CLOSE(p_max_degree, expected_max, error); - CT p_min = bg::formula::vertex_latitude - ::template geographic - (p10, p11, p20, p21, bg::srs::spheroid()); - CT p_min_degree = p_min * 180 / bg::math::pi(); + CT p_min_degree = p_max.south * 180 / bg::math::pi(); BOOST_CHECK_CLOSE(p_min_degree, expected_min, error); - CT p_max_sph = bg::formula::vertex_latitude - ::template spherical(p10, p11, p20, p21); - CT p_max_degree_sph = p_max_sph * 180 / bg::math::pi(); + typename bg::formula::vertex_latitude::vertex_lat_result p_max_sph + = bg::formula::vertex_latitude::template spherical + (p10, p11, p20, p21); + + CT p_max_degree_sph = p_max_sph.north * 180 / bg::math::pi(); BOOST_CHECK_CLOSE(p_max_degree_sph, expected_max_sph, error); - CT p_min_sph = bg::formula::vertex_latitude - ::template spherical(p10, p11, p20, p21); - CT p_min_degree_sph = p_min_sph * 180 / bg::math::pi(); + CT p_min_degree_sph = p_max_sph.south * 180 / bg::math::pi(); BOOST_CHECK_CLOSE(p_min_degree_sph, expected_min_sph, error); - } @@ -61,6 +58,7 @@ void test_all() // Short segments test_vertex_lat (Pg(1, 1), Pg(10, 5), 5.0, 1.0, 5.0, 1.0); + test_vertex_lat (Pg(1, 1), Pg(10, 1), 1.0031124506594733, 1.0, 1.0030915676477881, 1.0); test_vertex_lat @@ -99,13 +97,13 @@ void test_all() // Different strategies for inverse test_vertex_lat (Pg(1, 1), Pg(10, 1), 1.0031124506594733, 1.0, - 1.0030915676477881, 1.0, 0.00000001); + 1.0030915676477881, 1.0, 0.00000001); test_vertex_lat (Pg(1, 1), Pg(10, 1), 1.0031124504591062, 1.0, - 1.0030915676477881, 1.0, 0.00000001); + 1.0030915676477881, 1.0, 0.00000001); test_vertex_lat (Pg(1, 1), Pg(10, 1), 1.0031124508942098, 1.0, - 1.0030915676477881, 1.0, 0.00000001); + 1.0030915676477881, 1.0, 0.00000001); // Meridian and equator test_vertex_lat @@ -120,7 +118,6 @@ void test_all() (Pg(150, -5), Pg(1, 1), 1.0, -8.1825389632359933, 1.0, -8.0761230625568015); test_vertex_lat (Pg(150, 5), Pg(1, -1), 8.1825389632359933, -1.0, 8.0761230625568015, -1.0); - } From a40bbbc69cf5bda768778bcf24ade957a79863a4 Mon Sep 17 00:00:00 2001 From: Mats Taraldsvik Date: Mon, 5 Sep 2016 20:16:16 +0200 Subject: [PATCH 21/89] [algorithms] Added equals for MultiPoint --- include/boost/geometry/algorithms/equals.hpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/include/boost/geometry/algorithms/equals.hpp b/include/boost/geometry/algorithms/equals.hpp index 0f0bdde58..36c648829 100644 --- a/include/boost/geometry/algorithms/equals.hpp +++ b/include/boost/geometry/algorithms/equals.hpp @@ -242,6 +242,20 @@ struct equals > {}; +template +struct equals + : detail::equals::equals_by_relate +{}; + +template +struct equals + : detail::equals::equals_by_relate +{}; + +template +struct equals + : detail::equals::equals_by_relate +{}; template struct equals @@ -285,7 +299,6 @@ struct equals struct equals - //: detail::equals::equals_by_collection : detail::equals::equals_by_relate {}; From 7555eb3ccc6285217d5479713a1964528085360b Mon Sep 17 00:00:00 2001 From: Mats Taraldsvik Date: Mon, 5 Sep 2016 20:14:39 +0200 Subject: [PATCH 22/89] [io][wkb] Implement support for reading Multi-geometries Adds support for reading Multi-geometries in the WKB data format. --- extensions/test/gis/io/wkb/read_wkb.cpp | 239 ++++++++++++++++- .../extensions/gis/io/wkb/detail/ogc.hpp | 25 +- .../extensions/gis/io/wkb/detail/parser.hpp | 49 +++- .../extensions/gis/io/wkb/read_wkb.hpp | 36 +-- .../multi/gis/io/wkb/detail/parser.hpp | 248 ++++++++++++++++++ .../extensions/multi/gis/io/wkb/read_wkb.hpp | 62 +++++ 6 files changed, 613 insertions(+), 46 deletions(-) create mode 100644 include/boost/geometry/extensions/multi/gis/io/wkb/detail/parser.hpp create mode 100644 include/boost/geometry/extensions/multi/gis/io/wkb/read_wkb.hpp diff --git a/extensions/test/gis/io/wkb/read_wkb.cpp b/extensions/test/gis/io/wkb/read_wkb.cpp index eae9301e8..95e7f525a 100644 --- a/extensions/test/gis/io/wkb/read_wkb.cpp +++ b/extensions/test/gis/io/wkb/read_wkb.cpp @@ -27,6 +27,12 @@ #include #include +#include +#include +#include + +#include + namespace bg = boost::geometry; namespace { // anonymous @@ -42,6 +48,15 @@ void test_geometry_wrong_wkb(std::string const& wkbhex, std::string const& wkt) BOOST_MESSAGE("read_wkb: " << bg::read_wkb(wkb.begin(), wkb.end(), g_wkb)); } +template +void test_geometry_parse_failure(std::string const& wkbhex, std::string const& wkt) +{ + byte_vector wkb; + BOOST_CHECK( bg::hex2wkb(wkbhex, std::back_inserter(wkb)) ); + Geometry g_wkb; + BOOST_CHECK( bg::read_wkb(wkb.begin(), wkb.end(), g_wkb) == false ); +} + template void test_geometry_equals_old(std::string const& wkbhex, std::string const& wkt) { @@ -130,16 +145,17 @@ int test_main(int, char* []) // "POINT (1.234 5.678)"); } + + typedef bg::model::point point_type; + typedef bg::model::point point3d_type; + + typedef bg::model::linestring linestring_type; + //typedef bg::model::linestring linestring3d_type; + + typedef bg::model::polygon polygon_type; + //typedef bg::model::polygon polygon3d_type; { - typedef bg::model::point point_type; - typedef bg::model::point point3d_type; - - typedef bg::model::linestring linestring_type; - //typedef bg::model::linestring linestring3d_type; - - typedef bg::model::polygon polygon_type; - //typedef bg::model::polygon polygon3d_type; // // POINT @@ -165,6 +181,16 @@ int test_main(int, char* []) ); } + { + point3d_type point(1.234, 5.678, 99.0); + + test_geometry_equals + ( + point, + "01e90300005839b4c876bef33f83c0caa145b616400000000000c05840" + ); + } + // // LINESTRING // @@ -185,6 +211,30 @@ int test_main(int, char* []) "010200000003000000000000000000F03F00000000000000400000000000000040000000000000084000000000000010400000000000001440" ); } + + + { + linestring_type linestring; + + bg::append(linestring, + boost::assign::list_of + (point_type(1.234, 5.678)) + (point_type(9.1011, 10.1112)) + (point_type(13.1415, 16.1718)) + ); + + test_geometry_equals + ( + linestring, + "0102000000030000005839B4C876BEF33F83C0CAA145B616404F401361C333224062A1D634EF3824409CC420B072482A40EB73B515FB2B3040" + ); + + test_geometry_equals + ( + linestring, + "0102000080030000005839B4C876BEF33F83C0CAA145B616400000000000C058404F401361C333224062A1D634EF3824400000000000C058409CC420B072482A40EB73B515FB2B30400000000000C05840" + ); + } // { // linestring3d_type linestring; @@ -225,7 +275,26 @@ int test_main(int, char* []) "010300000001000000050000000000000000004940000000000000494000000000000049400000000000005940000000000000594000000000000059400000000000005940000000000000494000000000000049400000000000004940" ); } + + { + polygon_type polygon; + bg::append(polygon, + boost::assign::list_of + (point_type(100.0, 200.0)) + (point_type(200.0, 200.0)) + (point_type(200.0, 400.0)) + (point_type(100.0, 400.0)) + (point_type(100.0, 200.0)) + ); + + test_geometry_equals + ( + polygon, + "010300000001000000050000000000000000005940000000000000694000000000000069400000000000006940000000000000694000000000000079400000000000005940000000000000794000000000000059400000000000006940" + ); + } + // { // polygon3d_type polygon; // @@ -251,7 +320,7 @@ int test_main(int, char* []) ); // Create an interior ring (append does not do this automatically) - boost::geometry::interior_rings(polygon).resize(1); + polygon.inners().resize(1); bg::append(polygon, boost::assign::list_of @@ -269,6 +338,158 @@ int test_main(int, char* []) } } + + // + // Multi Geometries + // + + typedef bg::model::multi_point multipoint_type; + typedef bg::model::multi_linestring multilinestring_type; + typedef bg::model::multi_polygon multipolygon_type; + + // + // MultiPoint + // + + { + multipoint_type multipoint; + + bg::append(multipoint, + boost::assign::list_of + (point_type(1.234, 5.678)) + ); + test_geometry_equals + ( + multipoint, + "01040000000100000001010000005839b4c876bef33f83c0caa145b61640" + ); + } + + { + multipoint_type multipoint; + + bg::append(multipoint, + boost::assign::list_of + (point_type(1.234, 5.678)) + (point_type(10.1112, 13.1415)) + ); + + test_geometry_equals + ( + multipoint, + "01040000000200000001010000005839b4c876bef33f83c0caa145b61640010100000062a1d634ef3824409cc420b072482a40" + ); + } + + // + // MultiLineString + // + + { + multilinestring_type multilinestring; + + // Create linestrings (append does not do this automatically) + multilinestring.resize(1); + + bg::append(multilinestring[0], + boost::assign::list_of + (point_type(1.234, 5.678)) + (point_type(9.1011, 10.1112)) + (point_type(13.1415, 16.1718)) + ); + + test_geometry_equals + ( + multilinestring, + "0105000000010000000102000000030000005839b4c876bef33f83c0caa145b616404f401361c333224062a1d634ef3824409cc420b072482a40eb73b515fb2b3040" + ); + } + + { + multilinestring_type multilinestring; + + // Create linestrings (append does not do this automatically) + multilinestring.resize(2); + + bg::append(multilinestring[0], + boost::assign::list_of + (point_type(1.234, 5.678)) + (point_type(9.1011, 10.1112)) + (point_type(13.1415, 16.1718)) + ); + + bg::append(multilinestring[1], + boost::assign::list_of + (point_type(19.2, 21.22)) + (point_type(23.24, 25.26)) + ); + + test_geometry_equals + ( + multilinestring, +"0105000000020000000102000000030000005839b4c876bef33f83c0caa145b616404f401361c333224062a1d634ef3824409cc420b072482a40eb73b515fb2b30400102000000020000003333333333333340b81e85eb513835403d0ad7a3703d3740c3f5285c8f423940" + ); + } + + // + // MultiPolygon + // + + { + multipolygon_type multipolygon; + + // Create polygons (append does not do this automatically) + multipolygon.resize(1); + + bg::append(multipolygon[0], + boost::assign::list_of + (point_type(100, 200)) + (point_type(200, 200)) + (point_type(200, 400)) + (point_type(100, 400)) + (point_type(100, 200)) + ); + + test_geometry_equals + ( + multipolygon, +"010600000001000000010300000001000000050000000000000000005940000000000000694000000000000069400000000000006940000000000000694000000000000079400000000000005940000000000000794000000000000059400000000000006940" + ); + } + + { + multipolygon_type multipolygon; + + // Create polygons (append does not do this automatically) + multipolygon.resize(1); + // Create an interior ring (append does not do this automatically) + multipolygon[0].inners().resize(1); + + bg::append(multipolygon[0], + boost::assign::list_of + (point_type(35, 10)) + (point_type(10, 20)) + (point_type(15, 40)) + (point_type(45, 45)) + (point_type(35, 10)) + ); + + bg::append(multipolygon[0], + boost::assign::list_of + (point_type(20, 30)) + (point_type(35, 35)) + (point_type(30, 20)) + (point_type(20, 30)), + 0 + ); + + test_geometry_equals + ( + multipolygon, +"0106000000010000000103000000020000000500000000000000008041400000000000002440000000000000244000000000000034400000000000002e40000000000000444000000000008046400000000000804640000000000080414000000000000024400400000000000000000034400000000000003e40000000000080414000000000008041400000000000003e40000000000000344000000000000034400000000000003e40" + ); + } + return 0; } diff --git a/include/boost/geometry/extensions/gis/io/wkb/detail/ogc.hpp b/include/boost/geometry/extensions/gis/io/wkb/detail/ogc.hpp index b85447347..523461009 100644 --- a/include/boost/geometry/extensions/gis/io/wkb/detail/ogc.hpp +++ b/include/boost/geometry/extensions/gis/io/wkb/detail/ogc.hpp @@ -68,12 +68,10 @@ struct geometry_type_ogc { point = 1, linestring = 2, - polygon = 3 - - // TODO: Not implemented - //multipoint = 4, - //multilinestring = 5, - //multipolygon = 6, + polygon = 3, + multipoint = 4, + multilinestring = 5, + multipolygon = 6, //collection = 7 }; }; @@ -169,6 +167,21 @@ struct geometry_type : geometry_type_impl {}; +template +struct geometry_type + : geometry_type_impl +{}; + +template +struct geometry_type + : geometry_type_impl +{}; + +template +struct geometry_type + : geometry_type_impl +{}; + }} // namespace detail::wkb #endif // DOXYGEN_NO_IMPL diff --git a/include/boost/geometry/extensions/gis/io/wkb/detail/parser.hpp b/include/boost/geometry/extensions/gis/io/wkb/detail/parser.hpp index 8c649d659..0e6758e03 100644 --- a/include/boost/geometry/extensions/gis/io/wkb/detail/parser.hpp +++ b/include/boost/geometry/extensions/gis/io/wkb/detail/parser.hpp @@ -15,6 +15,8 @@ #include #include +#include + #include #include #include @@ -33,6 +35,23 @@ namespace boost { namespace geometry { +/*! +\brief Read WKB Exception +\ingroup core +\details The read_wkb_exception is thrown when there is an error in wkb parsing + */ +class read_wkb_exception : public geometry::exception +{ +public: + + inline read_wkb_exception() {} + + virtual char const* what() const throw() + { + return "Boost.Geometry Read WKB exception"; + } +}; + #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace wkb { @@ -191,9 +210,12 @@ struct point_container_parser { return false; } - + typedef typename std::iterator_traits::difference_type size_type; - BOOST_GEOMETRY_ASSERT(num_points <= boost::uint32_t( (std::numeric_limits::max)() ) ); + if(num_points > (std::numeric_limits::max)() ) + { + throw boost::geometry::read_wkb_exception(); + } size_type const container_size = static_cast(num_points); size_type const point_size = dimension::value * sizeof(double); @@ -237,7 +259,11 @@ struct linestring_parser return false; } - BOOST_GEOMETRY_ASSERT(it != end); + if(it == end) + { + throw boost::geometry::read_wkb_exception(); + } + return point_container_parser::parse(it, end, linestring, order); } }; @@ -259,15 +285,15 @@ struct polygon_parser { return false; } - - typedef typename ring_type::type ring_type; + + typedef typename boost::geometry::ring_return_type::type ring_type; std::size_t rings_parsed = 0; while (rings_parsed < num_rings && it != end) { if (0 == rings_parsed) { - ring_type& ring0 = exterior_ring(polygon); + ring_type ring0 = exterior_ring(polygon); if (!point_container_parser::parse(it, end, ring0, order)) { return false; @@ -275,19 +301,16 @@ struct polygon_parser } else { - interior_rings(polygon).resize(rings_parsed); - ring_type& ringN = interior_rings(polygon).back(); + boost::geometry::range::resize(interior_rings(polygon), rings_parsed); + ring_type ringN = boost::geometry::range::back(interior_rings(polygon)); + if (!point_container_parser::parse(it, end, ringN, order)) { return false; } } - ++rings_parsed; - } - if (num_rings != rings_parsed) - { - return false; + ++rings_parsed; } return true; diff --git a/include/boost/geometry/extensions/gis/io/wkb/read_wkb.hpp b/include/boost/geometry/extensions/gis/io/wkb/read_wkb.hpp index 69662b584..73b4cd220 100644 --- a/include/boost/geometry/extensions/gis/io/wkb/read_wkb.hpp +++ b/include/boost/geometry/extensions/gis/io/wkb/read_wkb.hpp @@ -27,38 +27,38 @@ namespace dispatch template struct read_wkb {}; -template -struct read_wkb +template +struct read_wkb { template - static inline bool parse(Iterator& it, Iterator end, G& geometry, + static inline bool parse(Iterator& it, Iterator end, Geometry& geometry, detail::wkb::byte_order_type::enum_t order) { - return detail::wkb::point_parser::parse(it, end, geometry, order); + return detail::wkb::point_parser::parse(it, end, geometry, order); } }; -template -struct read_wkb +template +struct read_wkb { template - static inline bool parse(Iterator& it, Iterator end, G& geometry, + static inline bool parse(Iterator& it, Iterator end, Geometry& geometry, detail::wkb::byte_order_type::enum_t order) { geometry::clear(geometry); - return detail::wkb::linestring_parser::parse(it, end, geometry, order); + return detail::wkb::linestring_parser::parse(it, end, geometry, order); } }; -template -struct read_wkb +template +struct read_wkb { template - static inline bool parse(Iterator& it, Iterator end, G& geometry, + static inline bool parse(Iterator& it, Iterator end, Geometry& geometry, detail::wkb::byte_order_type::enum_t order) { geometry::clear(geometry); - return detail::wkb::polygon_parser::parse(it, end, geometry, order); + return detail::wkb::polygon_parser::parse(it, end, geometry, order); } }; @@ -66,8 +66,8 @@ struct read_wkb #endif // DOXYGEN_NO_DISPATCH -template -inline bool read_wkb(Iterator begin, Iterator end, G& geometry) +template +inline bool read_wkb(Iterator begin, Iterator end, Geometry& geometry) { // Stream of bytes can only be parsed using random access iterator. BOOST_STATIC_ASSERT(( @@ -82,16 +82,16 @@ inline bool read_wkb(Iterator begin, Iterator end, G& geometry) { return dispatch::read_wkb < - typename tag::type, - G + typename tag::type, + Geometry >::parse(begin, end, geometry, byte_order); } return false; } -template -inline bool read_wkb(ByteType const* bytes, std::size_t length, G& geometry) +template +inline bool read_wkb(ByteType const* bytes, std::size_t length, Geometry& geometry) { BOOST_STATIC_ASSERT((boost::is_integral::value)); BOOST_STATIC_ASSERT((sizeof(boost::uint8_t) == sizeof(ByteType))); diff --git a/include/boost/geometry/extensions/multi/gis/io/wkb/detail/parser.hpp b/include/boost/geometry/extensions/multi/gis/io/wkb/detail/parser.hpp new file mode 100644 index 000000000..30009af4c --- /dev/null +++ b/include/boost/geometry/extensions/multi/gis/io/wkb/detail/parser.hpp @@ -0,0 +1,248 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. + +// 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_MULTI_IO_WKB_DETAIL_PARSER_HPP +#define BOOST_GEOMETRY_MULTI_IO_WKB_DETAIL_PARSER_HPP + +#include +#include +#include + +#include + +#include +#include +#include + + +#include +#include +#include + +#include + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace wkb +{ + +template +struct multipoint_parser +{ + template + static bool parse(Iterator& it, Iterator end, MultiPoint& multipoint, byte_order_type::enum_t order) + { + if (!geometry_type_parser::parse(it, end, order)) + { + return false; + } + + boost::uint32_t num_points(0); + if (!value_parser::parse(it, end, num_points, order)) + { + return false; + } + + // Check that the number of double values in the stream is equal + // or greater than the number of expected values in the multipoint + + typedef typename std::iterator_traits::difference_type size_type; + + typedef typename point_type::type point_type; + + size_type const container_byte_size = dimension::value * num_points * sizeof(double) + + num_points * sizeof(boost::uint8_t) + + num_points * sizeof(boost::uint32_t); + + size_type const stream_byte_size = std::distance(it,end); + + if(stream_byte_size < container_byte_size) + { + throw boost::geometry::read_wkb_exception(); + } + + point_type point_buffer; + std::back_insert_iterator output(std::back_inserter(multipoint)); + + typedef typename std::iterator_traits::difference_type size_type; + if(num_points > (std::numeric_limits::max)() ) + { + throw boost::geometry::read_wkb_exception(); + } + + size_type points_parsed = 0; + while (points_parsed < num_points && it != end) + { + detail::wkb::byte_order_type::enum_t point_byte_order; + if (!detail::wkb::byte_order_parser::parse(it, end, point_byte_order)) + { + return false; + } + + if (!geometry_type_parser::parse(it, end, point_byte_order)) + { + return false; + } + + parsing_assigner::value>::run(it, end, point_buffer, point_byte_order); + + output = point_buffer; + + ++output; + ++points_parsed; + } + return true; + } +}; + +template +struct multilinestring_parser +{ + template + static bool parse(Iterator& it, Iterator end, MultiLinestring& multilinestring, byte_order_type::enum_t order) + { + typedef typename MultiLinestring::value_type linestring_type; + typedef typename point_type::type point_type; + + if (!geometry_type_parser::parse(it, end, order)) + { + return false; + } + + boost::uint32_t num_linestrings(0); + if (!value_parser::parse(it, end, num_linestrings, order)) + { + return false; + } + + std::back_insert_iterator output(std::back_inserter(multilinestring)); + + typedef typename std::iterator_traits::difference_type size_type; + if(num_linestrings > (std::numeric_limits::max)() ) + { + throw boost::geometry::read_wkb_exception(); + } + + size_type linestrings_parsed = 0; + while (linestrings_parsed < num_linestrings && it != end) + { + linestring_type linestring_buffer; + + detail::wkb::byte_order_type::enum_t linestring_byte_order; + if (!detail::wkb::byte_order_parser::parse(it, end, linestring_byte_order)) + { + return false; + } + + if (!geometry_type_parser::parse(it, end, order)) + { + return false; + } + + if(!point_container_parser::parse(it, end, linestring_buffer, linestring_byte_order)) + { + return false; + } + + output = linestring_buffer; + + ++output; + ++linestrings_parsed; + } + return true; + } +}; + +template +struct multipolygon_parser +{ + template + static bool parse(Iterator& it, Iterator end, MultiPolygon& multipolygon, byte_order_type::enum_t order) + { + typedef typename boost::range_value::type polygon_type; + + if (!geometry_type_parser::parse(it, end, order)) + { + return false; + } + + boost::uint32_t num_polygons(0); + if (!value_parser::parse(it, end, num_polygons, order)) + { + return false; + } + + std::back_insert_iterator output(std::back_inserter(multipolygon)); + + std::size_t polygons_parsed = 0; + while(polygons_parsed < num_polygons && it != end) + { + polygon_type polygon_buffer; + + detail::wkb::byte_order_type::enum_t polygon_byte_order; + if (!detail::wkb::byte_order_parser::parse(it, end, polygon_byte_order)) + { + return false; + } + + if (!geometry_type_parser::parse(it, end, order)) + { + return false; + } + + boost::uint32_t num_rings(0); + if (!value_parser::parse(it, end, num_rings, polygon_byte_order)) + { + return false; + } + + std::size_t rings_parsed = 0; + + while (rings_parsed < num_rings && it != end) + { + typedef typename boost::geometry::ring_return_type::type ring_type; + + if (0 == rings_parsed) + { + ring_type ring0 = exterior_ring(polygon_buffer); + + if (!point_container_parser::parse(it, end, ring0, polygon_byte_order)) + { + return false; + } + } + else + { + boost::geometry::range::resize(interior_rings(polygon_buffer), rings_parsed); + ring_type ringN = boost::geometry::range::back(interior_rings(polygon_buffer)); + + if (!point_container_parser::parse(it, end, ringN, polygon_byte_order)) + { + return false; + } + } + ++rings_parsed; + } + + output = polygon_buffer; + ++output; + } + + return true; + } +}; + +}} // namespace detail::wkb +#endif // DOXYGEN_NO_IMPL + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_MULTI_IO_WKB_DETAIL_PARSER_HPP diff --git a/include/boost/geometry/extensions/multi/gis/io/wkb/read_wkb.hpp b/include/boost/geometry/extensions/multi/gis/io/wkb/read_wkb.hpp new file mode 100644 index 000000000..b8e3e65bd --- /dev/null +++ b/include/boost/geometry/extensions/multi/gis/io/wkb/read_wkb.hpp @@ -0,0 +1,62 @@ +// Boost.Geometry + +// Copyright (c) 2015 Mats Taraldsvik + +// 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_MULTI_IO_WKB_READ_WKB_HPP +#define BOOST_GEOMETRY_MULTI_IO_WKB_READ_WKB_HPP + +#include + +#include +#include + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template +struct read_wkb +{ + template + static inline bool parse(Iterator& it, Iterator end, Geometry& geometry, + detail::wkb::byte_order_type::enum_t order) + { + return detail::wkb::multipoint_parser::parse(it, end, geometry, order); + } +}; + +template +struct read_wkb +{ + template + static inline bool parse(Iterator& it, Iterator end, Geometry& geometry, + detail::wkb::byte_order_type::enum_t order) + { + return detail::wkb::multilinestring_parser::parse(it, end, geometry, order); + } +}; + +template +struct read_wkb +{ + template + static inline bool parse(Iterator& it, Iterator end, Geometry& geometry, + detail::wkb::byte_order_type::enum_t order) + { + return detail::wkb::multipolygon_parser::parse(it, end, geometry, order); + } +}; + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_MULTI_IO_WKB_READ_WKB_HPP From f41ec1880f34cb8ff5d378ad88add61421b4fc2e Mon Sep 17 00:00:00 2001 From: Mats Taraldsvik Date: Wed, 26 Aug 2015 20:15:41 +0200 Subject: [PATCH 23/89] [io][wkb] Implement support for writing Multi-geometries --- extensions/test/gis/io/wkb/write_wkb.cpp | 177 +++++++++++++++++- .../multi/gis/io/wkb/detail/writer.hpp | 145 ++++++++++++++ .../extensions/multi/gis/io/wkb/write_wkb.hpp | 66 +++++++ 3 files changed, 380 insertions(+), 8 deletions(-) create mode 100644 include/boost/geometry/extensions/multi/gis/io/wkb/detail/writer.hpp create mode 100644 include/boost/geometry/extensions/multi/gis/io/wkb/write_wkb.hpp diff --git a/extensions/test/gis/io/wkb/write_wkb.cpp b/extensions/test/gis/io/wkb/write_wkb.cpp index 3b71c0f17..1e87eae90 100644 --- a/extensions/test/gis/io/wkb/write_wkb.cpp +++ b/extensions/test/gis/io/wkb/write_wkb.cpp @@ -27,9 +27,17 @@ #include +#include +#include +#include + +#include + #include #include +#include + namespace bg = boost::geometry; namespace { // anonymous @@ -42,10 +50,11 @@ void test_geometry_equals(Geometry const& geometry, std::string const& wkbhex) std::string hex_out; BOOST_CHECK( bg::wkb2hex(wkb_out.begin(), wkb_out.end(), hex_out) ); - + + boost::algorithm::to_lower(hex_out); + BOOST_CHECK_EQUAL( wkbhex, hex_out); } - } // namespace anonymous int test_main(int, char* []) @@ -67,7 +76,7 @@ int test_main(int, char* []) test_geometry_equals ( point, - "0101000000000000000000F03F0000000000000040" + "0101000000000000000000f03f0000000000000040" ); } @@ -77,7 +86,7 @@ int test_main(int, char* []) test_geometry_equals ( point, - "01E9030000000000000000F03F00000000000000400000000000000840" + "01e9030000000000000000f03f00000000000000400000000000000840" ); } @@ -98,7 +107,7 @@ int test_main(int, char* []) test_geometry_equals ( linestring, - "010200000003000000000000000000F03F00000000000000400000000000000040000000000000084000000000000010400000000000001440" + "010200000003000000000000000000f03f00000000000000400000000000000040000000000000084000000000000010400000000000001440" ); } @@ -115,7 +124,7 @@ int test_main(int, char* []) test_geometry_equals ( linestring, - "01EA03000003000000000000000000F03F00000000000000400000000000000840000000000000004000000000000008400000000000001040000000000000104000000000000014400000000000001840" + "01ea03000003000000000000000000f03f00000000000000400000000000000840000000000000004000000000000008400000000000001040000000000000104000000000000014400000000000001840" ); } @@ -157,7 +166,7 @@ int test_main(int, char* []) test_geometry_equals ( polygon, - "01EB0300000100000005000000000000000000494000000000000049400000000000001440000000000000494000000000000059400000000000002440000000000000594000000000000059400000000000001440000000000000594000000000000049400000000000002440000000000000494000000000000049400000000000001440" + "01eb0300000100000005000000000000000000494000000000000049400000000000001440000000000000494000000000000059400000000000002440000000000000594000000000000059400000000000001440000000000000594000000000000049400000000000002440000000000000494000000000000049400000000000001440" ); } @@ -187,9 +196,161 @@ int test_main(int, char* []) test_geometry_equals ( polygon, - "0103000000020000000500000000000000008041400000000000002440000000000080464000000000008046400000000000002E40000000000000444000000000000024400000000000003440000000000080414000000000000024400400000000000000000034400000000000003E40000000000080414000000000008041400000000000003E40000000000000344000000000000034400000000000003E40" + "0103000000020000000500000000000000008041400000000000002440000000000080464000000000008046400000000000002e40000000000000444000000000000024400000000000003440000000000080414000000000000024400400000000000000000034400000000000003e40000000000080414000000000008041400000000000003e40000000000000344000000000000034400000000000003e40" ); } + // + // Multi Geometries + // + + typedef bg::model::multi_point multipoint_type; + typedef bg::model::multi_linestring multilinestring_type; + typedef bg::model::multi_polygon multipolygon_type; + + // + // MultiPoint + // + + { + multipoint_type multipoint; + + bg::append(multipoint, + boost::assign::list_of + (point_type(1.234, 5.678)) + ); + + test_geometry_equals + ( + multipoint, + "01040000000100000001010000005839b4c876bef33f83c0caa145b61640" + ); + } + + { + multipoint_type multipoint; + + bg::append(multipoint, + boost::assign::list_of + (point_type(1.234, 5.678)) + (point_type(10.1112, 13.1415)) + ); + + test_geometry_equals + ( + multipoint, + "01040000000200000001010000005839b4c876bef33f83c0caa145b61640010100000062a1d634ef3824409cc420b072482a40" + ); + } + + // + // MultiLineString + // + + { + multilinestring_type multilinestring; + + // Create linestrings (append does not do this automatically) + multilinestring.resize(1); + + bg::append(multilinestring[0], + boost::assign::list_of + (point_type(1.234, 5.678)) + (point_type(9.1011, 10.1112)) + (point_type(13.1415, 16.1718)) + ); + + test_geometry_equals + ( + multilinestring, + "0105000000010000000102000000030000005839b4c876bef33f83c0caa145b616404f401361c333224062a1d634ef3824409cc420b072482a40eb73b515fb2b3040" + ); + } + + { + multilinestring_type multilinestring; + + // Create linestrings (append does not do this automatically) + multilinestring.resize(2); + + bg::append(multilinestring[0], + boost::assign::list_of + (point_type(1.234, 5.678)) + (point_type(9.1011, 10.1112)) + (point_type(13.1415, 16.1718)) + ); + + bg::append(multilinestring[1], + boost::assign::list_of + (point_type(19.2, 21.22)) + (point_type(23.24, 25.26)) + ); + + test_geometry_equals + ( + multilinestring, +"0105000000020000000102000000030000005839b4c876bef33f83c0caa145b616404f401361c333224062a1d634ef3824409cc420b072482a40eb73b515fb2b30400102000000020000003333333333333340b81e85eb513835403d0ad7a3703d3740c3f5285c8f423940" + ); + } + + // + // MultiPolygon + // + + { + multipolygon_type multipolygon; + + // Create polygons (append does not do this automatically) + multipolygon.resize(1); + + bg::append(multipolygon[0], + boost::assign::list_of + (point_type(100, 200)) + (point_type(200, 200)) + (point_type(200, 400)) + (point_type(100, 400)) + (point_type(100, 200)) + ); + + test_geometry_equals + ( + multipolygon, +"010600000001000000010300000001000000050000000000000000005940000000000000694000000000000069400000000000006940000000000000694000000000000079400000000000005940000000000000794000000000000059400000000000006940" + ); + } + + { + multipolygon_type multipolygon; + + // Create polygons (append does not do this automatically) + multipolygon.resize(1); + // Create an interior ring (append does not do this automatically) + multipolygon[0].inners().resize(1); + + bg::append(multipolygon[0], + boost::assign::list_of + (point_type(35, 10)) + (point_type(10, 20)) + (point_type(15, 40)) + (point_type(45, 45)) + (point_type(35, 10)) + ); + + bg::append(multipolygon[0], + boost::assign::list_of + (point_type(20, 30)) + (point_type(35, 35)) + (point_type(30, 20)) + (point_type(20, 30)), + 0 + ); + + test_geometry_equals + ( + multipolygon, +"0106000000010000000103000000020000000500000000000000008041400000000000002440000000000000244000000000000034400000000000002e40000000000000444000000000008046400000000000804640000000000080414000000000000024400400000000000000000034400000000000003e40000000000080414000000000008041400000000000003e40000000000000344000000000000034400000000000003e40" + ); + } + return 0; } diff --git a/include/boost/geometry/extensions/multi/gis/io/wkb/detail/writer.hpp b/include/boost/geometry/extensions/multi/gis/io/wkb/detail/writer.hpp new file mode 100644 index 000000000..5b826ce1a --- /dev/null +++ b/include/boost/geometry/extensions/multi/gis/io/wkb/detail/writer.hpp @@ -0,0 +1,145 @@ +// Boost.Geometry +// +// Copyright (c) 2015 Mats Taraldsvik. +// +// 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_MULTI_IO_WKB_DETAIL_WRITER_HPP +#define BOOST_GEOMETRY_MULTI_IO_WKB_DETAIL_WRITER_HPP + +#include +#include +#include +#include + +#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 wkb +{ + template + struct multipoint_writer + { + template + static bool write(MultiPoint const& multipoint, + OutputIterator& iter, + byte_order_type::enum_t byte_order) + { + // write endian type + value_writer::write(byte_order, iter, byte_order); + + // write geometry type + uint32_t type = geometry_type::get(); + value_writer::write(type, iter, byte_order); + + // write num points + uint32_t num_points = boost::size(multipoint); + value_writer::write(num_points, iter, byte_order); + + typedef typename point_type::type point_type; + + for(typename boost::range_iterator::type + point_iter = boost::begin(multipoint); + point_iter != boost::end(multipoint); + ++point_iter) + { + detail::wkb::point_writer::write(*point_iter, iter, byte_order); + } + + return true; + } + }; + + template + struct multilinestring_writer + { + template + static bool write(MultiLinestring const& multilinestring, + OutputIterator& iter, + byte_order_type::enum_t byte_order) + { + // write endian type + value_writer::write(byte_order, iter, byte_order); + + // write geometry type + uint32_t type = geometry_type::get(); + value_writer::write(type, iter, byte_order); + + // write num linestrings + uint32_t num_linestrings = boost::size(multilinestring); + value_writer::write(num_linestrings, iter, byte_order); + + typedef typename boost::range_value::type linestring_type; + + for(typename boost::range_iterator::type + linestring_iter = boost::begin(multilinestring); + linestring_iter != boost::end(multilinestring); + ++linestring_iter) + { + detail::wkb::linestring_writer::write(*linestring_iter, iter, byte_order); + } + + return true; + } + }; + + template + struct multipolygon_writer + { + template + static bool write(MultiPolygon const& multipolygon, + OutputIterator& iter, + byte_order_type::enum_t byte_order) + { + // write endian type + value_writer::write(byte_order, iter, byte_order); + + // write geometry type + uint32_t type = geometry_type::get(); + value_writer::write(type, iter, byte_order); + + // write num polygons + uint32_t num_polygons = boost::size(multipolygon); + value_writer::write(num_polygons, iter, byte_order); + + typedef typename boost::range_value::type polygon_type; + + for(typename boost::range_iterator::type + polygon_iter = boost::begin(multipolygon); + polygon_iter != boost::end(multipolygon); + ++polygon_iter) + { + detail::wkb::polygon_writer::write(*polygon_iter, iter, byte_order); + } + + return true; + } + }; + +}} // namespace detail::wkb +#endif // DOXYGEN_NO_IMPL + +}} // namespace boost::geometry +#endif // BOOST_GEOMETRY_MULTI_IO_WKB_DETAIL_WRITER_HPP diff --git a/include/boost/geometry/extensions/multi/gis/io/wkb/write_wkb.hpp b/include/boost/geometry/extensions/multi/gis/io/wkb/write_wkb.hpp new file mode 100644 index 000000000..1deed3ed3 --- /dev/null +++ b/include/boost/geometry/extensions/multi/gis/io/wkb/write_wkb.hpp @@ -0,0 +1,66 @@ +// Boost.Geometry +// +// Copyright (c) 2015 Mats Taraldsvik. +// +// 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_MULTI_IO_WKB_WRITE_WKB_HPP +#define BOOST_GEOMETRY_MULTI_IO_WKB_WRITE_WKB_HPP + +#include + +#include +#include + +#include + +#include +#include + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template +struct write_wkb +{ + template + static inline bool write(const Geometry& geometry, OutputIterator iter, + detail::wkb::byte_order_type::enum_t byte_order) + { + return detail::wkb::multipoint_writer::write(geometry, iter, byte_order); + } +}; + +template +struct write_wkb +{ + template + static inline bool write(const Geometry& geometry, OutputIterator iter, + detail::wkb::byte_order_type::enum_t byte_order) + { + return detail::wkb::multilinestring_writer::write(geometry, iter, byte_order); + } +}; + +template +struct write_wkb +{ + template + static inline bool write(const Geometry& geometry, OutputIterator iter, + detail::wkb::byte_order_type::enum_t byte_order) + { + return detail::wkb::multipolygon_writer::write(geometry, iter, byte_order); + } +}; + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + +}} // namespace boost::geometry +#endif // BOOST_GEOMETRY_MULTI_IO_WKB_WRITE_WKB_HPP From c9d6796b65c244aa962ab602dd01c400718e1fb8 Mon Sep 17 00:00:00 2001 From: Vissarion Fysikopoulos Date: Tue, 6 Sep 2016 17:58:30 +0300 Subject: [PATCH 24/89] [area] [formulas] More accurate spherical term computation; only one azimuth computation call --- .../boost/geometry/formulas/area_formulas.hpp | 91 ++++++++---- .../strategies/geographic/area_geographic.hpp | 15 +- .../strategies/spherical/area_spherical.hpp | 2 +- test/algorithms/area/area_geo.cpp | 139 +++++++++--------- test/algorithms/area/area_multi.cpp | 2 +- test/algorithms/area/area_sph_geo.cpp | 24 +-- 6 files changed, 157 insertions(+), 116 deletions(-) diff --git a/include/boost/geometry/formulas/area_formulas.hpp b/include/boost/geometry/formulas/area_formulas.hpp index a202e5fd8..d29cce04b 100644 --- a/include/boost/geometry/formulas/area_formulas.hpp +++ b/include/boost/geometry/formulas/area_formulas.hpp @@ -341,8 +341,8 @@ public: bool LongSegment, typename PointOfSegment > - static inline CT spherical_excess(PointOfSegment const& p1, - PointOfSegment const& p2) + static inline CT spherical(PointOfSegment const& p1, + PointOfSegment const& p2) { CT excess; @@ -381,12 +381,22 @@ public: * atan(((tan_lat1 + tan_lat2) / (CT(1) + tan_lat1 * tan_lat2)) * tan((geometry::get_as_radian<0>(p2) - geometry::get_as_radian<0>(p1)) / 2)); - } return excess; } + struct return_type_ellipsoidal + { + return_type_ellipsoidal() + : spherical_term(0), + ellipsoidal_term(0) + {} + + CT spherical_term; + CT ellipsoidal_term; + }; + /* Compute the ellipsoidal correction of a geodesic (or shperical) segment */ @@ -396,11 +406,13 @@ public: typename PointOfSegment, typename SpheroidConst > - static inline CT ellipsoidal_correction(PointOfSegment const& p1, - PointOfSegment const& p2, - SpheroidConst spheroid_const) + static inline return_type_ellipsoidal ellipsoidal(PointOfSegment const& p1, + PointOfSegment const& p2, + SpheroidConst spheroid_const) { + return_type_ellipsoidal result; + // Azimuth Approximation typedef Inverse inverse_type; typedef typename inverse_type::result_type inverse_result; @@ -414,23 +426,7 @@ public: CT alp1 = i_res.azimuth; CT alp2 = i_res.reverse_azimuth; - // Azimuth Approximation -/* - CT alp1, alp2; - - alp1 = AzimuthStrategy::apply(get_as_radian<0>(p1), - get_as_radian<1>(p1), - get_as_radian<0>(p2), - get_as_radian<1>(p2), - spheroid_const.m_spheroid).azimuth; - - alp2 = AzimuthStrategy::apply(get_as_radian<0>(p1), - get_as_radian<1>(p1), - get_as_radian<0>(p2), - get_as_radian<1>(p2), - spheroid_const.m_spheroid).reverse_azimuth; -*/ - // Integral approximation + // Constants CT const ep = spheroid_const.m_ep; CT const f = geometry::detail::flattening(spheroid_const.m_spheroid); @@ -438,6 +434,8 @@ public: std::size_t const series_order_plus_one = SeriesOrder + 1; std::size_t const series_order_plus_two = SeriesOrder + 2; + // Basic trigonometric computations + CT tan_bet1 = tan(get_as_radian<1>(p1)) * one_minus_f; CT tan_bet2 = tan(get_as_radian<1>(p2)) * one_minus_f; CT cos_bet1 = cos(atan(tan_bet1)); @@ -448,8 +446,48 @@ public: CT cos_alp1 = cos(alp1); CT cos_alp2 = cos(alp2); CT sin_alp0 = sin_alp1 * cos_bet1; + + // Spherical term computation + + CT sin_omg1 = sin_alp0 * sin_bet1; + CT cos_omg1 = cos_alp1 * cos_bet1; + CT sin_omg2 = sin_alp0 * sin_bet2; + CT cos_omg2 = cos_alp2 * cos_bet2; + CT sin_omg12 = cos_omg1 * sin_omg2 - sin_omg1 * cos_omg2; + CT cos_omg12 = cos_omg1 * cos_omg2 + sin_omg1 * sin_omg2; + CT excess; + + bool meridian = get<0>(p2) - get<0>(p1) == CT(0) + || get<1>(p1) == CT(90) || get<1>(p1) == -CT(90) + || get<1>(p2) == CT(90) || get<1>(p2) == -CT(90); + + if (!meridian && cos_omg12 > -CT(0.7) + && sin_bet2 - sin_bet1 < CT(1.75)) // short segment + { + normalize(sin_omg12, cos_omg12); + + CT cos_omg12p1 = CT(1) + cos_omg12; + CT cos_bet1p1 = CT(1) + cos_bet1; + CT cos_bet2p1 = CT(1) + cos_bet2; + excess = CT(2) * atan2(sin_omg12 * (sin_bet1 * cos_bet2p1 + sin_bet2 * cos_bet1p1), + cos_omg12p1 * (sin_bet1 * sin_bet2 + cos_bet1p1 * cos_bet2p1)); + } + else + { + /* + CT sin_alp2 = sin(alp2); + CT sin_alp12 = sin_alp2 * cos_alp1 - cos_alp2 * sin_alp1; + CT cos_alp12 = cos_alp2 * cos_alp1 + sin_alp2 * sin_alp1; + excess = atan2(sin_alp12, cos_alp12); + */ + excess = alp2 - alp1; + } + + result.spherical_term = excess; + + // Ellipsoidal term computation (uses integral approximation) + CT cos_alp0 = math::sqrt(CT(1) - math::sqr(sin_alp0)); - //CT cos_alp0 = hypot(cos_alp2, sin(alp2) * sin_bet2); CT cos_sig1 = cos_alp1 * cos_bet1; CT cos_sig2 = cos_alp2 * cos_bet2; CT sin_sig1 = sin_bet1; @@ -495,10 +533,11 @@ public: CT I12 = clenshaw_sum(cos_sig2, coeffs, coeffs + series_order_plus_one) - clenshaw_sum(cos_sig1, coeffs, coeffs + series_order_plus_one); - // Return the part of the ellipsodal correction that depends on + // The part of the ellipsodal correction that depends on // point coordinates - return cos_alp0 * sin_alp0 * I12; + result.ellipsoidal_term = cos_alp0 * sin_alp0 * I12; + return result; } // Keep track whenever a segment crosses the prime meridian diff --git a/include/boost/geometry/strategies/geographic/area_geographic.hpp b/include/boost/geometry/strategies/geographic/area_geographic.hpp index 4f210dfb8..8e594cd90 100644 --- a/include/boost/geometry/strategies/geographic/area_geographic.hpp +++ b/include/boost/geometry/strategies/geographic/area_geographic.hpp @@ -162,14 +162,15 @@ public : if (! geometry::math::equals(get<0>(p1), get<0>(p2))) { - //Compute the trapezoidal area - state.m_excess_sum += geometry::formula::area_formulas - ::template spherical_excess(p1, p2); + typedef geometry::formula::area_formulas area_formulas; - state.m_correction_sum += geometry::formula::area_formulas - - ::template ellipsoidal_correction - (p1, p2, spheroid_const); + typename area_formulas::return_type_ellipsoidal result = + area_formulas::template ellipsoidal + (p1, p2, spheroid_const); + + state.m_excess_sum += result.spherical_term; + state.m_correction_sum += result.ellipsoidal_term; // Keep track whenever a segment crosses the prime meridian geometry::formula::area_formulas diff --git a/include/boost/geometry/strategies/spherical/area_spherical.hpp b/include/boost/geometry/strategies/spherical/area_spherical.hpp index b71348d11..478aa5e03 100644 --- a/include/boost/geometry/strategies/spherical/area_spherical.hpp +++ b/include/boost/geometry/strategies/spherical/area_spherical.hpp @@ -112,7 +112,7 @@ public : { state.m_sum += geometry::formula::area_formulas - ::template spherical_excess(p1, p2); + ::template spherical(p1, p2); // Keep track whenever a segment crosses the prime meridian geometry::formula::area_formulas diff --git a/test/algorithms/area/area_geo.cpp b/test/algorithms/area/area_geo.cpp index f9134a87f..20fe2c2e7 100644 --- a/test/algorithms/area/area_geo.cpp +++ b/test/algorithms/area/area_geo.cpp @@ -164,114 +164,115 @@ void test_geo_strategies() CT err = 0.0000001; CT area_default = bg::area(geometry_geo); - BOOST_CHECK_CLOSE(area_default, 63292982057581.711, err); + BOOST_CHECK_CLOSE(area_default, 63316536092341.266, err); area = bg::area(geometry_geo, geographic_default); - BOOST_CHECK_CLOSE(area, 63292982057581.711, err); + BOOST_CHECK_CLOSE(area, 63316536092341.266, err); CT area_less_accurate = bg::area(geometry_geo, geographic_andoyer1); - BOOST_CHECK_CLOSE(area_less_accurate, 63292982421447.312, err); + BOOST_CHECK_CLOSE(area_less_accurate, 63316309346280.18, err); area = bg::area(geometry_geo, geographic_andoyer2); - BOOST_CHECK_CLOSE(area, 63292982299473.633, err); + BOOST_CHECK_CLOSE(area, 63316309224306.5, err); area = bg::area(geometry_geo, geographic_andoyer3); - BOOST_CHECK_CLOSE(area, 63292982299578.328, err); + BOOST_CHECK_CLOSE(area, 63316309224411.195, err); area = bg::area(geometry_geo, geographic_andoyer4); - BOOST_CHECK_CLOSE(area, 63292982299578.227, err); + BOOST_CHECK_CLOSE(area, 63316309224411.094, err); area = bg::area(geometry_geo, geographic_andoyer5); - BOOST_CHECK_CLOSE(area, 63292982299578.227, err); + BOOST_CHECK_CLOSE(area, 63316309224411.094, err); area = bg::area(geometry_geo, geographic_thomas1); - BOOST_CHECK_CLOSE(area, 63292982179555.766, err); + BOOST_CHECK_CLOSE(area, 63316536214315.32, err); area = bg::area(geometry_geo, geographic_thomas2); - BOOST_CHECK_CLOSE(area, 63292982057581.711, err); + BOOST_CHECK_CLOSE(area, 63316536092341.266, err); area = bg::area(geometry_geo, geographic_thomas3); - BOOST_CHECK_CLOSE(area, 63292982057686.406, err); + BOOST_CHECK_CLOSE(area, 63316536092445.961, err); area = bg::area(geometry_geo, geographic_thomas4); - BOOST_CHECK_CLOSE(area, 63292982057686.305, err); + BOOST_CHECK_CLOSE(area, 63316536092445.859, err); area = bg::area(geometry_geo, geographic_thomas5); - BOOST_CHECK_CLOSE(area, 63292982057686.305, err); + BOOST_CHECK_CLOSE(area, 63316536092445.859, err); area = bg::area(geometry_geo, geographic_vincenty1); - BOOST_CHECK_CLOSE(area, 63292982178432.859, err); + BOOST_CHECK_CLOSE(area, 63316536473798.984, err); area = bg::area(geometry_geo, geographic_vincenty2); - BOOST_CHECK_CLOSE(area, 63292982056458.805, err); + BOOST_CHECK_CLOSE(area, 63316536351824.93, err); area = bg::area(geometry_geo, geographic_vincenty3); - BOOST_CHECK_CLOSE(area, 63292982056563.5, err); + BOOST_CHECK_CLOSE(area, 63316536351929.625, err); area = bg::area(geometry_geo, geographic_vincenty4); - BOOST_CHECK_CLOSE(area, 63292982056563.398, err); + BOOST_CHECK_CLOSE(area, 63316536351929.523, err); CT area_most_accurate = bg::area(geometry_geo, geographic_vincenty5); - BOOST_CHECK_CLOSE(area, 63292982056563.398, err); + BOOST_CHECK_CLOSE(area, 63316536351929.523, err); area = bg::area(geometry_geo, geographic_vincenty5_default); - BOOST_CHECK_CLOSE(area, 63292982056563.398, err); + BOOST_CHECK_CLOSE(area, 63316536351929.523, err); area = bg::area(geometry_geo, geographic_vincenty_default); - BOOST_CHECK_CLOSE(area, 63292982056458.805, err); + BOOST_CHECK_CLOSE(area, 63316536351824.93, err); - BOOST_CHECK_CLOSE(area_most_accurate, area_less_accurate, .000001); - BOOST_CHECK_CLOSE(area_most_accurate, area_default, .00000001); + BOOST_CHECK_CLOSE(area_most_accurate, area_less_accurate, .001); + BOOST_CHECK_CLOSE(area_most_accurate, area_default, .000001); - /* timings and accuracy - std::cout.precision(32); + /* timings and accuracy */ + std::cout.precision(25); + std::size_t exp_times = 100000; { clock_t startTime = clock(); - for (int j=0; j < 100000; j++) area = bg::area(geometry_geo, geographic_andoyer1); - std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds." << std::endl; - std::cout << "area=" << area << std::endl;} + for (int j=0; j < exp_times; j++) area = bg::area(geometry_geo, geographic_andoyer1); + std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " "; + std::cout << area << std::endl;} { clock_t startTime = clock(); - for (int j=0; j < 100000; j++) area = bg::area(geometry_geo, geographic_andoyer2); - std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds." << std::endl; - std::cout << "area=" << area << std::endl;} + for (int j=0; j < exp_times; j++) area = bg::area(geometry_geo, geographic_andoyer2); + std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " "; + std::cout << area << std::endl;} { clock_t startTime = clock(); - for (int j=0; j < 100000; j++) area = bg::area(geometry_geo, geographic_andoyer3); - std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds." << std::endl; - std::cout << "area=" << area << std::endl;} + for (int j=0; j < exp_times; j++) area = bg::area(geometry_geo, geographic_andoyer3); + std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " "; + std::cout << area << std::endl;} { clock_t startTime = clock(); - for (int j=0; j < 100000; j++) area = bg::area(geometry_geo, geographic_andoyer4); - std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds." << std::endl; - std::cout << "area=" << area << std::endl;} + for (int j=0; j < exp_times; j++) area = bg::area(geometry_geo, geographic_andoyer4); + std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " "; + std::cout << area << std::endl;} { clock_t startTime = clock(); - for (int j=0; j < 100000; j++) area = bg::area(geometry_geo, geographic_andoyer5); - std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds." << std::endl; - std::cout << "area=" << area << std::endl;} + for (int j=0; j < exp_times; j++) area = bg::area(geometry_geo, geographic_andoyer5); + std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " "; + std::cout << area << std::endl;} { clock_t startTime = clock(); - for (int j=0; j < 100000; j++) area = bg::area(geometry_geo, geographic_thomas1); - std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds." << std::endl; - std::cout << "area=" << area << std::endl;} + for (int j=0; j < exp_times; j++) area = bg::area(geometry_geo, geographic_thomas1); + std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " "; + std::cout << area << std::endl;} { clock_t startTime = clock(); - for (int j=0; j < 100000; j++) area = bg::area(geometry_geo, geographic_thomas2); - std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds." << std::endl; - std::cout << "area=" << area << std::endl;} + for (int j=0; j < exp_times; j++) area = bg::area(geometry_geo, geographic_thomas2); + std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " "; + std::cout << area << std::endl;} { clock_t startTime = clock(); - for (int j=0; j < 100000; j++) area = bg::area(geometry_geo, geographic_thomas3); - std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds." << std::endl; - std::cout << "area=" << area << std::endl;} + for (int j=0; j < exp_times; j++) area = bg::area(geometry_geo, geographic_thomas3); + std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " "; + std::cout << area << std::endl;} { clock_t startTime = clock(); - for (int j=0; j < 100000; j++) area = bg::area(geometry_geo, geographic_thomas4); - std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds." << std::endl; - std::cout << "area=" << area << std::endl;} + for (int j=0; j < exp_times; j++) area = bg::area(geometry_geo, geographic_thomas4); + std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " "; + std::cout << area << std::endl;} { clock_t startTime = clock(); - for (int j=0; j < 100000; j++) area = bg::area(geometry_geo, geographic_thomas5); - std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds." << std::endl; - std::cout << "area=" << area << std::endl;} + for (int j=0; j < exp_times; j++) area = bg::area(geometry_geo, geographic_thomas5); + std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " "; + std::cout << area << std::endl;} { clock_t startTime = clock(); - for (int j=0; j < 100000; j++) area = bg::area(geometry_geo, geographic_vincenty1); - std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds." << std::endl; - std::cout << "area=" << area << std::endl;} + for (int j=0; j < exp_times; j++) area = bg::area(geometry_geo, geographic_vincenty1); + std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " "; + std::cout << area << std::endl;} { clock_t startTime = clock(); - for (int j=0; j < 100000; j++) area = bg::area(geometry_geo, geographic_vincenty2); - std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds." << std::endl; - std::cout << "area=" << area << std::endl;} + for (int j=0; j < exp_times; j++) area = bg::area(geometry_geo, geographic_vincenty2); + std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " "; + std::cout << area << std::endl;} { clock_t startTime = clock(); - for (int j=0; j < 100000; j++) area = bg::area(geometry_geo, geographic_vincenty3); - std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds." << std::endl; - std::cout << "area=" << area << std::endl;} + for (int j=0; j < exp_times; j++) area = bg::area(geometry_geo, geographic_vincenty3); + std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " "; + std::cout << area << std::endl;} { clock_t startTime = clock(); - for (int j=0; j < 100000; j++) area = bg::area(geometry_geo, geographic_vincenty4); - std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds." << std::endl; - std::cout << "area=" << area << std::endl;} + for (int j=0; j < exp_times; j++) area = bg::area(geometry_geo, geographic_vincenty4); + std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " "; + std::cout << area << std::endl;} { clock_t startTime = clock(); - for (int j=0; j < 100000; j++) area = bg::area(geometry_geo, geographic_vincenty5); - std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds." << std::endl; - std::cout << "area=" << area << std::endl;} - */ + for (int j=0; j < exp_times; j++) area = bg::area(geometry_geo, geographic_vincenty5); + std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " "; + std::cout << area << std::endl;} + } int test_main(int, char* []) diff --git a/test/algorithms/area/area_multi.cpp b/test/algorithms/area/area_multi.cpp index 89f0fbd4f..b351a9c01 100644 --- a/test/algorithms/area/area_multi.cpp +++ b/test/algorithms/area/area_multi.cpp @@ -37,7 +37,7 @@ void test_all() std::string poly = "MULTIPOLYGON(((0 0,0 7,4 2,2 0,0 0)))"; test_geometry(poly, 16.0); test_geometry(poly, 197897454752.69489); - test_geometry(poly, 197020675141.16785); + test_geometry(poly, 197022175077.78613); } int test_main( int , char* [] ) diff --git a/test/algorithms/area/area_sph_geo.cpp b/test/algorithms/area/area_sph_geo.cpp index 06f8aedeb..fb6082eff 100644 --- a/test/algorithms/area/area_sph_geo.cpp +++ b/test/algorithms/area/area_sph_geo.cpp @@ -89,7 +89,7 @@ void test_spherical_geo() bg::read_wkt(poly, geometry_geo); area = bg::area(geometry_geo, area_geographic); //GeoGraphicLib gives: 63758202715511.055 - BOOST_CHECK_CLOSE(area, 63758202715509.859, 0.0001); + BOOST_CHECK_CLOSE(area, 63758202715509.844, 0.0001); // Wrangel Island (dateline crossing) @@ -109,7 +109,7 @@ void test_spherical_geo() bg::read_wkt(poly, geometry_geo); area = bg::area(geometry_geo, area_geographic); - BOOST_CHECK_CLOSE(area, 4537974350.6843719, 0.0001); + BOOST_CHECK_CLOSE(area, 4537929936.5349159, 0.0001); // Wrangel, more in detail poly = "POLYGON((-178.568604 71.564148,-178.017548 71.449692,-177.833313 71.3461,\ @@ -149,7 +149,7 @@ void test_spherical_geo() BOOST_CHECK_CLOSE(area, 14136.09946, 0.001); // SQL Server gives: 14064.1902284513 bg::read_wkt(poly, geometry_geo); area = bg::area(geometry_geo, area_geographic); - BOOST_CHECK_CLOSE(area, 14064196647.560314, 0.0001); + BOOST_CHECK_CLOSE(area, 14064129044.674297, 0.0001); poly = "POLYGON((-178.7858 10.7852, 177.4758 11.2333, 179.7436 11.5733, -178.7858 10.7852))"; bg::read_wkt(poly, geometry); @@ -157,7 +157,7 @@ void test_spherical_geo() BOOST_CHECK_CLOSE(area, 13760.2456, 0.001); // SQL Server gives: 13697.0941155193 bg::read_wkt(poly, geometry_geo); area = bg::area(geometry_geo, area_geographic); - BOOST_CHECK_CLOSE(area, 13697095227.008451, 0.0001); + BOOST_CHECK_CLOSE(area, 13696308940.315653, 0.0001); poly = "POLYGON((-178.7858 20.7852, 177.4758 21.2333, 179.7436 21.5733, -178.7858 20.7852))"; bg::read_wkt(poly, geometry); @@ -165,7 +165,7 @@ void test_spherical_geo() BOOST_CHECK_CLOSE(area, 12987.8682, 0.001); // SQL Server gives: 12944.3970990317 -> -39m^2 bg::read_wkt(poly, geometry_geo); area = bg::area(geometry_geo, area_geographic); - BOOST_CHECK_CLOSE(area, 12944392155.546635, 0.0001); + BOOST_CHECK_CLOSE(area, 12943176284.560806, 0.0001); poly = "POLYGON((-178.7858 30.7852, 177.4758 31.2333, 179.7436 31.5733, -178.7858 30.7852))"; bg::read_wkt(poly, geometry); @@ -173,7 +173,7 @@ void test_spherical_geo() BOOST_CHECK_CLOSE(area, 11856.3935, 0.001); // SQL Server gives: 11838.5338423574 -> -18m^2 bg::read_wkt(poly, geometry_geo); area = bg::area(geometry_geo, area_geographic); - BOOST_CHECK_CLOSE(area, 11838524075.970982, 0.0001); + BOOST_CHECK_CLOSE(area, 11837280445.349375, 0.0001); poly = "POLYGON((-178.7858 40.7852, 177.4758 41.2333, 179.7436 41.5733, -178.7858 40.7852))"; bg::read_wkt(poly, geometry); @@ -182,7 +182,7 @@ void test_spherical_geo() // SQL Server gives: 10412.0607137119, -> +8m^2 bg::read_wkt(poly, geometry_geo); area = bg::area(geometry_geo, area_geographic); - BOOST_CHECK_CLOSE(area, 10412049661.81769, 0.0001); + BOOST_CHECK_CLOSE(area, 10411098789.39222, 0.0001); // Concave poly = "POLYGON((0 40,1 42,0 44,2 43,4 44,3 42,4 40,2 41,0 40))"; @@ -200,7 +200,7 @@ void test_spherical_geo() BOOST_CHECK_CLOSE(area, 133233.844876, 0.001); // SQL Server gives: 133353.335 bg::read_wkt(poly, geometry_geo); area = bg::area(geometry_geo, area_geographic); - BOOST_CHECK_CLOSE(area, 133353331647.58241, 0.0001); + BOOST_CHECK_CLOSE(area, 133353077343.10347, 0.0001); // around 0 meridian { @@ -225,7 +225,7 @@ void test_spherical_geo() area3 = bg::area(geometry_geo, area_geographic); BOOST_CHECK_CLOSE(area1, area2, 0.001); BOOST_CHECK_CLOSE(area2, area3, 0.001); - BOOST_CHECK_CLOSE(area1, 1227857282668.3145, 0.001); + BOOST_CHECK_CLOSE(area1, 1227877191611.2805, 0.001); } { std::string poly1 = "POLYGON((-10 -5,-10 5,0 5,0 -5,-10 -5))"; @@ -249,7 +249,7 @@ void test_spherical_geo() area3 = bg::area(geometry_geo, area_geographic); BOOST_CHECK_CLOSE(area1, area2, 0.001); BOOST_CHECK_CLOSE(area2, area3, 0.001); - BOOST_CHECK_CLOSE(area1, 1232493707152.2292, 0.001); + BOOST_CHECK_CLOSE(area1, 1232514639151.6477, 0.001); } // around 180 meridian { @@ -288,7 +288,7 @@ void test_spherical_geo() BOOST_CHECK_CLOSE(area2, area3, 0.001); BOOST_CHECK_CLOSE(area3, area4, 0.001); BOOST_CHECK_CLOSE(area4, area5, 0.001); - BOOST_CHECK_CLOSE(area1, 1227857282668.313, 0.001); + BOOST_CHECK_CLOSE(area1, 1227877191611.2805, 0.001); } { std::string poly1 = "POLYGON((-180 -5,-180 5,-170 5,-170 -5,-180 -5))"; @@ -326,7 +326,7 @@ void test_spherical_geo() BOOST_CHECK_CLOSE(area2, area3, 0.001); BOOST_CHECK_CLOSE(area3, area4, 0.001); BOOST_CHECK_CLOSE(area4, area5, 0.001); - BOOST_CHECK_CLOSE(area1, 1232493707152.2278, 0.001); + BOOST_CHECK_CLOSE(area1, 1232514639151.6477, 0.001); } // around poles { From 4c787629bafd4e9ad5e63d8c380565bb8a27ce75 Mon Sep 17 00:00:00 2001 From: Vissarion Fysikopoulos Date: Tue, 6 Sep 2016 18:31:17 +0300 Subject: [PATCH 25/89] [area] [formulas] Minor changes. --- include/boost/geometry/formulas/area_formulas.hpp | 2 +- test/algorithms/area/area_geo.cpp | 6 +++--- test/algorithms/area/area_sph_geo.cpp | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/boost/geometry/formulas/area_formulas.hpp b/include/boost/geometry/formulas/area_formulas.hpp index d29cce04b..4a3b24df7 100644 --- a/include/boost/geometry/formulas/area_formulas.hpp +++ b/include/boost/geometry/formulas/area_formulas.hpp @@ -453,7 +453,6 @@ public: CT cos_omg1 = cos_alp1 * cos_bet1; CT sin_omg2 = sin_alp0 * sin_bet2; CT cos_omg2 = cos_alp2 * cos_bet2; - CT sin_omg12 = cos_omg1 * sin_omg2 - sin_omg1 * cos_omg2; CT cos_omg12 = cos_omg1 * cos_omg2 + sin_omg1 * sin_omg2; CT excess; @@ -464,6 +463,7 @@ public: if (!meridian && cos_omg12 > -CT(0.7) && sin_bet2 - sin_bet1 < CT(1.75)) // short segment { + CT sin_omg12 = cos_omg1 * sin_omg2 - sin_omg1 * cos_omg2; normalize(sin_omg12, cos_omg12); CT cos_omg12p1 = CT(1) + cos_omg12; diff --git a/test/algorithms/area/area_geo.cpp b/test/algorithms/area/area_geo.cpp index 20fe2c2e7..46cb6eed5 100644 --- a/test/algorithms/area/area_geo.cpp +++ b/test/algorithms/area/area_geo.cpp @@ -208,8 +208,8 @@ void test_geo_strategies() BOOST_CHECK_CLOSE(area_most_accurate, area_less_accurate, .001); BOOST_CHECK_CLOSE(area_most_accurate, area_default, .000001); - - /* timings and accuracy */ +/* + // timings and accuracy std::cout.precision(25); std::size_t exp_times = 100000; { clock_t startTime = clock(); @@ -272,7 +272,7 @@ void test_geo_strategies() for (int j=0; j < exp_times; j++) area = bg::area(geometry_geo, geographic_vincenty5); std::cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " "; std::cout << area << std::endl;} - +*/ } int test_main(int, char* []) diff --git a/test/algorithms/area/area_sph_geo.cpp b/test/algorithms/area/area_sph_geo.cpp index fb6082eff..64c2022d4 100644 --- a/test/algorithms/area/area_sph_geo.cpp +++ b/test/algorithms/area/area_sph_geo.cpp @@ -83,9 +83,9 @@ void test_spherical_geo() ct const two = 2.0; BOOST_CHECK_CLOSE(area, two * two * expected, 0.0001); - // Geographic total area of earth is about 510072000 - // (https://en.wikipedia.org/wiki/Earth) - // So the 1/8 is 63759000 and here we get something close to it + // Geographic total area of earth is about 510065626583900.6 (WGS84 ellipsoid) + // (510072000 in https://en.wikipedia.org/wiki/Earth) + // So the 1/8 is 6.375820332×10^13 and here we get something close to it bg::read_wkt(poly, geometry_geo); area = bg::area(geometry_geo, area_geographic); //GeoGraphicLib gives: 63758202715511.055 From 81e073434cd71edd60a2506de9c84cbe9d4e6aa6 Mon Sep 17 00:00:00 2001 From: Vissarion Fysikopoulos Date: Tue, 13 Sep 2016 18:07:52 +0300 Subject: [PATCH 26/89] [envelope] Envelope of a segment with strategies --- .../detail/envelope/implementation.hpp | 4 +- .../algorithms/detail/envelope/interface.hpp | 44 ++++++- .../algorithms/detail/envelope/segment.hpp | 114 +++++++++++++----- .../algorithms/detail/expand/segment.hpp | 5 +- .../geometry/formulas/vertex_latitude.hpp | 85 +++---------- include/boost/geometry/strategies/azimuth.hpp | 36 ++++++ .../cartesian/azimuth_cartesian.hpp | 64 ++++++++++ .../geographic/azimuth_geographic.hpp | 70 +++++++++++ .../spherical/azimuth_spherical.hpp | 66 ++++++++++ .../boost/geometry/strategies/strategies.hpp | 4 + 10 files changed, 394 insertions(+), 98 deletions(-) create mode 100644 include/boost/geometry/strategies/azimuth.hpp create mode 100644 include/boost/geometry/strategies/cartesian/azimuth_cartesian.hpp create mode 100644 include/boost/geometry/strategies/geographic/azimuth_geographic.hpp create mode 100644 include/boost/geometry/strategies/spherical/azimuth_spherical.hpp diff --git a/include/boost/geometry/algorithms/detail/envelope/implementation.hpp b/include/boost/geometry/algorithms/detail/envelope/implementation.hpp index c1dbf8e58..6b3193e42 100644 --- a/include/boost/geometry/algorithms/detail/envelope/implementation.hpp +++ b/include/boost/geometry/algorithms/detail/envelope/implementation.hpp @@ -45,8 +45,8 @@ namespace detail { namespace envelope struct envelope_polygon { - template - static inline void apply(Polygon const& polygon, Box& mbr) + template + static inline void apply(Polygon const& polygon, Box& mbr, Strategy const& strategy) { typename ring_return_type::type ext_ring = exterior_ring(polygon); diff --git a/include/boost/geometry/algorithms/detail/envelope/interface.hpp b/include/boost/geometry/algorithms/detail/envelope/interface.hpp index befe4e42d..8f82119ad 100644 --- a/include/boost/geometry/algorithms/detail/envelope/interface.hpp +++ b/include/boost/geometry/algorithms/detail/envelope/interface.hpp @@ -37,6 +37,7 @@ namespace resolve_variant template struct envelope { +/* template static inline void apply(Geometry const& geometry, Box& box) { @@ -45,6 +46,15 @@ struct envelope dispatch::envelope::apply(geometry, box); } +*/ + template + static inline void apply(Geometry const& geometry, Box& box, Strategy const& strategy) + { + concepts::check(); + concepts::check(); + + dispatch::envelope::apply(geometry, box, strategy); + } }; template @@ -75,6 +85,26 @@ struct envelope > } // namespace resolve_variant +/*! +\brief \brief_calc{envelope (with strategy)} +\ingroup envelope +\details \details_calc{envelope,\det_envelope}. +\tparam Geometry \tparam_geometry +\tparam Box \tparam_box +\param geometry \param_geometry +\param mbr \param_box \param_set{envelope} + +\qbk{[include reference/algorithms/envelope.qbk]} +\qbk{ +[heading Example] +[envelope] [envelope_output] +} +*/ +template +inline void envelope(Geometry const& geometry, Box& mbr, Strategy& strategy) +{ + resolve_variant::envelope::apply(geometry, mbr, strategy); +} /*! \brief \brief_calc{envelope} @@ -94,7 +124,19 @@ struct envelope > template inline void envelope(Geometry const& geometry, Box& mbr) { - resolve_variant::envelope::apply(geometry, mbr); + // TODO put this into a resolve_strategy stage + // (and take the return type from resolve_variant) + typedef typename point_type::type point_type; + typedef typename coordinate_type::type coordinate_type; + //typedef typename strategy::azimuth::azimuth_geographic strategy_type; + + typedef typename strategy::azimuth::services::default_strategy + < + typename cs_tag::type, + coordinate_type + >::type strategy_type; + + resolve_variant::envelope::apply(geometry, mbr, strategy_type()); } diff --git a/include/boost/geometry/algorithms/detail/envelope/segment.hpp b/include/boost/geometry/algorithms/detail/envelope/segment.hpp index 6186e72a3..7a6a38c4f 100644 --- a/include/boost/geometry/algorithms/detail/envelope/segment.hpp +++ b/include/boost/geometry/algorithms/detail/envelope/segment.hpp @@ -7,6 +7,7 @@ // This file was modified by Oracle on 2015, 2016. // Modifications copyright (c) 2015-2016, Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -46,6 +47,10 @@ #include +#include +#include +#include +#include namespace boost { namespace geometry { @@ -58,8 +63,8 @@ namespace detail { namespace envelope template struct envelope_one_segment { - template - static inline void apply(Point const& p1, Point const& p2, Box& mbr) + template + static inline void apply(Point const& p1, Point const& p2, Box& mbr, Strategy const& strategy) { envelope_one_point::apply(p1, mbr); detail::expand::point_loop @@ -80,9 +85,11 @@ struct envelope_one_segment // normalized and in radians. // The longitudes and latitudes of the endpoints are overridden by // those of the box. +template class compute_mbr_of_segment { private: +/* // computes the azimuths of the segment with endpoints (lon1, lat1) // and (lon2, lat2) // radians @@ -111,7 +118,7 @@ private: cos_lat2 * sin_lat1 - sin_lat2 * cos_lat1 * cos_dlon); a2 += math::pi(); } - +*/ // degrees or radians template static inline void swap(CalculationType& lon1, @@ -150,7 +157,7 @@ private: return math::abs(lon1 - lon2) > constants::half_period(); // > pi } - +/* // radians template static inline CalculationType max_latitude(CalculationType const& azimuth, @@ -159,13 +166,14 @@ private: // azimuth and latitude are assumed to be in radians return acos( math::abs(cos(latitude) * sin(azimuth)) ); } - +*/ // degrees or radians - template + template static inline void compute_box_corners(CalculationType& lon1, CalculationType& lat1, CalculationType& lon2, - CalculationType& lat2) + CalculationType& lat2, + Strategy const& strategy) { // coordinates are assumed to be in radians BOOST_GEOMETRY_ASSERT(lon1 <= lon2); @@ -175,9 +183,22 @@ private: CalculationType lon2_rad = math::as_radian(lon2); CalculationType lat2_rad = math::as_radian(lat2); - CalculationType a1 = 0, a2 = 0; - azimuths(lon1_rad, lat1_rad, lon2_rad, lat2_rad, a1, a2); - + CalculationType a1, a2; + strategy.apply(lon1_rad, lat1_rad, lon2_rad, lat2_rad, a1, a2); +/* if (IsSpherical) + { + //geometry::strategy::azimuth::azimuth_spherical + // azimuth_spherical; + //azimuth_spherical.apply(lon1_rad, lat1_rad, lon2_rad, lat2_rad, a1, a2); + strategy.apply(lon1_rad, lat1_rad, lon2_rad, lat2_rad, a1, a2); + } + else + { + geometry::strategy::azimuth::azimuth_geographic + azimuth_geographic; + azimuth_geographic.apply(lon1_rad, lat1_rad, lon2_rad, lat2_rad, a1, a2); + } +*/ if (lat1 > lat2) { std::swap(lat1, lat2); @@ -192,11 +213,26 @@ private: if (contains_pi_half(a1, a2)) { + CalculationType p_max; + + if (IsSpherical) + { + p_max = geometry::formula::vertex_latitude:: + spherical(lat1_rad, a1); + } + else + { + p_max = geometry::formula::vertex_latitude:: + geographic(lat1_rad, a1, + geometry::srs::spheroid()); + } + CalculationType const mid_lat = lat1 + lat2; if (mid_lat < 0) { // update using min latitude - CalculationType const lat_min_rad = -max_latitude(a1, lat1_rad); + //CalculationType const lat_min_rad = -max_latitude(a1, lat1_rad); + CalculationType const lat_min_rad = -p_max; CalculationType const lat_min = math::from_radian(lat_min_rad); if (lat1 > lat_min) @@ -207,7 +243,8 @@ private: else if (mid_lat > 0) { // update using max latitude - CalculationType const lat_max_rad = max_latitude(a1, lat1_rad); + //CalculationType const lat_max_rad = max_latitude(a1, lat1_rad); + CalculationType const lat_max_rad = p_max; CalculationType const lat_max = math::from_radian(lat_max_rad); if (lat2 < lat_max) @@ -218,11 +255,12 @@ private: } } - template + template static inline void apply(CalculationType& lon1, CalculationType& lat1, CalculationType& lon2, - CalculationType& lat2) + CalculationType& lat2, + Strategy const& strategy) { typedef math::detail::constants_on_spheroid < @@ -278,16 +316,17 @@ private: swap(lon1, lat1, lon2, lat2); } - compute_box_corners(lon1, lat1, lon2, lat2); + compute_box_corners(lon1, lat1, lon2, lat2, strategy); } public: - template + template static inline void apply(CalculationType lon1, CalculationType lat1, CalculationType lon2, CalculationType lat2, - Box& mbr) + Box& mbr, + Strategy const& strategy) { typedef typename coordinate_type::type box_coordinate_type; @@ -298,7 +337,7 @@ public: helper_box_type radian_mbr; - apply(lon1, lat1, lon2, lat2); + apply(lon1, lat1, lon2, lat2, strategy); geometry::set < @@ -325,11 +364,11 @@ public: }; -template -struct envelope_segment_on_sphere +template +struct envelope_segment_on_sphere_or_spheroid { - template - static inline void apply(Point const& p1, Point const& p2, Box& mbr) + template + static inline void apply(Point const& p1, Point const& p2, Box& mbr, Strategy const& strategy) { // first compute the envelope range for the first two coordinates Point p1_normalized = detail::return_normalized(p1); @@ -337,16 +376,17 @@ struct envelope_segment_on_sphere typedef typename coordinate_system::type::units units_type; - compute_mbr_of_segment::template apply( + compute_mbr_of_segment::template apply( geometry::get<0>(p1_normalized), geometry::get<1>(p1_normalized), geometry::get<0>(p2_normalized), geometry::get<1>(p2_normalized), - mbr); + mbr, + strategy); // now compute the envelope range for coordinates of // dimension 2 and higher - envelope_one_segment<2, DimensionCount>::apply(p1, p2, mbr); + envelope_one_segment<2, DimensionCount>::apply(p1, p2, mbr, strategy); } template @@ -369,10 +409,15 @@ struct envelope_segment template struct envelope_segment - : envelope_segment_on_sphere + : envelope_segment_on_sphere_or_spheroid {}; +template +struct envelope_segment + : envelope_segment_on_sphere_or_spheroid +{}; + }} // namespace detail::envelope #endif // DOXYGEN_NO_DETAIL @@ -386,6 +431,7 @@ namespace dispatch template struct envelope { +/* template static inline void apply(Segment const& segment, Box& mbr) { @@ -397,8 +443,22 @@ struct envelope dimension::value, CS_Tag >::apply(p[0], p[1], mbr); } -}; +*/ + template + static inline void apply(Segment const& segment, + Box& mbr, + Strategy const& strategy) + { + 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_segment + < + dimension::value, CS_Tag + >::apply(p[0], p[1], mbr, strategy); + } +}; } // 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 041c1e175..7a1c79c4d 100644 --- a/include/boost/geometry/algorithms/detail/expand/segment.hpp +++ b/include/boost/geometry/algorithms/detail/expand/segment.hpp @@ -48,9 +48,10 @@ struct segment_on_sphere Box mbrs[2]; // compute the envelope of the segment - detail::envelope::envelope_segment_on_sphere + detail::envelope::envelope_segment_on_sphere_or_spheroid < - dimension::value + dimension::value, + true >::apply(segment, mbrs[0]); // normalize the box diff --git a/include/boost/geometry/formulas/vertex_latitude.hpp b/include/boost/geometry/formulas/vertex_latitude.hpp index 97b55985b..ab1b3f1dd 100644 --- a/include/boost/geometry/formulas/vertex_latitude.hpp +++ b/include/boost/geometry/formulas/vertex_latitude.hpp @@ -12,6 +12,7 @@ #define BOOST_GEOMETRY_FORMULAS_MAXIMUM_LATITUDE_HPP #include +#include namespace boost { namespace geometry { namespace formula { @@ -20,8 +21,8 @@ namespace boost { namespace geometry { namespace formula \brief Algorithm to compute the vertex latitude of a geodesic segment. Vertex is a point on the geodesic that maximizes (or minimizes) the latitude. \author See - Wood - Vertex Latitudes on Ellipsoid Geodesics, SIAM Rev., 38(4), 637–644, - 1996 + [Wood96] Wood - Vertex Latitudes on Ellipsoid Geodesics, SIAM Rev., 38(4), + 637–644, 1996 */ template @@ -30,88 +31,40 @@ class vertex_latitude public: - struct vertex_lat_result - { - vertex_lat_result() - : north(0), - south(0) - {} - - CT north, south; - }; - template < typename T1, typename T2 > - static inline vertex_lat_result spherical(T1 const& lon1, - T1 const& lat1, - T2 const& lon2, - T2 const& lat2) + static inline CT spherical(T1 const& lat1, + T2 const& alp1) { - vertex_lat_result vrt_result; - - geometry::formula::result_spherical result = geometry::formula:: - spherical_azimuth(lon1, lat1, lon2, lat2); - - CT const alp1 = std::abs(result.azimuth); - CT const alp2 = std::abs(result.reverse_azimuth); - - if(vertex_on_segment(alp1, alp2, lat1, lat2, vrt_result)) - { - CT const cos2_lat1 = math::sqr(cos(lat1)); - CT const sin2_alp1 = math::sqr(sin(alp1)); - CT const vertex_lat = std::asin(math::sqrt(1 - cos2_lat1 * sin2_alp1)); - - sign_adjastment(lat1, lat2, vertex_lat, vrt_result); - } - return vrt_result; + return std::acos( math::abs(cos(lat1) * sin(alp1)) ); } template < - template class Inverse, + //template class Inverse, typename T1, typename T2, typename Spheroid > - static inline vertex_lat_result geographic(T1 const& lon1, - T1 const& lat1, - T2 const& lon2, - T2 const& lat2, + static inline CT geographic(T1 const& lat1, + T2 const& alp1, Spheroid const& spheroid) { - vertex_lat_result vrt_result; - typedef Inverse inverse_type; - typedef typename inverse_type::result_type inverse_result; - inverse_result i_res = inverse_type::apply(lon1, lat1, lon2, lat2, spheroid); + CT const f = detail::flattening(spheroid); - CT const alp1 = std::abs(i_res.azimuth); - CT const alp2 = std::abs(i_res.reverse_azimuth); + CT const e2 = f * (CT(2) - f); + CT const sin_alp1 = sin(alp1); + CT const sin2_lat1 = math::sqr(sin(lat1)); + CT const cos2_lat1 = CT(1) - sin2_lat1; - if(vertex_on_segment(alp1, alp2, lat1, lat2, vrt_result)) - { - CT const a = get_radius<0>(spheroid); - CT const f = detail::flattening(spheroid); - CT const e2 = f * (CT(2) - f); - - CT const sin_alp1 = sin(alp1); - CT const sin2_lat1 = math::sqr(sin(lat1)); - CT const cos_lat1 = math::sqrt(CT(1) - sin2_lat1); - - // normal radius at point p1(lon1,lat1) - CT const n_b1 = a / (math::sqrt(CT(1) - e2 * sin2_lat1)); - - // the invariant of the geodesic - CT const c = n_b1 * cos_lat1 * sin_alp1; - - CT const a_c2 = math::sqr(a / c); - CT const vertex_lat = std::asin(math::sqrt((a_c2 - 1) / (a_c2 - e2))); - - sign_adjastment(lat1, lat2, vertex_lat, vrt_result); - } - return vrt_result; + CT const e2_sin2 = CT(1) - e2 * sin2_lat1; + CT const cos2_sin2 = cos2_lat1 * math::sqr(sin_alp1); + CT const vertex_lat = std::asin( math::sqrt((e2_sin2 - cos2_sin2) + / (e2_sin2 - e2 * cos2_sin2))); + return vertex_lat; } template diff --git a/include/boost/geometry/strategies/azimuth.hpp b/include/boost/geometry/strategies/azimuth.hpp new file mode 100644 index 000000000..fdcb5a445 --- /dev/null +++ b/include/boost/geometry/strategies/azimuth.hpp @@ -0,0 +1,36 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2016 Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fisikopoulos, 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_AZIMUTH_HPP +#define BOOST_GEOMETRY_STRATEGIES_AZIMUTH_HPP + +#include + +namespace boost { namespace geometry +{ + + +namespace strategy { namespace azimuth { namespace services +{ + +/*! + \brief Traits class binding a default azimuth strategy to a coordinate system + \ingroup azimuth + \tparam Tag tag of coordinate system +*/ +template +struct default_strategy +{}; + +}}} // namespace strategy::azimuth::services + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGIES_AZIMUTH_HPP diff --git a/include/boost/geometry/strategies/cartesian/azimuth_cartesian.hpp b/include/boost/geometry/strategies/cartesian/azimuth_cartesian.hpp new file mode 100644 index 000000000..a4a167370 --- /dev/null +++ b/include/boost/geometry/strategies/cartesian/azimuth_cartesian.hpp @@ -0,0 +1,64 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2016 Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fisikopoulos, 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_CARTESIAN_AZIMUTH_CARTESIAN_HPP +#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_AZIMUTH_CARTESIAN_HPP + +#include + +namespace boost { namespace geometry +{ + +namespace strategy { namespace azimuth +{ + +template +< + typename CalculationType +> +class azimuth_cartesian +{ +public : + + inline azimuth_cartesian() + {} + + inline void apply(CalculationType const& lon1_rad, + CalculationType const& lat1_rad, + CalculationType const& lon2_rad, + CalculationType const& lat2_rad, + CalculationType& a1, + CalculationType& a2) const + { + // not implemented + } + +}; + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +namespace services +{ + +template +struct default_strategy +{ + typedef strategy::azimuth::azimuth_cartesian type; +}; + +} + +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +}} // namespace strategy::azimuth + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_AZIMUTH_CARTESIAN_HPP diff --git a/include/boost/geometry/strategies/geographic/azimuth_geographic.hpp b/include/boost/geometry/strategies/geographic/azimuth_geographic.hpp new file mode 100644 index 000000000..92cd3a3af --- /dev/null +++ b/include/boost/geometry/strategies/geographic/azimuth_geographic.hpp @@ -0,0 +1,70 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2016 Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fisikopoulos, 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_GEOGRAPHIC_AZIMUTH_GEOGRAPHIC_HPP +#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_AZIMUTH_GEOGRAPHIC_HPP + +namespace boost { namespace geometry +{ + +namespace strategy { namespace azimuth +{ + +template +< + typename CalculationType, + template class Inverse = + geometry::formula::thomas_inverse +> +class azimuth_geographic +{ +public : + + inline azimuth_geographic() + {} + + inline void apply(CalculationType const& lon1_rad, + CalculationType const& lat1_rad, + CalculationType const& lon2_rad, + CalculationType const& lat2_rad, + CalculationType& a1, + CalculationType& a2) const + { + typedef Inverse inverse_type; + typedef typename inverse_type::result_type inverse_result; + inverse_result i_res = inverse_type::apply(lon1_rad, lat1_rad, + lon2_rad, lat2_rad, + geometry::srs::spheroid()); + a1 = i_res.azimuth; + a2 = i_res.reverse_azimuth; + } + +}; + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +namespace services +{ + +template +struct default_strategy +{ + typedef strategy::azimuth::azimuth_geographic type; +}; + +} + +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +}} // namespace strategy::azimuth + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_AZIMUTH_GEOGRAPHIC_HPP diff --git a/include/boost/geometry/strategies/spherical/azimuth_spherical.hpp b/include/boost/geometry/strategies/spherical/azimuth_spherical.hpp new file mode 100644 index 000000000..206012677 --- /dev/null +++ b/include/boost/geometry/strategies/spherical/azimuth_spherical.hpp @@ -0,0 +1,66 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2016 Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fisikopoulos, 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_AZIMUTH_SPHERICAL_HPP +#define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_AZIMUTH_SPHERICAL_HPP + +namespace boost { namespace geometry +{ + +namespace strategy { namespace azimuth +{ + +template +< + typename CalculationType +> +class azimuth_spherical +{ +public : + + inline azimuth_spherical() + {} + + inline void apply(CalculationType const& lon1_rad, + CalculationType const& lat1_rad, + CalculationType const& lon2_rad, + CalculationType const& lat2_rad, + CalculationType& a1, + CalculationType& a2) const + { + geometry::formula::result_spherical result = geometry::formula:: + spherical_azimuth(lon1_rad, lat1_rad, lon2_rad, lat2_rad); + + a1 = result.azimuth; + a2 = result.reverse_azimuth; + } + +}; + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +namespace services +{ + +template +struct default_strategy +{ + typedef strategy::azimuth::azimuth_spherical type; +}; + +} + +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +}} // namespace strategy::azimuth + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_AZIMUTH_SPHERICAL_HPP diff --git a/include/boost/geometry/strategies/strategies.hpp b/include/boost/geometry/strategies/strategies.hpp index 342485cc4..bb09f5b49 100644 --- a/include/boost/geometry/strategies/strategies.hpp +++ b/include/boost/geometry/strategies/strategies.hpp @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -35,6 +36,7 @@ #include #include +#include #include #include #include @@ -58,6 +60,7 @@ #include #include +#include #include #include #include @@ -65,6 +68,7 @@ #include #include +#include #include #include #include From 36af2b870f8490be39828455e8ae7668a8bf5b1e Mon Sep 17 00:00:00 2001 From: Vissarion Fysikopoulos Date: Mon, 19 Sep 2016 13:37:17 +0300 Subject: [PATCH 27/89] [envelope] [expand] [algorithms] [test] Envelope and expand algorithms with strategies --- .../algorithms/detail/envelope/box.hpp | 12 ++-- .../detail/envelope/implementation.hpp | 4 +- .../algorithms/detail/envelope/interface.hpp | 29 ++++++--- .../algorithms/detail/envelope/linear.hpp | 7 +- .../algorithms/detail/envelope/multipoint.hpp | 10 +-- .../algorithms/detail/envelope/point.hpp | 10 +-- .../algorithms/detail/envelope/range.hpp | 32 ++++----- .../detail/envelope/range_of_boxes.hpp | 18 +++-- .../algorithms/detail/envelope/segment.hpp | 33 ++++++---- .../geometry/algorithms/detail/expand/box.hpp | 12 ++-- .../algorithms/detail/expand/indexed.hpp | 20 +++--- .../algorithms/detail/expand/interface.hpp | 65 +++++++++++++++---- .../algorithms/detail/expand/point.hpp | 22 ++++--- .../algorithms/detail/expand/segment.hpp | 15 +++-- .../geographic/azimuth_geographic.hpp | 3 + .../spherical/azimuth_spherical.hpp | 9 +++ test/algorithms/envelope_expand/envelope.cpp | 7 ++ .../envelope_expand/envelope_on_spheroid.cpp | 3 + test/algorithms/envelope_expand/expand.cpp | 4 +- .../envelope_expand/test_envelope.hpp | 8 ++- 20 files changed, 215 insertions(+), 108 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/envelope/box.hpp b/include/boost/geometry/algorithms/detail/envelope/box.hpp index 379026294..40d219117 100644 --- a/include/boost/geometry/algorithms/detail/envelope/box.hpp +++ b/include/boost/geometry/algorithms/detail/envelope/box.hpp @@ -97,8 +97,10 @@ struct envelope_indexed_box_on_spheroid struct envelope_box { - template - static inline void apply(BoxIn const& box_in, BoxOut& mbr) + template + static inline void apply(BoxIn const& box_in, + BoxOut& mbr, + Strategy const& strategy) { envelope_indexed_box < @@ -115,8 +117,10 @@ struct envelope_box struct envelope_box_on_spheroid { - template - static inline void apply(BoxIn const& box_in, BoxOut& mbr) + template + static inline void apply(BoxIn const& box_in, + BoxOut& mbr, + Strategy const& strategy) { BoxIn box_in_normalized = detail::return_normalized(box_in); diff --git a/include/boost/geometry/algorithms/detail/envelope/implementation.hpp b/include/boost/geometry/algorithms/detail/envelope/implementation.hpp index 6b3193e42..577a0fdb9 100644 --- a/include/boost/geometry/algorithms/detail/envelope/implementation.hpp +++ b/include/boost/geometry/algorithms/detail/envelope/implementation.hpp @@ -57,12 +57,12 @@ struct envelope_polygon envelope_multi_range < envelope_range - >::apply(interior_rings(polygon), mbr); + >::apply(interior_rings(polygon), mbr, strategy); } else { // otherwise, consider only the exterior ring - envelope_range::apply(ext_ring, mbr); + envelope_range::apply(ext_ring, mbr, strategy); } } }; diff --git a/include/boost/geometry/algorithms/detail/envelope/interface.hpp b/include/boost/geometry/algorithms/detail/envelope/interface.hpp index 8f82119ad..ae6ce3a99 100644 --- a/include/boost/geometry/algorithms/detail/envelope/interface.hpp +++ b/include/boost/geometry/algorithms/detail/envelope/interface.hpp @@ -27,6 +27,10 @@ #include +#include +#include +#include +#include namespace boost { namespace geometry { @@ -48,7 +52,9 @@ struct envelope } */ template - static inline void apply(Geometry const& geometry, Box& box, Strategy const& strategy) + static inline void apply(Geometry const& geometry, + Box& box, + Strategy const& strategy) { concepts::check(); concepts::check(); @@ -57,29 +63,35 @@ struct envelope } }; + template struct envelope > { - template + template struct visitor: boost::static_visitor { Box& m_box; + Strategy const& m_strategy; - visitor(Box& box): m_box(box) {} + visitor(Box& box, Strategy const& strategy) + : m_box(box) + , m_strategy(strategy) + {} template void operator()(Geometry const& geometry) const { - envelope::apply(geometry, m_box); + envelope::apply(geometry, m_box, m_strategy); } }; - template + template static inline void apply(boost::variant const& geometry, - Box& box) + Box& box, + Strategy const& strategy) { - boost::apply_visitor(visitor(box), geometry); + boost::apply_visitor(visitor(box, strategy), geometry); } }; @@ -127,8 +139,7 @@ inline void envelope(Geometry const& geometry, Box& mbr) // TODO put this into a resolve_strategy stage // (and take the return type from resolve_variant) typedef typename point_type::type point_type; - typedef typename coordinate_type::type coordinate_type; - //typedef typename strategy::azimuth::azimuth_geographic strategy_type; + typedef typename coordinate_type::type coordinate_type; typedef typename strategy::azimuth::services::default_strategy < diff --git a/include/boost/geometry/algorithms/detail/envelope/linear.hpp b/include/boost/geometry/algorithms/detail/envelope/linear.hpp index 49c3cf313..3afa50573 100644 --- a/include/boost/geometry/algorithms/detail/envelope/linear.hpp +++ b/include/boost/geometry/algorithms/detail/envelope/linear.hpp @@ -36,12 +36,13 @@ namespace detail { namespace envelope struct envelope_linestring_on_spheroid { - template - static inline void apply(Linestring const& linestring, Box& mbr) + template + static inline void apply(Linestring const& linestring, Box& mbr, Strategy const& strategy) { envelope_range::apply(geometry::segments_begin(linestring), geometry::segments_end(linestring), - mbr); + mbr, + strategy); } }; diff --git a/include/boost/geometry/algorithms/detail/envelope/multipoint.hpp b/include/boost/geometry/algorithms/detail/envelope/multipoint.hpp index 210debfdb..65d0b4cf0 100644 --- a/include/boost/geometry/algorithms/detail/envelope/multipoint.hpp +++ b/include/boost/geometry/algorithms/detail/envelope/multipoint.hpp @@ -226,8 +226,8 @@ private: } public: - template - static inline void apply(MultiPoint const& multipoint, Box& mbr) + template + static inline void apply(MultiPoint const& multipoint, Box& mbr, Strategy const& strategy) { typedef typename point_type::type point_type; typedef typename coordinate_type::type coordinate_type; @@ -255,7 +255,7 @@ public: return dispatch::envelope < typename boost::range_value::type - >::apply(range::front(multipoint), mbr); + >::apply(range::front(multipoint), mbr, strategy); } // analyze the points and put the non-pole ones in the @@ -329,7 +329,7 @@ public: // compute envelope for higher coordinates iterator_type it = boost::begin(multipoint); - envelope_one_point<2, dimension::value>::apply(*it, mbr); + envelope_one_point<2, dimension::value>::apply(*it, mbr, strategy); for (++it; it != boost::end(multipoint); ++it) { @@ -338,7 +338,7 @@ public: strategy::compare::default_strategy, strategy::compare::default_strategy, 2, dimension::value - >::apply(mbr, *it); + >::apply(mbr, *it, strategy); } } }; diff --git a/include/boost/geometry/algorithms/detail/envelope/point.hpp b/include/boost/geometry/algorithms/detail/envelope/point.hpp index e914e7e8a..15286de71 100644 --- a/include/boost/geometry/algorithms/detail/envelope/point.hpp +++ b/include/boost/geometry/algorithms/detail/envelope/point.hpp @@ -58,8 +58,8 @@ struct envelope_one_point >::apply(point, box_corner); } - template - static inline void apply(Point const& point, Box& mbr) + template + static inline void apply(Point const& point, Box& mbr, Strategy strategy) { apply(point, mbr); apply(point, mbr); @@ -69,8 +69,8 @@ struct envelope_one_point struct envelope_point_on_spheroid { - template - static inline void apply(Point const& point, Box& mbr) + template + static inline void apply(Point const& point, Box& mbr, Strategy const& strategy) { Point normalized_point = detail::return_normalized(point); @@ -88,7 +88,7 @@ struct envelope_point_on_spheroid envelope_one_point < 2, dimension::value - >::apply(normalized_point, mbr); + >::apply(normalized_point, mbr, strategy); } }; diff --git a/include/boost/geometry/algorithms/detail/envelope/range.hpp b/include/boost/geometry/algorithms/detail/envelope/range.hpp index 63b518114..82700cbeb 100644 --- a/include/boost/geometry/algorithms/detail/envelope/range.hpp +++ b/include/boost/geometry/algorithms/detail/envelope/range.hpp @@ -51,8 +51,8 @@ namespace detail { namespace envelope // implementation for simple ranges struct envelope_range { - template - static inline void apply(Iterator first, Iterator last, Box& mbr) + template + static inline void apply(Iterator first, Iterator last, Box& mbr, Strategy const& strategy) { typedef typename std::iterator_traits::value_type value_type; @@ -63,20 +63,20 @@ struct envelope_range if (it != last) { // initialize box with first element in range - dispatch::envelope::apply(*it, mbr); + dispatch::envelope::apply(*it, mbr, strategy); // consider now the remaining elements in the range (if any) for (++it; it != last; ++it) { - dispatch::expand::apply(mbr, *it); + dispatch::expand::apply(mbr, *it, strategy); } } } - template - static inline void apply(Range const& range, Box& mbr) + template + static inline void apply(Range const& range, Box& mbr, Strategy const& strategy) { - return apply(boost::begin(range), boost::end(range), mbr); + return apply(boost::begin(range), boost::end(range), mbr, strategy); } }; @@ -85,8 +85,8 @@ struct envelope_range template struct envelope_multi_range { - template - static inline void apply(MultiRange const& multirange, Box& mbr) + template + static inline void apply(MultiRange const& multirange, Box& mbr, Strategy const& strategy) { typedef typename boost::range_iterator < @@ -103,14 +103,14 @@ struct envelope_multi_range if (initialized) { Box helper_mbr; - EnvelopePolicy::apply(*it, helper_mbr); + EnvelopePolicy::apply(*it, helper_mbr, strategy); - dispatch::expand::apply(mbr, helper_mbr); + dispatch::expand::apply(mbr, helper_mbr, strategy); } else { // compute the initial envelope - EnvelopePolicy::apply(*it, mbr); + EnvelopePolicy::apply(*it, mbr, strategy); initialized = true; } } @@ -129,8 +129,8 @@ struct envelope_multi_range template struct envelope_multi_range_on_spheroid { - template - static inline void apply(MultiRange const& multirange, Box& mbr) + template + static inline void apply(MultiRange const& multirange, Box& mbr, Strategy const& strategy) { typedef typename boost::range_iterator < @@ -147,7 +147,7 @@ struct envelope_multi_range_on_spheroid if (! geometry::is_empty(*it)) { Box helper_box; - EnvelopePolicy::apply(*it, helper_box); + EnvelopePolicy::apply(*it, helper_box, strategy); boxes.push_back(helper_box); } } @@ -159,7 +159,7 @@ struct envelope_multi_range_on_spheroid // and the MBR is simply initialized if (! boxes.empty()) { - envelope_range_of_boxes::apply(boxes, mbr); + envelope_range_of_boxes::apply(boxes, mbr, strategy); } else { 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 64bdb9b9c..283c3564b 100644 --- a/include/boost/geometry/algorithms/detail/envelope/range_of_boxes.hpp +++ b/include/boost/geometry/algorithms/detail/envelope/range_of_boxes.hpp @@ -149,8 +149,10 @@ 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) + template + static inline void apply(RangeOfBoxes const& range_of_boxes, + Box& mbr, + Strategy const& strategy) { typedef typename boost::range_value::type box_type; @@ -196,7 +198,7 @@ struct envelope_range_of_boxes_by_expansion min_corner, Dimension, DimensionCount - >::apply(mbr, *it); + >::apply(mbr, *it, strategy); detail::expand::indexed_loop < @@ -205,7 +207,7 @@ struct envelope_range_of_boxes_by_expansion max_corner, Dimension, DimensionCount - >::apply(mbr, *it); + >::apply(mbr, *it, strategy); } } @@ -225,8 +227,10 @@ struct envelope_range_of_boxes } }; - template - static inline void apply(RangeOfBoxes const& range_of_boxes, Box& mbr) + template + static inline void apply(RangeOfBoxes const& range_of_boxes, + Box& mbr, + Strategy const& strategy) { // boxes in the range are assumed to be normalized already @@ -313,7 +317,7 @@ struct envelope_range_of_boxes envelope_range_of_boxes_by_expansion < 2, dimension::value - >::apply(range_of_boxes, mbr); + >::apply(range_of_boxes, mbr, strategy); } }; diff --git a/include/boost/geometry/algorithms/detail/envelope/segment.hpp b/include/boost/geometry/algorithms/detail/envelope/segment.hpp index 7a6a38c4f..f339e9e82 100644 --- a/include/boost/geometry/algorithms/detail/envelope/segment.hpp +++ b/include/boost/geometry/algorithms/detail/envelope/segment.hpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -48,9 +49,6 @@ #include #include -#include -#include -#include namespace boost { namespace geometry { @@ -64,16 +62,19 @@ template struct envelope_one_segment { template - static inline void apply(Point const& p1, Point const& p2, Box& mbr, Strategy const& strategy) + static inline void apply(Point const& p1, + Point const& p2, + Box& mbr, + Strategy const& strategy) { - envelope_one_point::apply(p1, mbr); + envelope_one_point::apply(p1, mbr, strategy); detail::expand::point_loop < strategy::compare::default_strategy, strategy::compare::default_strategy, Dimension, DimensionCount - >::apply(mbr, p2); + >::apply(mbr, p2, strategy); } }; @@ -231,9 +232,9 @@ private: if (mid_lat < 0) { // update using min latitude - //CalculationType const lat_min_rad = -max_latitude(a1, lat1_rad); CalculationType const lat_min_rad = -p_max; - CalculationType const lat_min = math::from_radian(lat_min_rad); + CalculationType const lat_min + = math::from_radian(lat_min_rad); if (lat1 > lat_min) { @@ -243,9 +244,9 @@ private: else if (mid_lat > 0) { // update using max latitude - //CalculationType const lat_max_rad = max_latitude(a1, lat1_rad); CalculationType const lat_max_rad = p_max; - CalculationType const lat_max = math::from_radian(lat_max_rad); + CalculationType const lat_max + = math::from_radian(lat_max_rad); if (lat2 < lat_max) { @@ -320,7 +321,12 @@ private: } public: - template + template < + typename Units, + typename CalculationType, + typename Box, + typename Strategy + > static inline void apply(CalculationType lon1, CalculationType lat1, CalculationType lon2, @@ -368,7 +374,10 @@ template struct envelope_segment_on_sphere_or_spheroid { template - static inline void apply(Point const& p1, Point const& p2, Box& mbr, Strategy const& strategy) + static inline void apply(Point const& p1, + Point const& p2, + Box& mbr, + Strategy const& strategy) { // first compute the envelope range for the first two coordinates Point p1_normalized = detail::return_normalized(p1); diff --git a/include/boost/geometry/algorithms/detail/expand/box.hpp b/include/boost/geometry/algorithms/detail/expand/box.hpp index 4c89e6f1d..3c0635274 100644 --- a/include/boost/geometry/algorithms/detail/expand/box.hpp +++ b/include/boost/geometry/algorithms/detail/expand/box.hpp @@ -44,16 +44,18 @@ namespace detail { namespace expand struct box_on_spheroid { - template - static inline void apply(BoxOut& box_out, BoxIn const& box_in) + template + static inline void apply(BoxOut& box_out, + BoxIn const& box_in, + Strategy const& strategy) { // normalize both boxes and convert box-in to be of type of box-out BoxOut mbrs[2]; - detail::envelope::envelope_box_on_spheroid::apply(box_in, mbrs[0]); - detail::envelope::envelope_box_on_spheroid::apply(box_out, mbrs[1]); + detail::envelope::envelope_box_on_spheroid::apply(box_in, mbrs[0], strategy); + detail::envelope::envelope_box_on_spheroid::apply(box_out, mbrs[1], strategy); // compute the envelope of the two boxes - detail::envelope::envelope_range_of_boxes::apply(mbrs, box_out); + detail::envelope::envelope_range_of_boxes::apply(mbrs, box_out, strategy); } }; diff --git a/include/boost/geometry/algorithms/detail/expand/indexed.hpp b/include/boost/geometry/algorithms/detail/expand/indexed.hpp index bdd6eb450..d83d21d2e 100644 --- a/include/boost/geometry/algorithms/detail/expand/indexed.hpp +++ b/include/boost/geometry/algorithms/detail/expand/indexed.hpp @@ -49,8 +49,8 @@ template > struct indexed_loop { - template - static inline void apply(Box& box, Geometry const& source) + template + static inline void apply(Box& box, Geometry const& source, Strategy const& strategy) { typedef typename strategy::compare::detail::select_strategy < @@ -87,7 +87,7 @@ struct indexed_loop < StrategyLess, StrategyGreater, Index, Dimension + 1, DimensionCount - >::apply(box, source); + >::apply(box, source, strategy); } }; @@ -103,8 +103,8 @@ struct indexed_loop Index, DimensionCount, DimensionCount > { - template - static inline void apply(Box&, Geometry const&) {} + template + static inline void apply(Box&, Geometry const&, Strategy const&) {} }; @@ -117,20 +117,22 @@ template > struct expand_indexed { - template - static inline void apply(Box& box, Geometry const& geometry) + template + static inline void apply(Box& box, + Geometry const& geometry, + Strategy const& strategy) { indexed_loop < StrategyLess, StrategyGreater, 0, Dimension, DimensionCount - >::apply(box, geometry); + >::apply(box, geometry, strategy); indexed_loop < StrategyLess, StrategyGreater, 1, Dimension, DimensionCount - >::apply(box, geometry); + >::apply(box, geometry, strategy); } }; diff --git a/include/boost/geometry/algorithms/detail/expand/interface.hpp b/include/boost/geometry/algorithms/detail/expand/interface.hpp index 140754af4..1ef8d312b 100644 --- a/include/boost/geometry/algorithms/detail/expand/interface.hpp +++ b/include/boost/geometry/algorithms/detail/expand/interface.hpp @@ -28,6 +28,10 @@ #include +#include +#include +#include +#include namespace boost { namespace geometry { @@ -39,40 +43,45 @@ namespace resolve_variant template struct expand { - template - static inline void apply(Box& box, Geometry const& geometry) + template + static inline void apply(Box& box, Geometry const& geometry, Strategy const& strategy) { concepts::check(); concepts::check(); concepts::check_concepts_and_equal_dimensions(); - dispatch::expand::apply(box, geometry); + dispatch::expand::apply(box, geometry, strategy); } }; template struct expand > { - template + template struct visitor: boost::static_visitor { Box& m_box; + Strategy const& m_strategy; - visitor(Box& box) : m_box(box) {} + visitor(Box& box, Strategy const& strategy) + : m_box(box) + , m_strategy(strategy) + {} template void operator()(Geometry const& geometry) const { - return expand::apply(m_box, geometry); + return expand::apply(m_box, geometry, m_strategy); } }; - template + template static inline void apply(Box& box, - boost::variant const& geometry) + boost::variant const& geometry, + Strategy const& strategy) { - return boost::apply_visitor(visitor(box), geometry); + return boost::apply_visitor(visitor(box, strategy), geometry); } }; @@ -106,21 +115,51 @@ inline void expand(Box& box, Geometry const& geometry, } ***/ - /*! -\brief Expands a box using the bounding box (envelope) of another geometry (box, point) +\brief Expands (with strategy) \ingroup expand \tparam Box type of the box \tparam Geometry \tparam_geometry \param box box to be expanded using another geometry, mutable -\param geometry \param_geometry geometry which envelope (bounding box) will be added to the box +\param geometry \param_geometry geometry which envelope (bounding box) +will be added to the box + +\qbk{[include reference/algorithms/expand.qbk]} + */ +template +inline void expand(Box& box, Geometry const& geometry, Strategy const& strategy) +{ + + resolve_variant::expand::apply(box, geometry, strategy); +} + +/*! +\brief Expands a box using the bounding box (envelope) of another geometry +(box, point) +\ingroup expand +\tparam Box type of the box +\tparam Geometry \tparam_geometry +\param box box to be expanded using another geometry, mutable +\param geometry \param_geometry geometry which envelope (bounding box) will be +added to the box \qbk{[include reference/algorithms/expand.qbk]} */ template inline void expand(Box& box, Geometry const& geometry) { - resolve_variant::expand::apply(box, geometry); + // TODO put this into a resolve_strategy stage + // (and take the return type from resolve_variant) + typedef typename point_type::type point_type; + typedef typename coordinate_type::type coordinate_type; + + typedef typename strategy::azimuth::services::default_strategy + < + typename cs_tag::type, + coordinate_type + >::type strategy_type; + + resolve_variant::expand::apply(box, geometry, strategy_type()); } }} // namespace boost::geometry diff --git a/include/boost/geometry/algorithms/detail/expand/point.hpp b/include/boost/geometry/algorithms/detail/expand/point.hpp index 56b7f1c73..dcaa41d0f 100644 --- a/include/boost/geometry/algorithms/detail/expand/point.hpp +++ b/include/boost/geometry/algorithms/detail/expand/point.hpp @@ -59,8 +59,8 @@ template > struct point_loop { - template - static inline void apply(Box& box, Point const& source) + template + static inline void apply(Box& box, Point const& source, Strategy const& strategy) { typedef typename strategy::compare::detail::select_strategy < @@ -95,22 +95,24 @@ struct point_loop point_loop < StrategyLess, StrategyGreater, Dimension + 1, DimensionCount - >::apply(box, source); + >::apply(box, source, strategy); } }; template < - typename StrategyLess, typename StrategyGreater, std::size_t DimensionCount + typename StrategyLess, + typename StrategyGreater, + std::size_t DimensionCount > struct point_loop < StrategyLess, StrategyGreater, DimensionCount, DimensionCount > { - template - static inline void apply(Box&, Point const&) {} + template + static inline void apply(Box&, Point const&, Strategy const& strategy) {} }; @@ -123,8 +125,10 @@ template > struct point_loop_on_spheroid { - template - static inline void apply(Box& box, Point const& point) + template + static inline void apply(Box& box, + Point const& point, + Strategy const& strategy) { typedef typename point_type::type box_point_type; typedef typename coordinate_type::type box_coordinate_type; @@ -224,7 +228,7 @@ struct point_loop_on_spheroid point_loop < StrategyLess, StrategyGreater, 2, DimensionCount - >::apply(box, point); + >::apply(box, point, strategy); } }; diff --git a/include/boost/geometry/algorithms/detail/expand/segment.hpp b/include/boost/geometry/algorithms/detail/expand/segment.hpp index 7a1c79c4d..85c665a7d 100644 --- a/include/boost/geometry/algorithms/detail/expand/segment.hpp +++ b/include/boost/geometry/algorithms/detail/expand/segment.hpp @@ -42,23 +42,28 @@ namespace detail { namespace expand struct segment_on_sphere { - template - static inline void apply(Box& box, Segment const& segment) + template + static inline void apply(Box& box, + Segment const& segment, + Strategy const& strategy) { Box mbrs[2]; // compute the envelope of the segment + 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_segment_on_sphere_or_spheroid < dimension::value, true - >::apply(segment, mbrs[0]); + >::apply(p[0], p[1], mbrs[0], strategy); // normalize the box - detail::envelope::envelope_box_on_spheroid::apply(box, mbrs[1]); + detail::envelope::envelope_box_on_spheroid::apply(box, mbrs[1], strategy); // compute the envelope of the two boxes - detail::envelope::envelope_range_of_boxes::apply(mbrs, box); + detail::envelope::envelope_range_of_boxes::apply(mbrs, box, strategy); } }; diff --git a/include/boost/geometry/strategies/geographic/azimuth_geographic.hpp b/include/boost/geometry/strategies/geographic/azimuth_geographic.hpp index 92cd3a3af..d9903f766 100644 --- a/include/boost/geometry/strategies/geographic/azimuth_geographic.hpp +++ b/include/boost/geometry/strategies/geographic/azimuth_geographic.hpp @@ -10,6 +10,9 @@ #ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_AZIMUTH_GEOGRAPHIC_HPP #define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_AZIMUTH_GEOGRAPHIC_HPP +#include +#include + namespace boost { namespace geometry { diff --git a/include/boost/geometry/strategies/spherical/azimuth_spherical.hpp b/include/boost/geometry/strategies/spherical/azimuth_spherical.hpp index 206012677..15bb95252 100644 --- a/include/boost/geometry/strategies/spherical/azimuth_spherical.hpp +++ b/include/boost/geometry/strategies/spherical/azimuth_spherical.hpp @@ -10,6 +10,9 @@ #ifndef BOOST_GEOMETRY_STRATEGIES_SPHERICAL_AZIMUTH_SPHERICAL_HPP #define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_AZIMUTH_SPHERICAL_HPP +#include +//#include + namespace boost { namespace geometry { @@ -54,6 +57,12 @@ struct default_strategy typedef strategy::azimuth::azimuth_spherical type; }; +template +struct default_strategy +{ + typedef strategy::azimuth::azimuth_spherical type; +}; + } #endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS diff --git a/test/algorithms/envelope_expand/envelope.cpp b/test/algorithms/envelope_expand/envelope.cpp index 047851430..70ba8d366 100644 --- a/test/algorithms/envelope_expand/envelope.cpp +++ b/test/algorithms/envelope_expand/envelope.cpp @@ -35,6 +35,11 @@ BOOST_GEOMETRY_REGISTER_BOOST_TUPLE_CS(cs::cartesian) template void test_2d() { + test_envelope

("POINT(1 1)", 1, 1, 1, 1); + test_envelope >("LINESTRING(1 1,2 2)", 1, 2, 1, 2); + test_envelope >("POLYGON((1 1,1 3,3 3,3 1,1 1))", 1, 3, 1, 3); + test_envelope >("BOX(1 1,3 3)", 1, 3, 1, 3); + test_envelope

("POINT(1 1)", 1, 1, 1, 1); test_envelope >("LINESTRING(1 1,2 2)", 1, 2, 1, 2); test_envelope >("POLYGON((1 1,1 3,3 3,3 1,1 1))", 1, 3, 1, 3); @@ -52,6 +57,7 @@ void test_2d() typedef std::pair segment_type; test_envelope("SEGMENT(1 1,3 3)", 1, 3, 1, 3); + } template @@ -207,6 +213,7 @@ int test_main(int, char* []) //test_2d(); //test_2d(); //test_2d(); + test_2d >(); test_2d >(); test_2d >(); diff --git a/test/algorithms/envelope_expand/envelope_on_spheroid.cpp b/test/algorithms/envelope_expand/envelope_on_spheroid.cpp index f479e7b7f..4f0ec8913 100644 --- a/test/algorithms/envelope_expand/envelope_on_spheroid.cpp +++ b/test/algorithms/envelope_expand/envelope_on_spheroid.cpp @@ -863,6 +863,7 @@ void test_envelope_multipoint() mp.push_back(P(1-heps, 1-heps)); tester::apply("mp20", mp, 1-heps, 1-heps, 1, 1); } + } BOOST_AUTO_TEST_CASE( envelope_multipoint ) @@ -1262,6 +1263,7 @@ BOOST_AUTO_TEST_CASE( envelope_linestring ) l.push_back(P(1, 1)); tester::apply("l12", l, 0, 0, 1, 1); } + } @@ -1577,3 +1579,4 @@ BOOST_AUTO_TEST_CASE( envelope_cw_ring ) 170, -90, 350, 90); // FAILS NOW } #endif + diff --git a/test/algorithms/envelope_expand/expand.cpp b/test/algorithms/envelope_expand/expand.cpp index b3cf67ba3..dd1257b2c 100644 --- a/test/algorithms/envelope_expand/expand.cpp +++ b/test/algorithms/envelope_expand/expand.cpp @@ -86,10 +86,10 @@ void test_2d() test_expand(b, "BOX(1 1,2 2)", "(1,1),(2,2)"); // Test an 'incorrect' box -> should also correctly update the bbox - test_expand(b, "BOX(3 4,0 1)", "(0,1),(3,4)"); +// test_expand(b, "BOX(3 4,0 1)", "(0,1),(3,4)"); // Test a segment - test_expand(b, "SEGMENT(5 6,7 8)", "(0,1),(7,8)"); +// test_expand(b, "SEGMENT(5 6,7 8)", "(0,1),(7,8)"); } template diff --git a/test/algorithms/envelope_expand/test_envelope.hpp b/test/algorithms/envelope_expand/test_envelope.hpp index bf00d1282..e41dcc409 100644 --- a/test/algorithms/envelope_expand/test_envelope.hpp +++ b/test/algorithms/envelope_expand/test_envelope.hpp @@ -78,17 +78,21 @@ void test_envelope(std::string const& wkt, const T& y1, const T& y2, const T& z1 = 0, const T& z2 = 0) { + typedef bg::model::box::type > box_type; box_type b; Geometry geometry; bg::read_wkt(wkt, geometry); bg::envelope(geometry, b); - check_result::type::value>::apply(b, x1, y1, z1, x2, y2, z2); + check_result::type::value> + ::apply(b, x1, y1, z1, x2, y2, z2); boost::variant v(geometry); bg::envelope(v, b); - check_result::type::value>::apply(b, x1, y1, z1, x2, y2, z2); + check_result::type::value> + ::apply(b, x1, y1, z1, x2, y2, z2); + } From dde8368bc77504443be91b74d89103603d9474d0 Mon Sep 17 00:00:00 2001 From: Vissarion Fysikopoulos Date: Mon, 19 Sep 2016 13:52:59 +0300 Subject: [PATCH 28/89] [envelope] [expand] [algorithms] [test] Code cleaning and copyright info. --- .../algorithms/detail/envelope/box.hpp | 5 +- .../detail/envelope/implementation.hpp | 5 +- .../algorithms/detail/envelope/interface.hpp | 15 +---- .../algorithms/detail/envelope/linear.hpp | 9 ++- .../algorithms/detail/envelope/multipoint.hpp | 3 +- .../algorithms/detail/envelope/point.hpp | 5 +- .../algorithms/detail/envelope/range.hpp | 5 +- .../detail/envelope/range_of_boxes.hpp | 3 +- .../algorithms/detail/envelope/segment.hpp | 55 +------------------ .../geometry/algorithms/detail/expand/box.hpp | 5 +- .../algorithms/detail/expand/indexed.hpp | 5 +- .../algorithms/detail/expand/interface.hpp | 12 ++-- .../algorithms/detail/expand/point.hpp | 5 +- .../algorithms/detail/expand/segment.hpp | 5 +- test/algorithms/envelope_expand/envelope.cpp | 10 +--- .../envelope_expand/envelope_on_spheroid.cpp | 4 -- test/algorithms/envelope_expand/expand.cpp | 4 +- .../envelope_expand/test_envelope.hpp | 1 - 18 files changed, 51 insertions(+), 105 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/envelope/box.hpp b/include/boost/geometry/algorithms/detail/envelope/box.hpp index 40d219117..c39d2da72 100644 --- a/include/boost/geometry/algorithms/detail/envelope/box.hpp +++ b/include/boost/geometry/algorithms/detail/envelope/box.hpp @@ -4,9 +4,10 @@ // 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. +// This file was modified by Oracle on 2015, 2016. +// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Distributed under the Boost Software License, Version 1.0. diff --git a/include/boost/geometry/algorithms/detail/envelope/implementation.hpp b/include/boost/geometry/algorithms/detail/envelope/implementation.hpp index 577a0fdb9..d54970079 100644 --- a/include/boost/geometry/algorithms/detail/envelope/implementation.hpp +++ b/include/boost/geometry/algorithms/detail/envelope/implementation.hpp @@ -4,9 +4,10 @@ // 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. +// This file was modified by Oracle on 2015, 2016. +// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library diff --git a/include/boost/geometry/algorithms/detail/envelope/interface.hpp b/include/boost/geometry/algorithms/detail/envelope/interface.hpp index ae6ce3a99..b740cef0e 100644 --- a/include/boost/geometry/algorithms/detail/envelope/interface.hpp +++ b/include/boost/geometry/algorithms/detail/envelope/interface.hpp @@ -4,9 +4,10 @@ // 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. +// This file was modified by Oracle on 2015, 2016. +// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library @@ -41,16 +42,6 @@ namespace resolve_variant template struct envelope { -/* - template - static inline void apply(Geometry const& geometry, Box& box) - { - concepts::check(); - concepts::check(); - - dispatch::envelope::apply(geometry, box); - } -*/ template static inline void apply(Geometry const& geometry, Box& box, diff --git a/include/boost/geometry/algorithms/detail/envelope/linear.hpp b/include/boost/geometry/algorithms/detail/envelope/linear.hpp index 3afa50573..49efe70a3 100644 --- a/include/boost/geometry/algorithms/detail/envelope/linear.hpp +++ b/include/boost/geometry/algorithms/detail/envelope/linear.hpp @@ -4,9 +4,10 @@ // 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. +// This file was modified by Oracle on 2015, 2016. +// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Distributed under the Boost Software License, Version 1.0. @@ -37,7 +38,9 @@ namespace detail { namespace envelope struct envelope_linestring_on_spheroid { template - static inline void apply(Linestring const& linestring, Box& mbr, Strategy const& strategy) + static inline void apply(Linestring const& linestring, + Box& mbr, + Strategy const& strategy) { envelope_range::apply(geometry::segments_begin(linestring), geometry::segments_end(linestring), diff --git a/include/boost/geometry/algorithms/detail/envelope/multipoint.hpp b/include/boost/geometry/algorithms/detail/envelope/multipoint.hpp index 65d0b4cf0..efee4701c 100644 --- a/include/boost/geometry/algorithms/detail/envelope/multipoint.hpp +++ b/include/boost/geometry/algorithms/detail/envelope/multipoint.hpp @@ -1,7 +1,8 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2015, Oracle and/or its affiliates. +// Copyright (c) 2015-2016, Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Distributed under the Boost Software License, Version 1.0. diff --git a/include/boost/geometry/algorithms/detail/envelope/point.hpp b/include/boost/geometry/algorithms/detail/envelope/point.hpp index 15286de71..c316f84e2 100644 --- a/include/boost/geometry/algorithms/detail/envelope/point.hpp +++ b/include/boost/geometry/algorithms/detail/envelope/point.hpp @@ -4,9 +4,10 @@ // 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. +// This file was modified by Oracle on 2015, 2016. +// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Distributed under the Boost Software License, Version 1.0. diff --git a/include/boost/geometry/algorithms/detail/envelope/range.hpp b/include/boost/geometry/algorithms/detail/envelope/range.hpp index 82700cbeb..48a829d72 100644 --- a/include/boost/geometry/algorithms/detail/envelope/range.hpp +++ b/include/boost/geometry/algorithms/detail/envelope/range.hpp @@ -4,9 +4,10 @@ // 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. +// This file was modified by Oracle on 2015, 2016. +// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library 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 283c3564b..f61fc422d 100644 --- a/include/boost/geometry/algorithms/detail/envelope/range_of_boxes.hpp +++ b/include/boost/geometry/algorithms/detail/envelope/range_of_boxes.hpp @@ -1,7 +1,8 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2015, Oracle and/or its affiliates. +// Copyright (c) 2015-2016, Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Distributed under the Boost Software License, Version 1.0. diff --git a/include/boost/geometry/algorithms/detail/envelope/segment.hpp b/include/boost/geometry/algorithms/detail/envelope/segment.hpp index f339e9e82..b3ce07276 100644 --- a/include/boost/geometry/algorithms/detail/envelope/segment.hpp +++ b/include/boost/geometry/algorithms/detail/envelope/segment.hpp @@ -90,36 +90,7 @@ template class compute_mbr_of_segment { private: -/* - // computes the azimuths of the segment with endpoints (lon1, lat1) - // and (lon2, lat2) - // radians - template - static inline void azimuths(CalculationType const& lon1, - CalculationType const& lat1, - CalculationType const& lon2, - CalculationType const& lat2, - CalculationType& a1, - CalculationType& a2) - { - BOOST_GEOMETRY_ASSERT(lon1 <= lon2); - CalculationType dlon = lon2 - lon1; - CalculationType sin_dlon = sin(dlon); - CalculationType cos_dlon = cos(dlon); - CalculationType cos_lat1 = cos(lat1); - CalculationType cos_lat2 = cos(lat2); - CalculationType sin_lat1 = sin(lat1); - CalculationType sin_lat2 = sin(lat2); - - a1 = atan2(sin_dlon * cos_lat2, - cos_lat1 * sin_lat2 - sin_lat1 * cos_lat2 * cos_dlon); - - a2 = atan2(-sin_dlon * cos_lat1, - cos_lat2 * sin_lat1 - sin_lat2 * cos_lat1 * cos_dlon); - a2 += math::pi(); - } -*/ // degrees or radians template static inline void swap(CalculationType& lon1, @@ -158,16 +129,7 @@ private: return math::abs(lon1 - lon2) > constants::half_period(); // > pi } -/* - // radians - template - static inline CalculationType max_latitude(CalculationType const& azimuth, - CalculationType const& latitude) - { - // azimuth and latitude are assumed to be in radians - return acos( math::abs(cos(latitude) * sin(azimuth)) ); - } -*/ + // degrees or radians template static inline void compute_box_corners(CalculationType& lon1, @@ -186,20 +148,7 @@ private: CalculationType a1, a2; strategy.apply(lon1_rad, lat1_rad, lon2_rad, lat2_rad, a1, a2); -/* if (IsSpherical) - { - //geometry::strategy::azimuth::azimuth_spherical - // azimuth_spherical; - //azimuth_spherical.apply(lon1_rad, lat1_rad, lon2_rad, lat2_rad, a1, a2); - strategy.apply(lon1_rad, lat1_rad, lon2_rad, lat2_rad, a1, a2); - } - else - { - geometry::strategy::azimuth::azimuth_geographic - azimuth_geographic; - azimuth_geographic.apply(lon1_rad, lat1_rad, lon2_rad, lat2_rad, a1, a2); - } -*/ + if (lat1 > lat2) { std::swap(lat1, lat2); diff --git a/include/boost/geometry/algorithms/detail/expand/box.hpp b/include/boost/geometry/algorithms/detail/expand/box.hpp index 3c0635274..3edb23f5a 100644 --- a/include/boost/geometry/algorithms/detail/expand/box.hpp +++ b/include/boost/geometry/algorithms/detail/expand/box.hpp @@ -5,9 +5,10 @@ // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2014-2015 Samuel Debionne, Grenoble, France. -// This file was modified by Oracle on 2015. -// Modifications copyright (c) 2015, Oracle and/or its affiliates. +// This file was modified by Oracle on 2015, 2016. +// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Distributed under the Boost Software License, Version 1.0. diff --git a/include/boost/geometry/algorithms/detail/expand/indexed.hpp b/include/boost/geometry/algorithms/detail/expand/indexed.hpp index d83d21d2e..28cf0e2e4 100644 --- a/include/boost/geometry/algorithms/detail/expand/indexed.hpp +++ b/include/boost/geometry/algorithms/detail/expand/indexed.hpp @@ -5,9 +5,10 @@ // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2014-2015 Samuel Debionne, Grenoble, France. -// This file was modified by Oracle on 2015. -// Modifications copyright (c) 2015, Oracle and/or its affiliates. +// This file was modified by Oracle on 2015, 2016. +// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library diff --git a/include/boost/geometry/algorithms/detail/expand/interface.hpp b/include/boost/geometry/algorithms/detail/expand/interface.hpp index 1ef8d312b..daa15003e 100644 --- a/include/boost/geometry/algorithms/detail/expand/interface.hpp +++ b/include/boost/geometry/algorithms/detail/expand/interface.hpp @@ -5,9 +5,10 @@ // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2014-2015 Samuel Debionne, Grenoble, France. -// This file was modified by Oracle on 2015. -// Modifications copyright (c) 2015, Oracle and/or its affiliates. +// This file was modified by Oracle on 2015, 2016. +// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library @@ -44,7 +45,9 @@ template struct expand { template - static inline void apply(Box& box, Geometry const& geometry, Strategy const& strategy) + static inline void apply(Box& box, + Geometry const& geometry, + Strategy const& strategy) { concepts::check(); concepts::check(); @@ -81,7 +84,8 @@ struct expand > boost::variant const& geometry, Strategy const& strategy) { - return boost::apply_visitor(visitor(box, strategy), geometry); + return boost::apply_visitor(visitor(box, strategy), + geometry); } }; diff --git a/include/boost/geometry/algorithms/detail/expand/point.hpp b/include/boost/geometry/algorithms/detail/expand/point.hpp index dcaa41d0f..aa77fc177 100644 --- a/include/boost/geometry/algorithms/detail/expand/point.hpp +++ b/include/boost/geometry/algorithms/detail/expand/point.hpp @@ -5,9 +5,10 @@ // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2014-2015 Samuel Debionne, Grenoble, France. -// This file was modified by Oracle on 2015. -// Modifications copyright (c) 2015, Oracle and/or its affiliates. +// This file was modified by Oracle on 2015, 2016. +// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library diff --git a/include/boost/geometry/algorithms/detail/expand/segment.hpp b/include/boost/geometry/algorithms/detail/expand/segment.hpp index 85c665a7d..e603742f6 100644 --- a/include/boost/geometry/algorithms/detail/expand/segment.hpp +++ b/include/boost/geometry/algorithms/detail/expand/segment.hpp @@ -5,9 +5,10 @@ // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2014-2015 Samuel Debionne, Grenoble, France. -// This file was modified by Oracle on 2015. -// Modifications copyright (c) 2015, Oracle and/or its affiliates. +// This file was modified by Oracle on 2015, 2016. +// Modifications copyright (c) 2015-2016, Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Distributed under the Boost Software License, Version 1.0. diff --git a/test/algorithms/envelope_expand/envelope.cpp b/test/algorithms/envelope_expand/envelope.cpp index 70ba8d366..7418b27c6 100644 --- a/test/algorithms/envelope_expand/envelope.cpp +++ b/test/algorithms/envelope_expand/envelope.cpp @@ -5,9 +5,10 @@ // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. -// This file was modified by Oracle on 2015. +// This file was modified by Oracle on 2015, 2016. // Modifications copyright (c) 2015, Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library @@ -35,11 +36,6 @@ BOOST_GEOMETRY_REGISTER_BOOST_TUPLE_CS(cs::cartesian) template void test_2d() { - test_envelope

("POINT(1 1)", 1, 1, 1, 1); - test_envelope >("LINESTRING(1 1,2 2)", 1, 2, 1, 2); - test_envelope >("POLYGON((1 1,1 3,3 3,3 1,1 1))", 1, 3, 1, 3); - test_envelope >("BOX(1 1,3 3)", 1, 3, 1, 3); - test_envelope

("POINT(1 1)", 1, 1, 1, 1); test_envelope >("LINESTRING(1 1,2 2)", 1, 2, 1, 2); test_envelope >("POLYGON((1 1,1 3,3 3,3 1,1 1))", 1, 3, 1, 3); @@ -57,7 +53,6 @@ void test_2d() typedef std::pair segment_type; test_envelope("SEGMENT(1 1,3 3)", 1, 3, 1, 3); - } template @@ -213,7 +208,6 @@ int test_main(int, char* []) //test_2d(); //test_2d(); //test_2d(); - test_2d >(); test_2d >(); test_2d >(); diff --git a/test/algorithms/envelope_expand/envelope_on_spheroid.cpp b/test/algorithms/envelope_expand/envelope_on_spheroid.cpp index 4f0ec8913..5c75dbdfa 100644 --- a/test/algorithms/envelope_expand/envelope_on_spheroid.cpp +++ b/test/algorithms/envelope_expand/envelope_on_spheroid.cpp @@ -863,7 +863,6 @@ void test_envelope_multipoint() mp.push_back(P(1-heps, 1-heps)); tester::apply("mp20", mp, 1-heps, 1-heps, 1, 1); } - } BOOST_AUTO_TEST_CASE( envelope_multipoint ) @@ -1262,8 +1261,6 @@ BOOST_AUTO_TEST_CASE( envelope_linestring ) l.push_back(P(0, 0)); l.push_back(P(1, 1)); tester::apply("l12", l, 0, 0, 1, 1); - } - } @@ -1579,4 +1576,3 @@ BOOST_AUTO_TEST_CASE( envelope_cw_ring ) 170, -90, 350, 90); // FAILS NOW } #endif - diff --git a/test/algorithms/envelope_expand/expand.cpp b/test/algorithms/envelope_expand/expand.cpp index dd1257b2c..b3cf67ba3 100644 --- a/test/algorithms/envelope_expand/expand.cpp +++ b/test/algorithms/envelope_expand/expand.cpp @@ -86,10 +86,10 @@ void test_2d() test_expand(b, "BOX(1 1,2 2)", "(1,1),(2,2)"); // Test an 'incorrect' box -> should also correctly update the bbox -// test_expand(b, "BOX(3 4,0 1)", "(0,1),(3,4)"); + test_expand(b, "BOX(3 4,0 1)", "(0,1),(3,4)"); // Test a segment -// test_expand(b, "SEGMENT(5 6,7 8)", "(0,1),(7,8)"); + test_expand(b, "SEGMENT(5 6,7 8)", "(0,1),(7,8)"); } template diff --git a/test/algorithms/envelope_expand/test_envelope.hpp b/test/algorithms/envelope_expand/test_envelope.hpp index e41dcc409..c0dc91639 100644 --- a/test/algorithms/envelope_expand/test_envelope.hpp +++ b/test/algorithms/envelope_expand/test_envelope.hpp @@ -78,7 +78,6 @@ void test_envelope(std::string const& wkt, const T& y1, const T& y2, const T& z1 = 0, const T& z2 = 0) { - typedef bg::model::box::type > box_type; box_type b; From af2b0c680e7bc0564e4fae4665afe5b974db6a8a Mon Sep 17 00:00:00 2001 From: Vissarion Fysikopoulos Date: Mon, 19 Sep 2016 18:02:35 +0300 Subject: [PATCH 29/89] [envelope] [expand] [algorithms] [test] Tests for spheroid. --- .../algorithms/detail/envelope/box.hpp | 4 +- .../algorithms/detail/envelope/linear.hpp | 14 + .../algorithms/detail/envelope/point.hpp | 2 +- .../algorithms/detail/envelope/range.hpp | 13 +- .../algorithms/detail/envelope/segment.hpp | 39 +- .../algorithms/detail/expand/point.hpp | 2 +- .../algorithms/detail/expand/segment.hpp | 21 +- .../geometry/formulas/vertex_latitude.hpp | 43 +- .../envelope_expand/envelope_on_spheroid.cpp | 458 +++++++++++++++++- .../envelope_expand/expand_on_spheroid.cpp | 114 ++++- 10 files changed, 645 insertions(+), 65 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/envelope/box.hpp b/include/boost/geometry/algorithms/detail/envelope/box.hpp index c39d2da72..795f51392 100644 --- a/include/boost/geometry/algorithms/detail/envelope/box.hpp +++ b/include/boost/geometry/algorithms/detail/envelope/box.hpp @@ -101,7 +101,7 @@ struct envelope_box template static inline void apply(BoxIn const& box_in, BoxOut& mbr, - Strategy const& strategy) + Strategy const&) { envelope_indexed_box < @@ -121,7 +121,7 @@ struct envelope_box_on_spheroid template static inline void apply(BoxIn const& box_in, BoxOut& mbr, - Strategy const& strategy) + Strategy const&) { BoxIn box_in_normalized = detail::return_normalized(box_in); diff --git a/include/boost/geometry/algorithms/detail/envelope/linear.hpp b/include/boost/geometry/algorithms/detail/envelope/linear.hpp index 49efe70a3..09d8a76da 100644 --- a/include/boost/geometry/algorithms/detail/envelope/linear.hpp +++ b/include/boost/geometry/algorithms/detail/envelope/linear.hpp @@ -69,6 +69,11 @@ struct envelope : detail::envelope::envelope_linestring_on_spheroid {}; +template +struct envelope + : detail::envelope::envelope_linestring_on_spheroid +{}; + template struct envelope @@ -90,6 +95,15 @@ struct envelope > {}; +template +struct envelope + < + MultiLinestring, multi_linestring_tag, geographic_tag + > : detail::envelope::envelope_multi_range_on_spheroid + < + detail::envelope::envelope_linestring_on_spheroid + > +{}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH diff --git a/include/boost/geometry/algorithms/detail/envelope/point.hpp b/include/boost/geometry/algorithms/detail/envelope/point.hpp index c316f84e2..ee0559bf5 100644 --- a/include/boost/geometry/algorithms/detail/envelope/point.hpp +++ b/include/boost/geometry/algorithms/detail/envelope/point.hpp @@ -60,7 +60,7 @@ struct envelope_one_point } template - static inline void apply(Point const& point, Box& mbr, Strategy strategy) + static inline void apply(Point const& point, Box& mbr, Strategy const&) { apply(point, mbr); apply(point, mbr); diff --git a/include/boost/geometry/algorithms/detail/envelope/range.hpp b/include/boost/geometry/algorithms/detail/envelope/range.hpp index 48a829d72..b5591f61a 100644 --- a/include/boost/geometry/algorithms/detail/envelope/range.hpp +++ b/include/boost/geometry/algorithms/detail/envelope/range.hpp @@ -53,7 +53,10 @@ namespace detail { namespace envelope struct envelope_range { template - static inline void apply(Iterator first, Iterator last, Box& mbr, Strategy const& strategy) + static inline void apply(Iterator first, + Iterator last, + Box& mbr, + Strategy const& strategy) { typedef typename std::iterator_traits::value_type value_type; @@ -87,7 +90,9 @@ template struct envelope_multi_range { template - static inline void apply(MultiRange const& multirange, Box& mbr, Strategy const& strategy) + static inline void apply(MultiRange const& multirange, + Box& mbr, + Strategy const& strategy) { typedef typename boost::range_iterator < @@ -131,7 +136,9 @@ template struct envelope_multi_range_on_spheroid { template - static inline void apply(MultiRange const& multirange, Box& mbr, Strategy const& strategy) + static inline void apply(MultiRange const& multirange, + Box& mbr, + Strategy const& strategy) { typedef typename boost::range_iterator < diff --git a/include/boost/geometry/algorithms/detail/envelope/segment.hpp b/include/boost/geometry/algorithms/detail/envelope/segment.hpp index b3ce07276..7c6839713 100644 --- a/include/boost/geometry/algorithms/detail/envelope/segment.hpp +++ b/include/boost/geometry/algorithms/detail/envelope/segment.hpp @@ -86,7 +86,7 @@ struct envelope_one_segment // normalized and in radians. // The longitudes and latitudes of the endpoints are overridden by // those of the box. -template +template class compute_mbr_of_segment { private: @@ -163,19 +163,8 @@ private: if (contains_pi_half(a1, a2)) { - CalculationType p_max; - - if (IsSpherical) - { - p_max = geometry::formula::vertex_latitude:: - spherical(lat1_rad, a1); - } - else - { - p_max = geometry::formula::vertex_latitude:: - geographic(lat1_rad, a1, - geometry::srs::spheroid()); - } + CalculationType p_max = geometry::formula + ::vertex_latitude::apply(lat1_rad, a1); CalculationType const mid_lat = lat1 + lat2; if (mid_lat < 0) @@ -319,7 +308,7 @@ public: }; -template +template struct envelope_segment_on_sphere_or_spheroid { template @@ -334,7 +323,7 @@ struct envelope_segment_on_sphere_or_spheroid typedef typename coordinate_system::type::units units_type; - compute_mbr_of_segment::template apply( + compute_mbr_of_segment::template apply( geometry::get<0>(p1_normalized), geometry::get<1>(p1_normalized), geometry::get<0>(p2_normalized), @@ -367,13 +356,13 @@ struct envelope_segment template struct envelope_segment - : envelope_segment_on_sphere_or_spheroid + : envelope_segment_on_sphere_or_spheroid {}; template struct envelope_segment - : envelope_segment_on_sphere_or_spheroid + : envelope_segment_on_sphere_or_spheroid {}; @@ -389,19 +378,6 @@ namespace dispatch template struct envelope { -/* - template - static inline void apply(Segment const& segment, Box& mbr) - { - 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_segment - < - dimension::value, CS_Tag - >::apply(p[0], p[1], mbr); - } -*/ template static inline void apply(Segment const& segment, Box& mbr, @@ -415,7 +391,6 @@ struct envelope dimension::value, CS_Tag >::apply(p[0], p[1], mbr, strategy); } - }; } // namespace dispatch diff --git a/include/boost/geometry/algorithms/detail/expand/point.hpp b/include/boost/geometry/algorithms/detail/expand/point.hpp index aa77fc177..f0cbd1db0 100644 --- a/include/boost/geometry/algorithms/detail/expand/point.hpp +++ b/include/boost/geometry/algorithms/detail/expand/point.hpp @@ -113,7 +113,7 @@ struct point_loop > { template - static inline void apply(Box&, Point const&, Strategy const& strategy) {} + static inline void apply(Box&, Point const&, Strategy const&) {} }; diff --git a/include/boost/geometry/algorithms/detail/expand/segment.hpp b/include/boost/geometry/algorithms/detail/expand/segment.hpp index e603742f6..fcc1e3137 100644 --- a/include/boost/geometry/algorithms/detail/expand/segment.hpp +++ b/include/boost/geometry/algorithms/detail/expand/segment.hpp @@ -40,8 +40,8 @@ namespace boost { namespace geometry namespace detail { namespace expand { - -struct segment_on_sphere +template +struct segment_on_sphere_or_spheroid { template static inline void apply(Box& box, @@ -57,7 +57,7 @@ struct segment_on_sphere detail::envelope::envelope_segment_on_sphere_or_spheroid < dimension::value, - true + CS_Tag >::apply(p[0], p[1], mbrs[0], strategy); // normalize the box @@ -110,9 +110,22 @@ struct expand StrategyLess, StrategyGreater, box_tag, segment_tag, spherical_equatorial_tag, spherical_equatorial_tag - > : detail::expand::segment_on_sphere + > : detail::expand::segment_on_sphere_or_spheroid {}; +template +< + typename Box, typename Segment, + typename StrategyLess, typename StrategyGreater +> +struct expand + < + Box, Segment, + StrategyLess, StrategyGreater, + box_tag, segment_tag, + geographic_tag, geographic_tag + > : detail::expand::segment_on_sphere_or_spheroid +{}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH diff --git a/include/boost/geometry/formulas/vertex_latitude.hpp b/include/boost/geometry/formulas/vertex_latitude.hpp index ab1b3f1dd..b960484aa 100644 --- a/include/boost/geometry/formulas/vertex_latitude.hpp +++ b/include/boost/geometry/formulas/vertex_latitude.hpp @@ -13,6 +13,8 @@ #include #include +#include +#include namespace boost { namespace geometry { namespace formula { @@ -26,7 +28,7 @@ a point on the geodesic that maximizes (or minimizes) the latitude. */ template -class vertex_latitude +class vertex_latitude_on_sphere { public: @@ -35,24 +37,28 @@ public: typename T1, typename T2 > - static inline CT spherical(T1 const& lat1, - T2 const& alp1) + static inline CT apply(T1 const& lat1, + T2 const& alp1) { return std::acos( math::abs(cos(lat1) * sin(alp1)) ); } +}; +template +class vertex_latitude_on_spheroid +{ +public: template < //template class Inverse, typename T1, - typename T2, - typename Spheroid + typename T2 > - static inline CT geographic(T1 const& lat1, - T2 const& alp1, - Spheroid const& spheroid) + static inline CT apply(T1 const& lat1, + T2 const& alp1) { + geometry::srs::spheroid spheroid; CT const f = detail::flattening(spheroid); CT const e2 = f * (CT(2) - f); @@ -97,6 +103,27 @@ public: }; +template +struct vertex_latitude +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_COORDINATE_SYSTEM, (types) + ); + +}; + +template +struct vertex_latitude + : vertex_latitude_on_sphere +{}; + +template +struct vertex_latitude + : vertex_latitude_on_spheroid +{}; + + }}} // namespace boost::geometry::formula #endif // BOOST_GEOMETRY_FORMULAS_MAXIMUM_LATITUDE_HPP diff --git a/test/algorithms/envelope_expand/envelope_on_spheroid.cpp b/test/algorithms/envelope_expand/envelope_on_spheroid.cpp index 5c75dbdfa..1b52f9b97 100644 --- a/test/algorithms/envelope_expand/envelope_on_spheroid.cpp +++ b/test/algorithms/envelope_expand/envelope_on_spheroid.cpp @@ -3,6 +3,7 @@ // Copyright (c) 2015-2016, Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -519,7 +520,7 @@ BOOST_AUTO_TEST_CASE( envelope_point_with_height ) } -BOOST_AUTO_TEST_CASE( envelope_segment ) +BOOST_AUTO_TEST_CASE( envelope_segment_sphere ) { typedef bg::cs::spherical_equatorial coordinate_system_type; typedef bg::model::point P; @@ -701,8 +702,189 @@ BOOST_AUTO_TEST_CASE( envelope_segment ) 1-heps, 1, 1, 2); } +BOOST_AUTO_TEST_CASE( envelope_segment_spheroid ) +{ + typedef bg::cs::geographic coordinate_system_type; + typedef bg::model::point P; + typedef bg::model::segment

G; + typedef bg::model::box

B; + typedef test_envelope_on_spheroid tester; -BOOST_AUTO_TEST_CASE( envelope_segment_with_height ) + double const eps = std::numeric_limits::epsilon(); + + tester::apply("s01", + from_wkt("SEGMENT(10 10,40 40)"), + 10, 10, 40, 40); + + tester::apply("s02", + from_wkt("SEGMENT(10 10,40 10)"), + 10, 10, 40, 10.347587605817935); + + tester::apply("s02a", + from_wkt("SEGMENT(40 10,10 10)"), + 10, 10, 40, 10.347587605817935); + + tester::apply("s03", + from_wkt("SEGMENT(160 10,-170 10)"), + 160, 10, 190, 10.347587605817935); + + tester::apply("s03a", + from_wkt("SEGMENT(-170 10,160 10)"), + 160, 10, 190, 10.347587605817935); + + tester::apply("s03b", + from_wkt("SEGMENT(-170 -10,160 -10)"), + 160, -10.347587605817935, 190, -10); + + tester::apply("s04", + from_wkt("SEGMENT(-40 45,140 60)"), + -40, 45, 140, 90); + + tester::apply("s04a", + from_wkt("SEGMENT(-40 45,140 25)"), + -40, 25, 140, 90); + + // segment ending at the north pole + tester::apply("s05", + from_wkt("SEGMENT(40 45,80 90)"), + 40, 45, 40, 90); + + // segment starting at the north pole + tester::apply("s05a", + from_wkt("SEGMENT(80 90,40 45)"), + 40, 45, 40, 90); + + // segment ending at the north pole + tester::apply("s06", + from_wkt("SEGMENT(-40 45,80 90)"), + -40, 45, -40, 90); + + // segment starting at the north pole + tester::apply("s06a", + from_wkt("SEGMENT(70 90,-40 45)"), + -40, 45, -40, 90); + + // segment ending at the north pole + tester::apply("s07", + from_wkt("SEGMENT(40 -45,80 90)"), + 40, -45, 40, 90); + + // segment passing through the south pole + tester::apply("s08", + from_wkt("SEGMENT(-170 -45,10 -30)"), + -170, -90, 10, -30); + + tester::apply("s09", + from_wkt("SEGMENT(1 -45,179 30)"), + 1, -85.392785243526134, 179, 30, + 3 * eps); + + tester::apply("s09a", + from_wkt("SEGMENT(2 -45,181 30)"), + 2, -87.689300911353811, 181, 30); + + // very long segment + tester::apply("s10", + from_wkt("SEGMENT(0 -45,181 30)"), + -179, -88.111912243387664, 0, 30, + 2.0 * eps); + + tester::apply("s11", + from_wkt("SEGMENT(260 30,20 45)"), + -100, 30, 20, 57.990810958016951); + + tester::apply("s11a", + from_wkt("SEGMENT(260 45,20 30)"), + -100, 30, 20, 49.537982311875638); + + // segment degenerating to the north pole + tester::apply("s12", + from_wkt("SEGMENT(10 90,20 90)"), + 0, 90, 0, 90); + + // segment degenerating to the south pole + tester::apply("s13", + from_wkt("SEGMENT(10 -90,20 -90)"), + 0, -90, 0, -90); + + tester::apply("s14", + from_wkt("SEGMENT(20 20,10 30)"), + 10, 20, 20, 30);//48.87458730907602); + + tester::apply("s15", + from_wkt("SEGMENT(50 45,185 45)"), + 50, 45, 185, 69.098479073903178); + + // segment that lies on the equator + tester::apply("s16", + from_wkt("SEGMENT(0 0,50 0)"), + 0, 0, 50, 0); + + // segment that lies on the equator + tester::apply("s16a", + from_wkt("SEGMENT(-50 0,50 0)"), + -50, 0, 50, 0); + + // segment that lies on the equator and touches antimeridian + tester::apply("s16b", + from_wkt("SEGMENT(50 0,180 0)"), + 50, 0, 180, 0); + + // segment that lies on the equator and crosses antimeridian + tester::apply("s16c", + from_wkt("SEGMENT(-170 0,160 0)"), + 160, 0, 190, 0); + + tester::apply("s17", + from_wkt("SEGMENT(140 10, -140 80)"), + 140, 10, 220, 80); + + tester::apply("s17-r", + from_wkt("SEGMENT(-140 80, 140 10)"), + 140, 10, 220, 80); + + tester::apply("s18", + from_wkt("SEGMENT(20 10, 100 80)"), + 20, 10, 100, 80); + + tester::apply("s18-r", + from_wkt("SEGMENT(100 80, 20 10)"), + 20, 10, 100, 80); + + // segment connecting the north and south pole + // + // this should be forbidden actually, as it is not well-defined + // with this test we demonstrate that the algorithm still returns + // something meaningful + tester::apply("s99", + from_wkt("SEGMENT(10 90,20 -90)"), + 0, -90, 0, 90); + + // https://svn.boost.org/trac/boost/ticket/12106 + tester::apply("s100_ticket_12106", + G(P(11.488323611111111, 53.687086666666673), P(11.488324166666667, 53.687086666666673)), + 11.488323611111111, 53.687086666666673, 11.488324166666667, 53.687086666666673); + + double const heps = eps / 2; + + tester::apply("s101", + G(P(1, 1), P(1-heps, 1-heps)), + 1-heps, 1-heps, 1, 1); + tester::apply("s102", + G(P(1, 1), P(1, 1-heps)), + 1, 1-heps, 1, 1); + tester::apply("s103", + G(P(1, 1), P(1-heps, 1)), + 1-heps, 1, 1, 1); + tester::apply("s104", + G(P(2, 1), P(1, 1-heps)), + 1, 1-heps, 2, 1.000038327157039); + tester::apply("s105", + G(P(1, 2), P(1-heps, 1)), + 1-heps, 1, 1, 2); +} + +BOOST_AUTO_TEST_CASE( envelope_segment_sphere_with_height ) { typedef bg::cs::spherical_equatorial coordinate_system_type; typedef bg::model::point point_type; @@ -719,6 +901,22 @@ BOOST_AUTO_TEST_CASE( envelope_segment_with_height ) 10, 10, 567, 40, 40, 1356); } +BOOST_AUTO_TEST_CASE( envelope_segment_spheroid_with_height ) +{ + typedef bg::cs::geographic 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() @@ -1131,7 +1329,7 @@ BOOST_AUTO_TEST_CASE( envelope_box_with_height ) } -BOOST_AUTO_TEST_CASE( envelope_linestring ) +BOOST_AUTO_TEST_CASE( envelope_sphere_linestring ) { typedef bg::cs::spherical_equatorial coordinate_system_type; typedef bg::model::point P; @@ -1261,10 +1459,144 @@ BOOST_AUTO_TEST_CASE( envelope_linestring ) l.push_back(P(0, 0)); l.push_back(P(1, 1)); tester::apply("l12", l, 0, 0, 1, 1); + } +} + +BOOST_AUTO_TEST_CASE( envelope_spheroid_linestring ) +{ + typedef bg::cs::geographic coordinate_system_type; + typedef bg::model::point P; + 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)"), + 10, 15, 10, 15); + + tester::apply("l01a", + from_wkt("LINESTRING(370 15)"), + 10, 15, 10, 15); + + tester::apply("l01b", + from_wkt("LINESTRING(370 90)"), + 0, 90, 0, 90); + + tester::apply("l02", + from_wkt("LINESTRING(10 10,20 20,10 30)"), + 10, 10, 20, 30); + + // linestring that circles the entire globe + tester::apply("l03", + from_wkt("LINESTRING(-185 0,-170 25,-50 10,10 10,20 20,100 5,180 15)"), + -180, 0, 180, 25.322173172331812, + 4.0 * std::numeric_limits::epsilon()); + + // linestring that crosses the antimeridian but staying close to it + tester::apply("l04", + from_wkt("LINESTRING(-170 10,170 45,160 5,-160 25)"), + 160, 5, 200, 45); + + // linestring that goes through the north pole (twice) + tester::apply("l05", + from_wkt("LINESTRING(-170 80,10 60,20 80,-160 30)"), + -170, 30, 20, 90); + + // linestring that goes through the north pole (three times) + tester::apply("l05a", + from_wkt("LINESTRING(-170 80,10 60,20 80,-160 30,-150 30,30 70)"), + -170, 30, 30, 90); + + // linestring that goes through the north pole (four times) + tester::apply("l05b", + from_wkt("LINESTRING(-170 80,10 60,20 80,-160 30,-150 30,30 70,40 85,-140 25)"), + -170, 25, 40, 90); + + // linestring that goes through the north pole (five times) + tester::apply("l05c", + from_wkt("LINESTRING(-170 80,10 60,20 80,-160 30,-150 30,30 70,40 85,-140 25,-130 25,50 45)"), + -170, 25, 50, 90); + + // linestring that goes through the north pole (five times) + tester::apply("l05d", + from_wkt("LINESTRING(-170 80,10 60,20 80,-160 30,-150 30,30 70,40 85,-140 25,-130 25,50 45,185 45)"), + -170, 25, 185, 90); + + // linestring that crosses the antimeridian + tester::apply("l06", + from_wkt("LINESTRING(-160 85,-170 80,170 40,160 80)"), + 160, 40, 200, 85); + + // linestring that crosses the antimeridian + tester::apply("l06a", + from_wkt("LINESTRING(-130 85,-170 84,170 40,160 80)"), + 160, 40, 230, 85.026305563151482); + + // linestring that goes through the north pole + tester::apply("l07", + from_wkt("LINESTRING(-160 40,-170 90,-140 40,-50 30)"), + -160, 30, -50, 90); + + // linestring that degenerates to the north pole + tester::apply("l08", + from_wkt("LINESTRING(-40 90,-30 90,-140 90,10 90)"), + 0, 90, 0, 90); + + // linestring with duplicate points + tester::apply("l09", + from_wkt("LINESTRING(-40 20,-40 20,-140 85,-10 5,-10 5)"), + -140, 5, -10, 85); + + // linestring with duplicate points + tester::apply("l09a", + from_wkt("LINESTRING(-40 20,320 20,-140 85,-10 5,350 5)"), + -140, 5, -10, 85); + + // linestring that lies on the equator + tester::apply("l10", + from_wkt("LINESTRING(0 0,50 0)"), + 0, 0, 50, 0); + + // linestring that lies on the equator + tester::apply("l10a", + from_wkt("LINESTRING(-50 0,50 0)"), + -50, 0, 50, 0); + + // linestring that lies on the equator and touches antimeridian + tester::apply("l10b", + from_wkt("LINESTRING(50 0,180 0)"), + 50, 0, 180, 0); + + // linestring that lies on the equator and crosses antimeridian + tester::apply("l10c", + from_wkt("LINESTRING(-170 0,160 0)"), + 160, 0, 190, 0); + + double eps = std::numeric_limits::epsilon(); + double heps = eps / 2; + + { + G l; + l.push_back(P(1, 1)); + l.push_back(P(1-heps, 1-heps)); + tester::apply("l11", l, 1-heps, 1-heps, 1, 1); + } + + { + G l; + l.push_back(P(0, 0)); + l.push_back(P(1-heps, 1-heps)); + l.push_back(P(0, 0)); + l.push_back(P(1, 1)); + tester::apply("l12", l, 0, 0, 1, 1); + } } -BOOST_AUTO_TEST_CASE( envelope_linestring_with_height ) +BOOST_AUTO_TEST_CASE( envelope_linestring_sphere_with_height ) { typedef bg::cs::spherical_equatorial coordinate_system_type; typedef bg::model::point point_type; @@ -1280,8 +1612,23 @@ BOOST_AUTO_TEST_CASE( envelope_linestring_with_height ) 10, 15, 30, 30, 35, 434); } +BOOST_AUTO_TEST_CASE( envelope_linestring_speroid_with_height ) +{ + typedef bg::cs::geographic 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; -BOOST_AUTO_TEST_CASE( envelope_multilinestring ) + // 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_sphere_multilinestring ) { typedef bg::cs::spherical_equatorial coordinate_system_type; typedef bg::model::point point_type; @@ -1345,8 +1692,72 @@ BOOST_AUTO_TEST_CASE( envelope_multilinestring ) 10, 25, 260, 80.07385383411011); } +BOOST_AUTO_TEST_CASE( envelope_spheroid_multilinestring ) +{ + typedef bg::cs::geographic 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; -BOOST_AUTO_TEST_CASE( envelope_multilinestring_with_height ) + // 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))"), + -180, 25, 180, 80); + + tester::apply("ml03", + from_wkt("MULTILINESTRING((-150 40,-100 80,10 40),(-10 25,10 35,100 45),(50 30,150 45,-160 30))"), + -150, 25, 200, 80); + + tester::apply("ml04", + from_wkt("MULTILINESTRING((-150 40,-100 80),(10 35,100 80))"), + -150, 35, 100, 80.082544902477267); + + tester::apply("ml04a", + from_wkt("MULTILINESTRING((-150 40,-100 80),(10 35,100 80),(170 25,-160 80))"), + 10, 25, 260, 80.082544902477267); + + tester::apply("ml05", + from_wkt("MULTILINESTRING((-140 40,-100 80),(10 35,100 80))"), + -140, 35, 100, 80.082544902477267); + + tester::apply("ml05a", + from_wkt("MULTILINESTRING((-140 40,-100 80),(10 35,100 80),(170 25,-160 80))"), + 10, 25, 260, 80.082544902477267); +} + + +BOOST_AUTO_TEST_CASE( envelope_multilinestring_sphere_with_height ) { typedef bg::cs::spherical_equatorial coordinate_system_type; typedef bg::model::point point_type; @@ -1369,22 +1780,47 @@ BOOST_AUTO_TEST_CASE( envelope_multilinestring_with_height ) -10, 25, 300, 260, 80, 700); } +BOOST_AUTO_TEST_CASE( envelope_multilinestring_spheroid_with_height ) +{ + typedef bg::cs::geographic 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) // TODO: re-activate once implementation is done BOOST_AUTO_TEST_CASE( envelope_cw_ring ) { - typedef deg_cw_ring_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::polygon G; + typedef bg::model::box B; + typedef test_envelope_on_spheroid tester; double const eps = std::numeric_limits::epsilon(); tester::apply("r01cw", from_wkt("POLYGON((0 10,0 45,50 10,0 10))"), 0, 10, 50, 45); - +#if 0 // ring that contains both the north and south poles in its interior tester::apply("r01cw-r", from_wkt("POLYGON((0 10,50 10,0 45,0 10))"), @@ -1574,5 +2010,5 @@ BOOST_AUTO_TEST_CASE( envelope_cw_ring ) tester::apply("r21cw-r", from_wkt("POLYGON((-10 0,-10 -90,170 0,170 90,-10 0))"), 170, -90, 350, 90); // FAILS NOW -} #endif +} diff --git a/test/algorithms/envelope_expand/expand_on_spheroid.cpp b/test/algorithms/envelope_expand/expand_on_spheroid.cpp index 40426469d..99b184abc 100644 --- a/test/algorithms/envelope_expand/expand_on_spheroid.cpp +++ b/test/algorithms/envelope_expand/expand_on_spheroid.cpp @@ -1,8 +1,9 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // Unit Test -// Copyright (c) 2015, Oracle and/or its affiliates. +// Copyright (c) 2015-2016, Oracle and/or its affiliates. +// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Licensed under the Boost Software License version 1.0. @@ -624,7 +625,7 @@ BOOST_AUTO_TEST_CASE( expand_point_with_height ) } -BOOST_AUTO_TEST_CASE( expand_segment ) +BOOST_AUTO_TEST_CASE( expand_segment_sphere ) { typedef bg::cs::spherical_equatorial coordinate_system_type; typedef bg::model::point point_type; @@ -703,8 +704,86 @@ BOOST_AUTO_TEST_CASE( expand_segment ) 10, -90, 100, 45); } +BOOST_AUTO_TEST_CASE( expand_segment_spheroid ) +{ + typedef bg::cs::geographic 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; -BOOST_AUTO_TEST_CASE( expand_segment_with_height ) + tester::apply("s01", + from_wkt("BOX(20 20,50 50)"), + from_wkt("SEGMENT(10 10,40 40)"), + 10, 10, 50, 50); + + tester::apply("s02", + from_wkt("BOX(20 20,50 50)"), + from_wkt("SEGMENT(10 10,40 10)"), + 10, 10, 50, 50); + + tester::apply("s03", + from_wkt("BOX(5 5,50 10)"), + from_wkt("SEGMENT(40 10,10 10)"), + 5, 5, 50, 10.347587605817935, + 4.0 * std::numeric_limits::epsilon()); + + // segment ending at the north pole + tester::apply("s04", + from_wkt("BOX(5 15,50 50)"), + from_wkt("SEGMENT(40 45,80 90)"), + 5, 15, 50, 90); + + // segment ending at the north pole + tester::apply("s04a", + from_wkt("BOX(5 15,30 30)"), + from_wkt("SEGMENT(40 45,80 90)"), + 5, 15, 40, 90); + + // segment starting at the north pole + tester::apply("s05", + from_wkt("BOX(5 15,50 50)"), + from_wkt("SEGMENT(80 90,40 45)"), + 5, 15, 50, 90); + + // segment starting at the north pole + tester::apply("s05a", + from_wkt("BOX(5 15,30 30)"), + from_wkt("SEGMENT(80 90,40 45)"), + 5, 15, 40, 90); + + // segment passing through the south pole + tester::apply("s06", + from_wkt("BOX(5 15,30 40)"), + from_wkt("SEGMENT(-170 -45,10 -30)"), + -170, -90, 30, 40); + + // segment degenerating to the north pole + tester::apply("s07", + from_wkt("BOX(5 15,30 40)"), + from_wkt("SEGMENT(10 90,20 90)"), + 5, 15, 30, 90); + + // segment degenerating to the south pole + tester::apply("s08", + from_wkt("BOX(5 15,30 40)"), + from_wkt("SEGMENT(10 -90,20 -90)"), + 5, -90, 30, 40); + + // box degenerating to the south pole + tester::apply("s09", + from_wkt("BOX(10 -90,30 -90)"), + from_wkt("SEGMENT(10 -30,100 45)"), + 10, -90, 100, 45); + + // box degenerating to the south pole + tester::apply("s09a", + from_wkt("BOX(10 -90,130 -90)"), + from_wkt("SEGMENT(10 -30,100 45)"), + 10, -90, 100, 45); +} + +BOOST_AUTO_TEST_CASE( expand_segment_sphere_with_height ) { typedef bg::cs::spherical_equatorial coordinate_system_type; typedef bg::model::point point_type; @@ -733,6 +812,35 @@ BOOST_AUTO_TEST_CASE( expand_segment_with_height ) 10, 10, 60, 50, 50, 1000); } +BOOST_AUTO_TEST_CASE( expand_segment_spheroid_with_height ) +{ + typedef bg::cs::geographic 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() From dfe08e58d2a8003683eed3c1c295d575b9deea78 Mon Sep 17 00:00:00 2001 From: Vissarion Fysikopoulos Date: Tue, 20 Sep 2016 14:21:17 +0300 Subject: [PATCH 30/89] [envelope] [algorithms] [test] Tests for spheroid with strategies. --- .../envelope_expand/envelope_on_spheroid.cpp | 526 +++++++++++++++++- 1 file changed, 520 insertions(+), 6 deletions(-) diff --git a/test/algorithms/envelope_expand/envelope_on_spheroid.cpp b/test/algorithms/envelope_expand/envelope_on_spheroid.cpp index 1b52f9b97..a6d2c2036 100644 --- a/test/algorithms/envelope_expand/envelope_on_spheroid.cpp +++ b/test/algorithms/envelope_expand/envelope_on_spheroid.cpp @@ -10,6 +10,9 @@ // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html +#include +#include +#include #ifndef BOOST_TEST_MODULE #define BOOST_TEST_MODULE test_envelope_on_spheroid @@ -47,8 +50,41 @@ #include "test_envelope_expand_on_spheroid.hpp" +template < + template class Inverse, + typename CS_Tag + > +struct test_envelope +{ + template + static inline void apply(Geometry& geometry, Box& detected) + { + bg::envelope(geometry, detected); + } +}; -template +template