1 // Boost.Geometry
2
3 // Copyright (c) 2019-2020, Oracle and/or its affiliates.
4 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
5
6 // Licensed under the Boost Software License version 1.0.
7 // http://www.boost.org/users/license.html
8
9 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_TUPLED_OUTPUT_HPP
10 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_TUPLED_OUTPUT_HPP
11
12 #include <boost/geometry/algorithms/convert.hpp>
13 #include <boost/geometry/core/config.hpp>
14 #include <boost/geometry/core/tag.hpp>
15 #include <boost/geometry/core/tag_cast.hpp>
16 #include <boost/geometry/core/tags.hpp>
17 #include <boost/geometry/geometries/concepts/check.hpp>
18 #include <boost/geometry/util/range.hpp>
19 #include <boost/geometry/util/tuples.hpp>
20
21 #include <boost/mpl/and.hpp>
22 #include <boost/mpl/if.hpp>
23 #include <boost/range/value_type.hpp>
24 #include <boost/type_traits/detail/yes_no_type.hpp>
25 #include <boost/type_traits/integral_constant.hpp>
26 #include <boost/type_traits/is_base_of.hpp>
27 #include <boost/type_traits/is_same.hpp>
28 #include <boost/type_traits/is_void.hpp>
29
30 namespace boost { namespace geometry
31 {
32
33
34 #ifndef DOXYGEN_NO_DETAIL
35 namespace detail
36 {
37
38 // true for any geometry
39 template <typename T>
40 struct is_geometry
41 : boost::integral_constant
42 <
43 bool,
44 (! boost::is_void<typename geometry::tag<T>::type>::value)
45 >
46 {};
47
48 // true for multi-point, multi-linestring or multi-polygon
49 template <typename Geometry>
50 struct is_multi_geometry
51 : boost::is_base_of
52 <
53 geometry::multi_tag,
54 typename geometry::tag<Geometry>::type
55 >
56 {};
57
58 // true for point, linestring or polygon
59 template <typename T>
60 struct is_multi_geometry_element
61 : boost::integral_constant
62 <
63 bool,
64 ((boost::is_same<typename geometry::tag<T>::type, point_tag>::value)
65 || (boost::is_same<typename geometry::tag<T>::type, linestring_tag>::value)
66 || (boost::is_same<typename geometry::tag<T>::type, polygon_tag>::value))
67 >
68 {};
69
70
71 template <typename T>
72 struct is_range_impl
73 {
74 typedef boost::type_traits::yes_type yes_type;
75 typedef boost::type_traits::no_type no_type;
76
77 template <typename U>
78 static yes_type test(typename boost::range_iterator<U>::type*);
79
80 template <typename U>
81 static no_type test(...);
82
83 static const bool value = (sizeof(test<T>(0)) == sizeof(yes_type));
84 };
85
86 // true if T is range (boost::range_iterator<T>::type is defined)
87 template <typename T>
88 struct is_range
89 : boost::integral_constant<bool, is_range_impl<T>::value>
90 {};
91
92
93 template <typename T, bool IsRange = is_range<T>::value>
94 struct is_tupled_output_element_base
95 : boost::integral_constant<bool, false>
96 {};
97
98 template <typename T>
99 struct is_tupled_output_element_base<T, true>
100 : boost::integral_constant
101 <
102 bool,
103 (is_multi_geometry<T>::value
104 ||
105 ((! is_geometry<T>::value)
106 &&
107 is_multi_geometry_element
108 <
109 typename boost::range_value<T>::type
110 >::value))
111 >
112 {};
113
114 // true if T is a multi-geometry or is a range of points, linestrings or
115 // polygons
116 template <typename T>
117 struct is_tupled_output_element
118 : is_tupled_output_element_base<T>
119 {};
120
121
122
123 // true if Output is not a geometry (so e.g. tuple was not adapted to any
124 // concept) and at least one of the tuple elements is a multi-geometry or
125 // a range of points, linestrings or polygons
126 template <typename Output>
127 struct is_tupled_output_check
128 : boost::mpl::and_
129 <
130 boost::is_same<typename geometry::tag<Output>::type, void>,
131 //geometry::tuples::exists_if<Output, is_multi_geometry>
132 geometry::tuples::exists_if<Output, is_tupled_output_element>
133 >
134 {};
135
136
137 // true if T is not a geometry (so e.g. tuple was not adapted to any
138 // concept) and at least one of the tuple elements is a point, linesting
139 // or polygon
140 template <typename T>
141 struct is_tupled_single_output_check
142 : boost::mpl::and_
143 <
144 boost::is_same<typename geometry::tag<T>::type, void>,
145 geometry::tuples::exists_if<T, is_multi_geometry_element>
146 >
147 {};
148
149
150 // true if Output is boost::tuple, boost::tuples::cons, std::pair or std::tuple
151 template <typename T>
152 struct is_tupled
153 : boost::integral_constant<bool, false>
154 {};
155
156 template
157 <
158 class T0, class T1, class T2, class T3, class T4,
159 class T5, class T6, class T7, class T8, class T9
160 >
161 struct is_tupled<boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> >
162 : boost::integral_constant<bool, true>
163 {};
164
165 template <typename HT, typename TT>
166 struct is_tupled<boost::tuples::cons<HT, TT> >
167 : boost::integral_constant<bool, true>
168 {};
169
170 template <typename F, typename S>
171 struct is_tupled<std::pair<F, S> >
172 : boost::integral_constant<bool, true>
173 {};
174
175 #ifdef BOOST_GEOMETRY_CXX11_TUPLE
176
177 template <typename ...Ts>
178 struct is_tupled<std::tuple<Ts...> >
179 : boost::integral_constant<bool, true>
180 {};
181
182 #endif // BOOST_GEOMETRY_CXX11_TUPLE
183
184
185
186 // true if Output is boost::tuple, boost::tuples::cons, std::pair or std::tuple
187 // and is_tupled_output_check defiend above passes
188 template <typename Output, bool IsTupled = is_tupled<Output>::value>
189 struct is_tupled_output
190 : boost::integral_constant<bool, false>
191 {};
192
193 template <typename Output>
194 struct is_tupled_output<Output, true>
195 : is_tupled_output_check<Output>
196 {};
197
198
199 // true if T is boost::tuple, boost::tuples::cons, std::pair or std::tuple
200 // and is_tupled_single_output_check defiend above passes
201 template <typename T, bool IsTupled = is_tupled<T>::value>
202 struct is_tupled_single_output
203 : boost::integral_constant<bool, false>
204 {};
205
206 template <typename T>
207 struct is_tupled_single_output<T, true>
208 : is_tupled_single_output_check<T>
209 {};
210
211
212 template <typename Tag>
213 struct tupled_output_find_index_pred
214 {
215 template <typename T>
216 struct pred
217 : boost::is_same<typename geometry::tag<T>::type, Tag>
218 {};
219 };
220
221 // Valid only if tupled_output_has<Output, Tag> is true
222 template <typename Output, typename Tag>
223 struct tupled_output_find_index
224 : geometry::tuples::find_index_if
225 <
226 Output,
227 tupled_output_find_index_pred<Tag>::template pred
228 >
229 {};
230
231
232 template
233 <
234 typename Output,
235 typename Tag,
236 bool IsTupledOutput = is_tupled_output<Output>::value
237 >
238 struct tupled_output_has
239 : boost::integral_constant<bool, false>
240 {};
241
242 template <typename Output, typename Tag>
243 struct tupled_output_has<Output, Tag, true>
244 : boost::integral_constant
245 <
246 bool,
247 ((tupled_output_find_index<Output, Tag>::value)
248 < (geometry::tuples::size<Output>::value))
249 >
250 {};
251
252
253 // Valid only if tupled_output_has<Output, Tag> is true
254 template <typename Tag, typename Output>
255 inline typename geometry::tuples::element
256 <
257 tupled_output_find_index<Output, Tag>::value,
258 Output
259 >::type &
tupled_output_get(Output & output)260 tupled_output_get(Output & output)
261 {
262 return geometry::tuples::get<tupled_output_find_index<Output, Tag>::value>(output);
263 }
264
265
266 // defines a tuple-type holding value-types of ranges being elements of
267 // Output pair/tuple
268
269 template
270 <
271 typename Tuple,
272 size_t I = 0,
273 size_t N = geometry::tuples::size<Tuple>::value
274 >
275 struct tupled_range_values_bt
276 {
277 typedef boost::tuples::cons
278 <
279 typename boost::range_value
280 <
281 typename geometry::tuples::element<I, Tuple>::type
282 >::type,
283 typename tupled_range_values_bt<Tuple, I+1, N>::type
284 > type;
285 };
286
287 template <typename Tuple, size_t N>
288 struct tupled_range_values_bt<Tuple, N, N>
289 {
290 typedef boost::tuples::null_type type;
291 };
292
293 template <typename Output>
294 struct tupled_range_values
295 : tupled_range_values_bt<Output>
296 {};
297
298 template <typename F, typename S>
299 struct tupled_range_values<std::pair<F, S> >
300 {
301 typedef std::pair
302 <
303 typename boost::range_value<F>::type,
304 typename boost::range_value<S>::type
305 > type;
306 };
307
308 #ifdef BOOST_GEOMETRY_CXX11_TUPLE
309
310 template <typename ...Ts>
311 struct tupled_range_values<std::tuple<Ts...> >
312 {
313 typedef std::tuple<typename boost::range_value<Ts>::type...> type;
314 };
315
316 #endif // BOOST_GEOMETRY_CXX11_TUPLE
317
318
319 // util defining a type and creating a tuple holding back-insert-iterators to
320 // ranges being elements of Output pair/tuple
321
322 template <typename Tuple,
323 size_t I = 0,
324 size_t N = geometry::tuples::size<Tuple>::value>
325 struct tupled_back_inserters_bt
326 {
327 typedef boost::tuples::cons
328 <
329 geometry::range::back_insert_iterator
330 <
331 typename geometry::tuples::element<I, Tuple>::type
332 >,
333 typename tupled_back_inserters_bt<Tuple, I+1, N>::type
334 > type;
335
applyboost::geometry::detail::tupled_back_inserters_bt336 static type apply(Tuple & tup)
337 {
338 return type(geometry::range::back_inserter(geometry::tuples::get<I>(tup)),
339 tupled_back_inserters_bt<Tuple, I+1, N>::apply(tup));
340 }
341 };
342
343 template <typename Tuple, size_t N>
344 struct tupled_back_inserters_bt<Tuple, N, N>
345 {
346 typedef boost::tuples::null_type type;
347
applyboost::geometry::detail::tupled_back_inserters_bt348 static type apply(Tuple const&)
349 {
350 return type();
351 }
352 };
353
354 template <typename Tuple>
355 struct tupled_back_inserters
356 : tupled_back_inserters_bt<Tuple>
357 {};
358
359 template <typename F, typename S>
360 struct tupled_back_inserters<std::pair<F, S> >
361 {
362 typedef std::pair
363 <
364 geometry::range::back_insert_iterator<F>,
365 geometry::range::back_insert_iterator<S>
366 > type;
367
applyboost::geometry::detail::tupled_back_inserters368 static type apply(std::pair<F, S> & p)
369 {
370 return type(geometry::range::back_inserter(p.first),
371 geometry::range::back_inserter(p.second));
372 }
373 };
374
375 #ifdef BOOST_GEOMETRY_CXX11_TUPLE
376
377 // NOTE: In C++14 std::integer_sequence and std::make_integer_sequence could be used
378
379 template <typename Is, typename Tuple>
380 struct tupled_back_inserters_st;
381
382 template <int ...Is, typename ...Ts>
383 struct tupled_back_inserters_st<geometry::tuples::int_sequence<Is...>, std::tuple<Ts...> >
384 {
385 typedef std::tuple<geometry::range::back_insert_iterator<Ts>...> type;
386
applyboost::geometry::detail::tupled_back_inserters_st387 static type apply(std::tuple<Ts...> & tup)
388 {
389 return type(geometry::range::back_inserter(std::get<Is>(tup))...);
390 }
391 };
392
393 template <typename ...Ts>
394 struct tupled_back_inserters<std::tuple<Ts...> >
395 : tupled_back_inserters_st
396 <
397 typename geometry::tuples::make_int_sequence<sizeof...(Ts)>::type,
398 std::tuple<Ts...>
399 >
400 {};
401
402 #endif // BOOST_GEOMETRY_CXX11_TUPLE
403
404
405 template
406 <
407 typename GeometryOut,
408 bool IsTupled = is_tupled_output<GeometryOut>::value
409 >
410 struct output_geometry_value
411 : boost::range_value<GeometryOut>
412 {};
413
414 template <typename GeometryOut>
415 struct output_geometry_value<GeometryOut, true>
416 : tupled_range_values<GeometryOut>
417 {};
418
419
420 template
421 <
422 typename GeometryOut,
423 bool IsTupled = is_tupled_output<GeometryOut>::value
424 >
425 struct output_geometry_back_inserter_
426 {
427 typedef geometry::range::back_insert_iterator<GeometryOut> type;
428
applyboost::geometry::detail::output_geometry_back_inserter_429 static type apply(GeometryOut & out)
430 {
431 return geometry::range::back_inserter(out);
432 }
433 };
434
435 template <typename GeometryOut>
436 struct output_geometry_back_inserter_<GeometryOut, true>
437 : tupled_back_inserters<GeometryOut>
438 {};
439
440 template <typename GeometryOut>
441 inline typename output_geometry_back_inserter_<GeometryOut>::type
output_geometry_back_inserter(GeometryOut & out)442 output_geometry_back_inserter(GeometryOut & out)
443 {
444 return output_geometry_back_inserter_<GeometryOut>::apply(out);
445 }
446
447
448 // is_tag_same_as_pred
449 // Defines a predicate true if type's tag is the same as Tag
450 template <typename Tag>
451 struct is_tag_same_as_pred
452 {
453 template <typename T>
454 struct pred
455 : boost::is_same<typename geometry::tag<T>::type, Tag>
456 {};
457 };
458
459
460 // Allows to access a type/object in a pair/tuple corresponding to an index in
461 // GeometryOut pair/tuple of a geometry defined by Tag.
462 // If GeometryOut is a geometry then it's expected to be defined by DefaultTag.
463 template
464 <
465 typename GeometryOut,
466 typename Tag,
467 typename DefaultTag,
468 typename GeometryTag = typename geometry::tag<GeometryOut>::type
469 >
470 struct output_geometry_access
471 {};
472
473 // assume GeometryTag is void because not adapted tuple holding geometries was passed
474 template <typename TupledOut, typename Tag, typename DefaultTag>
475 struct output_geometry_access<TupledOut, Tag, DefaultTag, void>
476 {
477 static const int index = geometry::tuples::find_index_if
478 <
479 TupledOut, is_tag_same_as_pred<Tag>::template pred
480 >::value;
481
482 typedef typename geometry::tuples::element<index, TupledOut>::type type;
483
484 template <typename Tuple>
485 static typename geometry::tuples::element<index, Tuple>::type&
getboost::geometry::detail::output_geometry_access486 get(Tuple & tup)
487 {
488 return geometry::tuples::get<index>(tup);
489 }
490 };
491
492 template <typename GeometryOut, typename Tag, typename DefaultTag>
493 struct output_geometry_access<GeometryOut, Tag, DefaultTag, DefaultTag>
494 {
495 typedef GeometryOut type;
496
497 template <typename T>
getboost::geometry::detail::output_geometry_access498 static T& get(T & v)
499 {
500 return v;
501 }
502 };
503
504
505 template <typename Geometry>
506 struct output_geometry_concept_check
507 {
applyboost::geometry::detail::output_geometry_concept_check508 static void apply()
509 {
510 concepts::check<Geometry>();
511 }
512 };
513
514 template <typename First, typename Second>
515 struct output_geometry_concept_check<std::pair<First, Second> >
516 {
applyboost::geometry::detail::output_geometry_concept_check517 static void apply()
518 {
519 concepts::check<First>();
520 concepts::check<Second>();
521 }
522 };
523
524 template <typename Tuple,
525 size_t I = 0,
526 size_t N = geometry::tuples::size<Tuple>::value>
527 struct output_geometry_concept_check_t
528 {
applyboost::geometry::detail::output_geometry_concept_check_t529 static void apply()
530 {
531 concepts::check<typename geometry::tuples::element<I, Tuple>::type>();
532 output_geometry_concept_check_t<Tuple, I + 1, N>::apply();
533 }
534 };
535
536 template <typename Tuple, size_t N>
537 struct output_geometry_concept_check_t<Tuple, N, N>
538 {
applyboost::geometry::detail::output_geometry_concept_check_t539 static void apply()
540 {}
541 };
542
543 template
544 <
545 class T0, class T1, class T2, class T3, class T4,
546 class T5, class T6, class T7, class T8, class T9
547 >
548 struct output_geometry_concept_check<boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> >
549 : output_geometry_concept_check_t<boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> >
550 {};
551
552 template <typename HT, typename TT>
553 struct output_geometry_concept_check<boost::tuples::cons<HT, TT> >
554 : output_geometry_concept_check_t<boost::tuples::cons<HT, TT> >
555 {};
556
557 #ifdef BOOST_GEOMETRY_CXX11_TUPLE
558
559 template <typename ...Ts>
560 struct output_geometry_concept_check<std::tuple<Ts...> >
561 : output_geometry_concept_check_t<std::tuple<Ts...> >
562 {};
563
564 #endif // BOOST_GEOMETRY_CXX11_TUPLE
565
566
567 struct tupled_output_tag {};
568
569
570 template <typename GeometryOut>
571 struct setop_insert_output_tag
572 : boost::mpl::if_c
573 <
574 geometry::detail::is_tupled_single_output<GeometryOut>::value,
575 tupled_output_tag,
576 typename geometry::tag<GeometryOut>::type
577 >
578 {};
579
580
581 template <typename Geometry1, typename Geometry2, typename TupledOut, bool IsFound, typename Tag>
582 struct expect_output_assert_base;
583
584 template <typename Geometry1, typename Geometry2, typename TupledOut, bool IsFound>
585 struct expect_output_assert_base<Geometry1, Geometry2, TupledOut, IsFound, pointlike_tag>
586 {
587 BOOST_MPL_ASSERT_MSG
588 (
589 IsFound, POINTLIKE_GEOMETRY_EXPECTED_IN_TUPLED_OUTPUT,
590 (types<Geometry1, Geometry2, TupledOut>)
591 );
592 };
593
594 template <typename Geometry1, typename Geometry2, typename TupledOut, bool IsFound>
595 struct expect_output_assert_base<Geometry1, Geometry2, TupledOut, IsFound, linear_tag>
596 {
597 BOOST_MPL_ASSERT_MSG
598 (
599 IsFound, LINEAR_GEOMETRY_EXPECTED_IN_TUPLED_OUTPUT,
600 (types<Geometry1, Geometry2, TupledOut>)
601 );
602 };
603
604 template <typename Geometry1, typename Geometry2, typename TupledOut, bool IsFound>
605 struct expect_output_assert_base<Geometry1, Geometry2, TupledOut, IsFound, areal_tag>
606 {
607 BOOST_MPL_ASSERT_MSG
608 (
609 IsFound, AREAL_GEOMETRY_EXPECTED_IN_TUPLED_OUTPUT,
610 (types<Geometry1, Geometry2, TupledOut>)
611 );
612 };
613
614
615 template <typename Geometry1, typename Geometry2, typename TupledOut, typename Tag>
616 struct expect_output_assert
617 : expect_output_assert_base
618 <
619 Geometry1, Geometry2, TupledOut,
620 geometry::tuples::exists_if
621 <
622 TupledOut,
623 is_tag_same_as_pred<Tag>::template pred
624 >::value,
625 typename geometry::tag_cast
626 <
627 Tag, pointlike_tag, linear_tag, areal_tag
628 >::type
629 >
630 {};
631
632 template <typename Geometry1, typename Geometry2, typename TupledOut>
633 struct expect_output_assert<Geometry1, Geometry2, TupledOut, void>
634 {};
635
636 template
637 <
638 typename Geometry1, typename Geometry2, typename TupledOut,
639 typename Tag1,
640 typename Tag2 = void,
641 typename Tag3 = void
642 >
643 struct expect_output
644 : expect_output_assert<Geometry1, Geometry2, TupledOut, Tag1>
645 , expect_output_assert<Geometry1, Geometry2, TupledOut, Tag2>
646 , expect_output_assert<Geometry1, Geometry2, TupledOut, Tag3>
647 {};
648
649 template
650 <
651 typename Geometry1, typename Geometry2, typename TupledOut,
652 typename Tag1, typename Tag2
653 >
654 struct expect_output<Geometry1, Geometry2, TupledOut, Tag1, Tag2, void>
655 : expect_output_assert<Geometry1, Geometry2, TupledOut, Tag1>
656 , expect_output_assert<Geometry1, Geometry2, TupledOut, Tag2>
657 {};
658
659 template
660 <
661 typename Geometry1, typename Geometry2, typename TupledOut,
662 typename Tag1
663 >
664 struct expect_output<Geometry1, Geometry2, TupledOut, Tag1, void, void>
665 : expect_output_assert<Geometry1, Geometry2, TupledOut, Tag1>
666 {};
667
668
669 template <typename CastedTag>
670 struct single_tag_from_base_tag;
671
672 template <>
673 struct single_tag_from_base_tag<pointlike_tag>
674 {
675 typedef point_tag type;
676 };
677
678 template <>
679 struct single_tag_from_base_tag<linear_tag>
680 {
681 typedef linestring_tag type;
682 };
683
684 template <>
685 struct single_tag_from_base_tag<areal_tag>
686 {
687 typedef polygon_tag type;
688 };
689
690
691 template
692 <
693 typename Geometry,
694 typename SingleOut,
695 bool IsMulti = geometry::detail::is_multi_geometry<Geometry>::value
696 >
697 struct convert_to_output
698 {
699 template <typename OutputIterator>
applyboost::geometry::detail::convert_to_output700 static OutputIterator apply(Geometry const& geometry,
701 OutputIterator oit)
702 {
703 SingleOut single_out;
704 geometry::convert(geometry, single_out);
705 *oit++ = single_out;
706 return oit;
707 }
708 };
709
710 template
711 <
712 typename Geometry,
713 typename SingleOut
714 >
715 struct convert_to_output<Geometry, SingleOut, true>
716 {
717 template <typename OutputIterator>
applyboost::geometry::detail::convert_to_output718 static OutputIterator apply(Geometry const& geometry,
719 OutputIterator oit)
720 {
721 typedef typename boost::range_iterator<Geometry const>::type iterator;
722 for (iterator it = boost::begin(geometry); it != boost::end(geometry); ++it)
723 {
724 SingleOut single_out;
725 geometry::convert(*it, single_out);
726 *oit++ = single_out;
727 }
728 return oit;
729 }
730 };
731
732
733 } // namespace detail
734 #endif // DOXYGEN_NO_DETAIL
735
736 }} // namespace boost::geometry
737
738 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_TUPLED_OUTPUT_HPP
739