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