colocate_clusters.hpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. // Boost.Geometry
  2. // Copyright (c) 2023 Barend Gehrels, Amsterdam, the Netherlands.
  3. // Use, modification and distribution is subject to the Boost Software License,
  4. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COLOCATE_CLUSTERS_HPP
  7. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COLOCATE_CLUSTERS_HPP
  8. #include <boost/geometry/core/access.hpp>
  9. #include <boost/geometry/core/cs.hpp>
  10. #include <boost/geometry/core/coordinate_type.hpp>
  11. #include <boost/geometry/core/tags.hpp>
  12. namespace boost { namespace geometry
  13. {
  14. #ifndef DOXYGEN_NO_DETAIL
  15. namespace detail { namespace overlay
  16. {
  17. // Default implementation, using the first point for all turns in the cluster.
  18. template
  19. <
  20. typename Point,
  21. typename CoordinateType = typename geometry::coordinate_type<Point>::type,
  22. typename CsTag = typename geometry::cs_tag<Point>::type,
  23. bool IsIntegral = std::is_integral<CoordinateType>::value
  24. >
  25. struct cluster_colocator
  26. {
  27. template <typename TurnIndices, typename Turns>
  28. static inline void apply(TurnIndices const& indices, Turns& turns)
  29. {
  30. // This approach works for all but one testcase (rt_p13)
  31. // The problem is fill_sbs, which uses sides and these sides might change slightly
  32. // depending on the exact location of the cluster.
  33. // Using the centroid is, on the average, a safer choice for sides.
  34. // Alternatively fill_sbs could be revised, but that requires a lot of work
  35. // and is outside current scope.
  36. // Integer coordinates are always colocated already and do not need centroid calculation.
  37. // Geographic/spherical coordinates might (in extremely rare cases) cross the date line
  38. // and therefore the first point is taken for them as well.
  39. auto it = indices.begin();
  40. auto const& first_point = turns[*it].point;
  41. for (++it; it != indices.end(); ++it)
  42. {
  43. turns[*it].point = first_point;
  44. }
  45. }
  46. };
  47. // Specialization for non-integral cartesian coordinates, calculating
  48. // the centroid of the points of the turns in the cluster.
  49. template <typename Point, typename CoordinateType>
  50. struct cluster_colocator<Point, CoordinateType, geometry::cartesian_tag, false>
  51. {
  52. template <typename TurnIndices, typename Turns>
  53. static inline void apply(TurnIndices const& indices, Turns& turns)
  54. {
  55. CoordinateType centroid_0 = 0;
  56. CoordinateType centroid_1 = 0;
  57. for (auto const& index : indices)
  58. {
  59. centroid_0 += geometry::get<0>(turns[index].point);
  60. centroid_1 += geometry::get<1>(turns[index].point);
  61. }
  62. centroid_0 /= indices.size();
  63. centroid_1 /= indices.size();
  64. for (auto const& index : indices)
  65. {
  66. geometry::set<0>(turns[index].point, centroid_0);
  67. geometry::set<1>(turns[index].point, centroid_1);
  68. }
  69. }
  70. };
  71. // Moves intersection points per cluster such that they are identical.
  72. // Because clusters are intersection close together, and
  73. // handled as one location. Then they should also have one location.
  74. // It is necessary to avoid artefacts and invalidities.
  75. template <typename Clusters, typename Turns>
  76. inline void colocate_clusters(Clusters const& clusters, Turns& turns)
  77. {
  78. for (auto const& pair : clusters)
  79. {
  80. auto const& turn_indices = pair.second.turn_indices;
  81. if (turn_indices.size() < 2)
  82. {
  83. // Defensive check
  84. continue;
  85. }
  86. using point_t = decltype(turns[*turn_indices.begin()].point);
  87. cluster_colocator<point_t>::apply(turn_indices, turns);
  88. }
  89. }
  90. }} // namespace detail::overlay
  91. #endif //DOXYGEN_NO_DETAIL
  92. }} // namespace boost::geometry
  93. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COLOCATE_CLUSTERS_HPP