Chris@16
|
1 // Boost.Geometry (aka GGL, Generic Geometry Library)
|
Chris@16
|
2
|
Chris@16
|
3 // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
|
Chris@16
|
4 // Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
|
Chris@16
|
5 // Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
|
Chris@16
|
6
|
Chris@16
|
7 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
|
Chris@16
|
8 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
|
Chris@16
|
9
|
Chris@16
|
10 // Use, modification and distribution is subject to the Boost Software License,
|
Chris@16
|
11 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
12 // http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
13
|
Chris@16
|
14 #ifndef BOOST_GEOMETRY_ALGORITHMS_EQUALS_HPP
|
Chris@16
|
15 #define BOOST_GEOMETRY_ALGORITHMS_EQUALS_HPP
|
Chris@16
|
16
|
Chris@16
|
17
|
Chris@16
|
18 #include <cstddef>
|
Chris@16
|
19 #include <vector>
|
Chris@16
|
20
|
Chris@16
|
21 #include <boost/range.hpp>
|
Chris@16
|
22
|
Chris@16
|
23 #include <boost/geometry/core/access.hpp>
|
Chris@16
|
24 #include <boost/geometry/core/coordinate_dimension.hpp>
|
Chris@16
|
25 #include <boost/geometry/core/reverse_dispatch.hpp>
|
Chris@16
|
26
|
Chris@16
|
27 #include <boost/geometry/geometries/concepts/check.hpp>
|
Chris@16
|
28
|
Chris@16
|
29 #include <boost/geometry/algorithms/detail/disjoint.hpp>
|
Chris@16
|
30 #include <boost/geometry/algorithms/detail/not.hpp>
|
Chris@16
|
31 #include <boost/geometry/algorithms/not_implemented.hpp>
|
Chris@16
|
32
|
Chris@16
|
33 // For trivial checks
|
Chris@16
|
34 #include <boost/geometry/algorithms/area.hpp>
|
Chris@16
|
35 #include <boost/geometry/algorithms/length.hpp>
|
Chris@16
|
36 #include <boost/geometry/util/math.hpp>
|
Chris@16
|
37 #include <boost/geometry/util/select_coordinate_type.hpp>
|
Chris@16
|
38 #include <boost/geometry/util/select_most_precise.hpp>
|
Chris@16
|
39
|
Chris@16
|
40 #include <boost/geometry/algorithms/detail/equals/collect_vectors.hpp>
|
Chris@16
|
41
|
Chris@16
|
42 #include <boost/variant/static_visitor.hpp>
|
Chris@16
|
43 #include <boost/variant/apply_visitor.hpp>
|
Chris@16
|
44
|
Chris@16
|
45
|
Chris@16
|
46 namespace boost { namespace geometry
|
Chris@16
|
47 {
|
Chris@16
|
48
|
Chris@16
|
49 #ifndef DOXYGEN_NO_DETAIL
|
Chris@16
|
50 namespace detail { namespace equals
|
Chris@16
|
51 {
|
Chris@16
|
52
|
Chris@16
|
53
|
Chris@16
|
54 template
|
Chris@16
|
55 <
|
Chris@16
|
56 std::size_t Dimension,
|
Chris@16
|
57 std::size_t DimensionCount
|
Chris@16
|
58 >
|
Chris@16
|
59 struct box_box
|
Chris@16
|
60 {
|
Chris@16
|
61 template <typename Box1, typename Box2>
|
Chris@16
|
62 static inline bool apply(Box1 const& box1, Box2 const& box2)
|
Chris@16
|
63 {
|
Chris@16
|
64 if (!geometry::math::equals(get<min_corner, Dimension>(box1), get<min_corner, Dimension>(box2))
|
Chris@16
|
65 || !geometry::math::equals(get<max_corner, Dimension>(box1), get<max_corner, Dimension>(box2)))
|
Chris@16
|
66 {
|
Chris@16
|
67 return false;
|
Chris@16
|
68 }
|
Chris@16
|
69 return box_box<Dimension + 1, DimensionCount>::apply(box1, box2);
|
Chris@16
|
70 }
|
Chris@16
|
71 };
|
Chris@16
|
72
|
Chris@16
|
73 template <std::size_t DimensionCount>
|
Chris@16
|
74 struct box_box<DimensionCount, DimensionCount>
|
Chris@16
|
75 {
|
Chris@16
|
76 template <typename Box1, typename Box2>
|
Chris@16
|
77 static inline bool apply(Box1 const& , Box2 const& )
|
Chris@16
|
78 {
|
Chris@16
|
79 return true;
|
Chris@16
|
80 }
|
Chris@16
|
81 };
|
Chris@16
|
82
|
Chris@16
|
83
|
Chris@16
|
84 struct area_check
|
Chris@16
|
85 {
|
Chris@16
|
86 template <typename Geometry1, typename Geometry2>
|
Chris@16
|
87 static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
|
Chris@16
|
88 {
|
Chris@16
|
89 return geometry::math::equals(
|
Chris@16
|
90 geometry::area(geometry1),
|
Chris@16
|
91 geometry::area(geometry2));
|
Chris@16
|
92 }
|
Chris@16
|
93 };
|
Chris@16
|
94
|
Chris@16
|
95
|
Chris@16
|
96 struct length_check
|
Chris@16
|
97 {
|
Chris@16
|
98 template <typename Geometry1, typename Geometry2>
|
Chris@16
|
99 static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
|
Chris@16
|
100 {
|
Chris@16
|
101 return geometry::math::equals(
|
Chris@16
|
102 geometry::length(geometry1),
|
Chris@16
|
103 geometry::length(geometry2));
|
Chris@16
|
104 }
|
Chris@16
|
105 };
|
Chris@16
|
106
|
Chris@16
|
107
|
Chris@16
|
108 template <typename TrivialCheck>
|
Chris@16
|
109 struct equals_by_collection
|
Chris@16
|
110 {
|
Chris@16
|
111 template <typename Geometry1, typename Geometry2>
|
Chris@16
|
112 static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
|
Chris@16
|
113 {
|
Chris@16
|
114 if (! TrivialCheck::apply(geometry1, geometry2))
|
Chris@16
|
115 {
|
Chris@16
|
116 return false;
|
Chris@16
|
117 }
|
Chris@16
|
118
|
Chris@16
|
119 typedef typename geometry::select_most_precise
|
Chris@16
|
120 <
|
Chris@16
|
121 typename select_coordinate_type
|
Chris@16
|
122 <
|
Chris@16
|
123 Geometry1, Geometry2
|
Chris@16
|
124 >::type,
|
Chris@16
|
125 double
|
Chris@16
|
126 >::type calculation_type;
|
Chris@16
|
127
|
Chris@16
|
128 typedef std::vector<collected_vector<calculation_type> > v;
|
Chris@16
|
129 v c1, c2;
|
Chris@16
|
130
|
Chris@16
|
131 geometry::collect_vectors(c1, geometry1);
|
Chris@16
|
132 geometry::collect_vectors(c2, geometry2);
|
Chris@16
|
133
|
Chris@16
|
134 if (boost::size(c1) != boost::size(c2))
|
Chris@16
|
135 {
|
Chris@16
|
136 return false;
|
Chris@16
|
137 }
|
Chris@16
|
138
|
Chris@16
|
139 std::sort(c1.begin(), c1.end());
|
Chris@16
|
140 std::sort(c2.begin(), c2.end());
|
Chris@16
|
141
|
Chris@16
|
142 // Just check if these vectors are equal.
|
Chris@16
|
143 return std::equal(c1.begin(), c1.end(), c2.begin());
|
Chris@16
|
144 }
|
Chris@16
|
145 };
|
Chris@16
|
146
|
Chris@16
|
147
|
Chris@16
|
148 }} // namespace detail::equals
|
Chris@16
|
149 #endif // DOXYGEN_NO_DETAIL
|
Chris@16
|
150
|
Chris@16
|
151
|
Chris@16
|
152 #ifndef DOXYGEN_NO_DISPATCH
|
Chris@16
|
153 namespace dispatch
|
Chris@16
|
154 {
|
Chris@16
|
155
|
Chris@16
|
156 template
|
Chris@16
|
157 <
|
Chris@16
|
158 typename Geometry1,
|
Chris@16
|
159 typename Geometry2,
|
Chris@16
|
160 typename Tag1 = typename tag<Geometry1>::type,
|
Chris@16
|
161 typename Tag2 = typename tag<Geometry2>::type,
|
Chris@16
|
162 std::size_t DimensionCount = dimension<Geometry1>::type::value,
|
Chris@16
|
163 bool Reverse = reverse_dispatch<Geometry1, Geometry2>::type::value
|
Chris@16
|
164 >
|
Chris@16
|
165 struct equals: not_implemented<Tag1, Tag2>
|
Chris@16
|
166 {};
|
Chris@16
|
167
|
Chris@16
|
168
|
Chris@16
|
169 // If reversal is needed, perform it
|
Chris@16
|
170 template
|
Chris@16
|
171 <
|
Chris@16
|
172 typename Geometry1, typename Geometry2,
|
Chris@16
|
173 typename Tag1, typename Tag2,
|
Chris@16
|
174 std::size_t DimensionCount
|
Chris@16
|
175 >
|
Chris@16
|
176 struct equals<Geometry1, Geometry2, Tag1, Tag2, DimensionCount, true>
|
Chris@16
|
177 : equals<Geometry2, Geometry1, Tag2, Tag1, DimensionCount, false>
|
Chris@16
|
178 {
|
Chris@16
|
179 static inline bool apply(Geometry1 const& g1, Geometry2 const& g2)
|
Chris@16
|
180 {
|
Chris@16
|
181 return equals
|
Chris@16
|
182 <
|
Chris@16
|
183 Geometry2, Geometry1,
|
Chris@16
|
184 Tag2, Tag1,
|
Chris@16
|
185 DimensionCount,
|
Chris@16
|
186 false
|
Chris@16
|
187 >::apply(g2, g1);
|
Chris@16
|
188 }
|
Chris@16
|
189 };
|
Chris@16
|
190
|
Chris@16
|
191
|
Chris@16
|
192 template <typename P1, typename P2, std::size_t DimensionCount, bool Reverse>
|
Chris@16
|
193 struct equals<P1, P2, point_tag, point_tag, DimensionCount, Reverse>
|
Chris@16
|
194 : geometry::detail::not_
|
Chris@16
|
195 <
|
Chris@16
|
196 P1,
|
Chris@16
|
197 P2,
|
Chris@16
|
198 detail::disjoint::point_point<P1, P2, 0, DimensionCount>
|
Chris@16
|
199 >
|
Chris@16
|
200 {};
|
Chris@16
|
201
|
Chris@16
|
202
|
Chris@16
|
203 template <typename Box1, typename Box2, std::size_t DimensionCount, bool Reverse>
|
Chris@16
|
204 struct equals<Box1, Box2, box_tag, box_tag, DimensionCount, Reverse>
|
Chris@16
|
205 : detail::equals::box_box<0, DimensionCount>
|
Chris@16
|
206 {};
|
Chris@16
|
207
|
Chris@16
|
208
|
Chris@16
|
209 template <typename Ring1, typename Ring2, bool Reverse>
|
Chris@16
|
210 struct equals<Ring1, Ring2, ring_tag, ring_tag, 2, Reverse>
|
Chris@16
|
211 : detail::equals::equals_by_collection<detail::equals::area_check>
|
Chris@16
|
212 {};
|
Chris@16
|
213
|
Chris@16
|
214
|
Chris@16
|
215 template <typename Polygon1, typename Polygon2, bool Reverse>
|
Chris@16
|
216 struct equals<Polygon1, Polygon2, polygon_tag, polygon_tag, 2, Reverse>
|
Chris@16
|
217 : detail::equals::equals_by_collection<detail::equals::area_check>
|
Chris@16
|
218 {};
|
Chris@16
|
219
|
Chris@16
|
220
|
Chris@16
|
221 template <typename LineString1, typename LineString2, bool Reverse>
|
Chris@16
|
222 struct equals<LineString1, LineString2, linestring_tag, linestring_tag, 2, Reverse>
|
Chris@16
|
223 : detail::equals::equals_by_collection<detail::equals::length_check>
|
Chris@16
|
224 {};
|
Chris@16
|
225
|
Chris@16
|
226
|
Chris@16
|
227 template <typename Polygon, typename Ring, bool Reverse>
|
Chris@16
|
228 struct equals<Polygon, Ring, polygon_tag, ring_tag, 2, Reverse>
|
Chris@16
|
229 : detail::equals::equals_by_collection<detail::equals::area_check>
|
Chris@16
|
230 {};
|
Chris@16
|
231
|
Chris@16
|
232
|
Chris@16
|
233 template <typename Ring, typename Box, bool Reverse>
|
Chris@16
|
234 struct equals<Ring, Box, ring_tag, box_tag, 2, Reverse>
|
Chris@16
|
235 : detail::equals::equals_by_collection<detail::equals::area_check>
|
Chris@16
|
236 {};
|
Chris@16
|
237
|
Chris@16
|
238
|
Chris@16
|
239 template <typename Polygon, typename Box, bool Reverse>
|
Chris@16
|
240 struct equals<Polygon, Box, polygon_tag, box_tag, 2, Reverse>
|
Chris@16
|
241 : detail::equals::equals_by_collection<detail::equals::area_check>
|
Chris@16
|
242 {};
|
Chris@16
|
243
|
Chris@16
|
244
|
Chris@16
|
245 template <typename Geometry1, typename Geometry2>
|
Chris@16
|
246 struct devarianted_equals
|
Chris@16
|
247 {
|
Chris@16
|
248 static inline bool apply(Geometry1 const& geometry1,
|
Chris@16
|
249 Geometry2 const& geometry2)
|
Chris@16
|
250 {
|
Chris@16
|
251 concept::check_concepts_and_equal_dimensions
|
Chris@16
|
252 <
|
Chris@16
|
253 Geometry1 const,
|
Chris@16
|
254 Geometry2 const
|
Chris@16
|
255 >();
|
Chris@16
|
256 return equals<Geometry1, Geometry2>::apply(geometry1, geometry2);
|
Chris@16
|
257 }
|
Chris@16
|
258 };
|
Chris@16
|
259
|
Chris@16
|
260 template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
|
Chris@16
|
261 struct devarianted_equals<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
|
Chris@16
|
262 {
|
Chris@16
|
263 struct visitor: static_visitor<bool>
|
Chris@16
|
264 {
|
Chris@16
|
265 Geometry2 const& m_geometry2;
|
Chris@16
|
266
|
Chris@16
|
267 visitor(Geometry2 const& geometry2)
|
Chris@16
|
268 : m_geometry2(geometry2)
|
Chris@16
|
269 {}
|
Chris@16
|
270
|
Chris@16
|
271 template <typename Geometry1>
|
Chris@16
|
272 inline bool operator()(Geometry1 const& geometry1) const
|
Chris@16
|
273 {
|
Chris@16
|
274 return devarianted_equals<Geometry1, Geometry2>
|
Chris@16
|
275 ::apply(geometry1, m_geometry2);
|
Chris@16
|
276 }
|
Chris@16
|
277
|
Chris@16
|
278 };
|
Chris@16
|
279
|
Chris@16
|
280 static inline bool apply(
|
Chris@16
|
281 boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
|
Chris@16
|
282 Geometry2 const& geometry2
|
Chris@16
|
283 )
|
Chris@16
|
284 {
|
Chris@16
|
285 return apply_visitor(visitor(geometry2), geometry1);
|
Chris@16
|
286 }
|
Chris@16
|
287 };
|
Chris@16
|
288
|
Chris@16
|
289 template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
|
Chris@16
|
290 struct devarianted_equals<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
|
Chris@16
|
291 {
|
Chris@16
|
292 struct visitor: static_visitor<bool>
|
Chris@16
|
293 {
|
Chris@16
|
294 Geometry1 const& m_geometry1;
|
Chris@16
|
295
|
Chris@16
|
296 visitor(Geometry1 const& geometry1)
|
Chris@16
|
297 : m_geometry1(geometry1)
|
Chris@16
|
298 {}
|
Chris@16
|
299
|
Chris@16
|
300 template <typename Geometry2>
|
Chris@16
|
301 inline bool operator()(Geometry2 const& geometry2) const
|
Chris@16
|
302 {
|
Chris@16
|
303 return devarianted_equals<Geometry1, Geometry2>
|
Chris@16
|
304 ::apply(m_geometry1, geometry2);
|
Chris@16
|
305 }
|
Chris@16
|
306
|
Chris@16
|
307 };
|
Chris@16
|
308
|
Chris@16
|
309 static inline bool apply(
|
Chris@16
|
310 Geometry1 const& geometry1,
|
Chris@16
|
311 boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2
|
Chris@16
|
312 )
|
Chris@16
|
313 {
|
Chris@16
|
314 return apply_visitor(visitor(geometry1), geometry2);
|
Chris@16
|
315 }
|
Chris@16
|
316 };
|
Chris@16
|
317
|
Chris@16
|
318 template <
|
Chris@16
|
319 BOOST_VARIANT_ENUM_PARAMS(typename T1),
|
Chris@16
|
320 BOOST_VARIANT_ENUM_PARAMS(typename T2)
|
Chris@16
|
321 >
|
Chris@16
|
322 struct devarianted_equals<
|
Chris@16
|
323 boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>,
|
Chris@16
|
324 boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>
|
Chris@16
|
325 >
|
Chris@16
|
326 {
|
Chris@16
|
327 struct visitor: static_visitor<bool>
|
Chris@16
|
328 {
|
Chris@16
|
329 template <typename Geometry1, typename Geometry2>
|
Chris@16
|
330 inline bool operator()(Geometry1 const& geometry1,
|
Chris@16
|
331 Geometry2 const& geometry2) const
|
Chris@16
|
332 {
|
Chris@16
|
333 return devarianted_equals<Geometry1, Geometry2>
|
Chris@16
|
334 ::apply(geometry1, geometry2);
|
Chris@16
|
335 }
|
Chris@16
|
336
|
Chris@16
|
337 };
|
Chris@16
|
338
|
Chris@16
|
339 static inline bool apply(
|
Chris@16
|
340 boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1,
|
Chris@16
|
341 boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2
|
Chris@16
|
342 )
|
Chris@16
|
343 {
|
Chris@16
|
344 return apply_visitor(visitor(), geometry1, geometry2);
|
Chris@16
|
345 }
|
Chris@16
|
346 };
|
Chris@16
|
347
|
Chris@16
|
348
|
Chris@16
|
349 } // namespace dispatch
|
Chris@16
|
350 #endif // DOXYGEN_NO_DISPATCH
|
Chris@16
|
351
|
Chris@16
|
352
|
Chris@16
|
353 /*!
|
Chris@16
|
354 \brief \brief_check{are spatially equal}
|
Chris@16
|
355 \details \details_check12{equals, is spatially equal}. Spatially equal means
|
Chris@16
|
356 that the same point set is included. A box can therefore be spatially equal
|
Chris@16
|
357 to a ring or a polygon, or a linestring can be spatially equal to a
|
Chris@16
|
358 multi-linestring or a segment. This only works theoretically, not all
|
Chris@16
|
359 combinations are implemented yet.
|
Chris@16
|
360 \ingroup equals
|
Chris@16
|
361 \tparam Geometry1 \tparam_geometry
|
Chris@16
|
362 \tparam Geometry2 \tparam_geometry
|
Chris@16
|
363 \param geometry1 \param_geometry
|
Chris@16
|
364 \param geometry2 \param_geometry
|
Chris@16
|
365 \return \return_check2{are spatially equal}
|
Chris@16
|
366
|
Chris@16
|
367 \qbk{[include reference/algorithms/equals.qbk]}
|
Chris@16
|
368
|
Chris@16
|
369 */
|
Chris@16
|
370 template <typename Geometry1, typename Geometry2>
|
Chris@16
|
371 inline bool equals(Geometry1 const& geometry1, Geometry2 const& geometry2)
|
Chris@16
|
372 {
|
Chris@16
|
373 return dispatch::devarianted_equals<Geometry1, Geometry2>
|
Chris@16
|
374 ::apply(geometry1, geometry2);
|
Chris@16
|
375 }
|
Chris@16
|
376
|
Chris@16
|
377
|
Chris@16
|
378 }} // namespace boost::geometry
|
Chris@16
|
379
|
Chris@16
|
380
|
Chris@16
|
381 #endif // BOOST_GEOMETRY_ALGORITHMS_EQUALS_HPP
|
Chris@16
|
382
|