// Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2009-2015 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2015-2021. // Modifications copyright (c) 2015-2021, 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) #ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_CENTROID_WEIGHTED_LENGTH_HPP #define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_CENTROID_WEIGHTED_LENGTH_HPP #include #include #include // Helper geometry #include #include #include #include #include namespace boost { namespace geometry { namespace strategy { namespace centroid { template < typename Ignored1 = void, typename Ignored2 = void, typename CalculationType = void > class weighted_length { private : typedef geometry::strategy::distance::pythagoras pythagoras_strategy; template struct calculation_type { // Below the distance between two GeometryPoints is calculated. // ResultPoint is taken into account by passing them together here. typedef typename pythagoras_strategy::template calculation_type < GeometryPoint, ResultPoint >::type type; }; template class sums { friend class weighted_length; template friend struct set_sum_div_length; typedef typename calculation_type::type calc_type; typedef typename geometry::model::point < calc_type, geometry::dimension::value, cs::cartesian > work_point; calc_type length; work_point average_sum; public: inline sums() : length(calc_type()) { geometry::assign_zero(average_sum); } }; public : template struct state_type { typedef sums type; }; template static inline void apply(GeometryPoint const& p1, GeometryPoint const& p2, sums& state) { typedef typename calculation_type::type distance_type; distance_type const d = pythagoras_strategy::apply(p1, p2); state.length += d; distance_type const d_half = d / distance_type(2); geometry::detail::for_each_dimension([&](auto dimension) { distance_type const coord1 = get(p1); distance_type const coord2 = get(p2); distance_type const wm = (coord1 + coord2) * d_half; // weighted median set(state.average_sum, get(state.average_sum) + wm); }); } template static inline bool result(sums const& state, ResultPoint& centroid) { typedef typename calculation_type::type distance_type; distance_type const zero = distance_type(); if (! geometry::math::equals(state.length, zero) && boost::math::isfinite(state.length)) // Prevent NaN centroid coordinates { // NOTE: above distance_type is checked, not the centroid coordinate_type // which means that the centroid can still be filled with INF // if e.g. distance_type is double and centroid contains floats geometry::detail::for_each_dimension([&](auto dimension) { typedef typename geometry::coordinate_type::type coordinate_type; geometry::set( centroid, boost::numeric_cast( geometry::get(state.average_sum) / state.length ) ); }); return true; } return false; } }; #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS namespace services { // Register this strategy for linear geometries, in all dimensions template struct default_strategy < cartesian_tag, linear_tag, N, Point, Geometry > { typedef weighted_length < Point, typename point_type::type > type; }; } // namespace services #endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS }} // namespace strategy::centroid }} // namespace boost::geometry #endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_CENTROID_WEIGHTED_LENGTH_HPP