centroid_weighted_length.hpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
  3. // Copyright (c) 2009-2015 Barend Gehrels, Amsterdam, the Netherlands.
  4. // This file was modified by Oracle on 2015.
  5. // Modifications copyright (c) 2015, Oracle and/or its affiliates.
  6. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  7. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
  8. // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
  9. // Use, modification and distribution is subject to the Boost Software License,
  10. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  11. // http://www.boost.org/LICENSE_1_0.txt)
  12. #ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_CENTROID_WEIGHTED_LENGTH_HPP
  13. #define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_CENTROID_WEIGHTED_LENGTH_HPP
  14. #include <boost/math/special_functions/fpclassify.hpp>
  15. #include <boost/numeric/conversion/cast.hpp>
  16. #include <boost/geometry/algorithms/detail/distance/interface.hpp>
  17. #include <boost/geometry/algorithms/detail/distance/point_to_geometry.hpp>
  18. #include <boost/geometry/arithmetic/arithmetic.hpp>
  19. #include <boost/geometry/util/for_each_coordinate.hpp>
  20. #include <boost/geometry/util/select_most_precise.hpp>
  21. #include <boost/geometry/strategies/centroid.hpp>
  22. #include <boost/geometry/strategies/default_distance_result.hpp>
  23. // Helper geometry
  24. #include <boost/geometry/geometries/point.hpp>
  25. namespace boost { namespace geometry
  26. {
  27. namespace strategy { namespace centroid
  28. {
  29. namespace detail
  30. {
  31. template <typename Type, std::size_t DimensionCount>
  32. struct weighted_length_sums
  33. {
  34. typedef typename geometry::model::point
  35. <
  36. Type, DimensionCount,
  37. cs::cartesian
  38. > work_point;
  39. Type length;
  40. work_point average_sum;
  41. inline weighted_length_sums()
  42. : length(Type())
  43. {
  44. geometry::assign_zero(average_sum);
  45. }
  46. };
  47. }
  48. template
  49. <
  50. typename Point,
  51. typename PointOfSegment = Point
  52. >
  53. class weighted_length
  54. {
  55. private :
  56. typedef typename select_most_precise
  57. <
  58. typename default_distance_result<Point>::type,
  59. typename default_distance_result<PointOfSegment>::type
  60. >::type distance_type;
  61. public :
  62. typedef detail::weighted_length_sums
  63. <
  64. distance_type,
  65. geometry::dimension<Point>::type::value
  66. > state_type;
  67. static inline void apply(PointOfSegment const& p1,
  68. PointOfSegment const& p2, state_type& state)
  69. {
  70. distance_type const d = geometry::distance(p1, p2);
  71. state.length += d;
  72. typename state_type::work_point weighted_median;
  73. geometry::assign_zero(weighted_median);
  74. geometry::add_point(weighted_median, p1);
  75. geometry::add_point(weighted_median, p2);
  76. geometry::multiply_value(weighted_median, d/2);
  77. geometry::add_point(state.average_sum, weighted_median);
  78. }
  79. static inline bool result(state_type const& state, Point& centroid)
  80. {
  81. distance_type const zero = distance_type();
  82. if (! geometry::math::equals(state.length, zero)
  83. && boost::math::isfinite(state.length)) // Prevent NaN centroid coordinates
  84. {
  85. // NOTE: above distance_type is checked, not the centroid coordinate_type
  86. // which means that the centroid can still be filled with INF
  87. // if e.g. distance_type is double and centroid contains floats
  88. geometry::for_each_coordinate(centroid, set_sum_div_length(state));
  89. return true;
  90. }
  91. return false;
  92. }
  93. struct set_sum_div_length
  94. {
  95. state_type const& m_state;
  96. set_sum_div_length(state_type const& state)
  97. : m_state(state)
  98. {}
  99. template <typename Pt, std::size_t Dimension>
  100. void apply(Pt & centroid) const
  101. {
  102. typedef typename geometry::coordinate_type<Pt>::type coordinate_type;
  103. geometry::set<Dimension>(
  104. centroid,
  105. boost::numeric_cast<coordinate_type>(
  106. geometry::get<Dimension>(m_state.average_sum) / m_state.length
  107. )
  108. );
  109. }
  110. };
  111. };
  112. #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
  113. namespace services
  114. {
  115. // Register this strategy for linear geometries, in all dimensions
  116. template <std::size_t N, typename Point, typename Geometry>
  117. struct default_strategy
  118. <
  119. cartesian_tag,
  120. linear_tag,
  121. N,
  122. Point,
  123. Geometry
  124. >
  125. {
  126. typedef weighted_length
  127. <
  128. Point,
  129. typename point_type<Geometry>::type
  130. > type;
  131. };
  132. } // namespace services
  133. #endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
  134. }} // namespace strategy::centroid
  135. }} // namespace boost::geometry
  136. #endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_CENTROID_WEIGHTED_LENGTH_HPP