1 // Boost.Geometry Index
2 //
3 // n-dimensional box's margin value (hypersurface), 2d perimeter, 3d surface, etc...
4 //
5 // Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
6 //
7 // This file was modified by Oracle on 2020.
8 // Modifications copyright (c) 2020 Oracle and/or its affiliates.
9 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
10 //
11 // Use, modification and distribution is subject to the Boost Software License,
12 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
13 // http://www.boost.org/LICENSE_1_0.txt)
14
15 #ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_MARGIN_HPP
16 #define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_MARGIN_HPP
17
18 #include <boost/geometry/core/static_assert.hpp>
19
20 // WARNING! comparable_margin() will work only if the same Geometries are compared
21 // so it shouldn't be used in the case of Variants!
22
23 namespace boost { namespace geometry { namespace index { namespace detail {
24
25 template <typename Box>
26 struct default_margin_result
27 {
28 typedef typename select_most_precise<
29 typename coordinate_type<Box>::type,
30 long double
31 >::type type;
32 };
33
34 //template <typename Box,
35 // std::size_t CurrentDimension,
36 // std::size_t EdgeDimension = dimension<Box>::value>
37 //struct margin_for_each_edge
38 //{
39 // BOOST_STATIC_ASSERT(0 < CurrentDimension);
40 // BOOST_STATIC_ASSERT(0 < EdgeDimension);
41 //
42 // static inline typename default_margin_result<Box>::type apply(Box const& b)
43 // {
44 // return margin_for_each_edge<Box, CurrentDimension, EdgeDimension - 1>::apply(b) *
45 // ( geometry::get<max_corner, EdgeDimension - 1>(b) - geometry::get<min_corner, EdgeDimension - 1>(b) );
46 // }
47 //};
48 //
49 //template <typename Box, std::size_t CurrentDimension>
50 //struct margin_for_each_edge<Box, CurrentDimension, CurrentDimension>
51 //{
52 // BOOST_STATIC_ASSERT(0 < CurrentDimension);
53 //
54 // static inline typename default_margin_result<Box>::type apply(Box const& b)
55 // {
56 // return margin_for_each_edge<Box, CurrentDimension, CurrentDimension - 1>::apply(b);
57 // }
58 //};
59 //
60 //template <typename Box, std::size_t CurrentDimension>
61 //struct margin_for_each_edge<Box, CurrentDimension, 1>
62 //{
63 // BOOST_STATIC_ASSERT(0 < CurrentDimension);
64 //
65 // static inline typename default_margin_result<Box>::type apply(Box const& b)
66 // {
67 // return geometry::get<max_corner, 0>(b) - geometry::get<min_corner, 0>(b);
68 // }
69 //};
70 //
71 //template <typename Box>
72 //struct margin_for_each_edge<Box, 1, 1>
73 //{
74 // static inline typename default_margin_result<Box>::type apply(Box const& /*b*/)
75 // {
76 // return 1;
77 // }
78 //};
79 //
80 //template <typename Box,
81 // std::size_t CurrentDimension = dimension<Box>::value>
82 //struct margin_for_each_dimension
83 //{
84 // BOOST_STATIC_ASSERT(0 < CurrentDimension);
85 //
86 // static inline typename default_margin_result<Box>::type apply(Box const& b)
87 // {
88 // return margin_for_each_dimension<Box, CurrentDimension - 1>::apply(b) +
89 // margin_for_each_edge<Box, CurrentDimension>::apply(b);
90 // }
91 //};
92 //
93 //template <typename Box>
94 //struct margin_for_each_dimension<Box, 1>
95 //{
96 // static inline typename default_margin_result<Box>::type apply(Box const& b)
97 // {
98 // return margin_for_each_edge<Box, 1>::apply(b);
99 // }
100 //};
101
102 // TODO - test if this definition of margin is ok for Dimension > 2
103 // Now it's sum of edges lengths
104 // maybe margin_for_each_dimension should be used to get more or less hypersurface?
105
106 template <typename Box,
107 std::size_t CurrentDimension = dimension<Box>::value>
108 struct simple_margin_for_each_dimension
109 {
110 BOOST_STATIC_ASSERT(0 < CurrentDimension);
111
applyboost::geometry::index::detail::simple_margin_for_each_dimension112 static inline typename default_margin_result<Box>::type apply(Box const& b)
113 {
114 return simple_margin_for_each_dimension<Box, CurrentDimension - 1>::apply(b) +
115 geometry::get<max_corner, CurrentDimension - 1>(b) - geometry::get<min_corner, CurrentDimension - 1>(b);
116 }
117 };
118
119 template <typename Box>
120 struct simple_margin_for_each_dimension<Box, 1>
121 {
applyboost::geometry::index::detail::simple_margin_for_each_dimension122 static inline typename default_margin_result<Box>::type apply(Box const& b)
123 {
124 return geometry::get<max_corner, 0>(b) - geometry::get<min_corner, 0>(b);
125 }
126 };
127
128 namespace dispatch {
129
130 template <typename Geometry, typename Tag>
131 struct comparable_margin
132 {
133 BOOST_GEOMETRY_STATIC_ASSERT_FALSE(
134 "Not implemented for this Geometry type.",
135 Geometry, Tag);
136 };
137
138 template <typename Geometry>
139 struct comparable_margin<Geometry, point_tag>
140 {
141 typedef typename default_margin_result<Geometry>::type result_type;
142
applyboost::geometry::index::detail::dispatch::comparable_margin143 static inline result_type apply(Geometry const& ) { return 0; }
144 };
145
146 template <typename Box>
147 struct comparable_margin<Box, box_tag>
148 {
149 typedef typename default_margin_result<Box>::type result_type;
150
applyboost::geometry::index::detail::dispatch::comparable_margin151 static inline result_type apply(Box const& g)
152 {
153 //return detail::margin_for_each_dimension<Box>::apply(g);
154 return detail::simple_margin_for_each_dimension<Box>::apply(g);
155 }
156 };
157
158 } // namespace dispatch
159
160 template <typename Geometry>
comparable_margin(Geometry const & g)161 typename default_margin_result<Geometry>::type comparable_margin(Geometry const& g)
162 {
163 return dispatch::comparable_margin<
164 Geometry,
165 typename tag<Geometry>::type
166 >::apply(g);
167 }
168
169 //template <typename Box>
170 //typename default_margin_result<Box>::type margin(Box const& b)
171 //{
172 // return 2 * detail::margin_for_each_dimension<Box>::apply(b);
173 //}
174
175 }}}} // namespace boost::geometry::index::detail
176
177 #endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_MARGIN_HPP
178