]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Boost.Geometry (aka GGL, Generic Geometry Library) |
2 | ||
3 | // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. | |
b32b8144 | 4 | // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. |
7c673cae | 5 | |
20effc67 TL |
6 | // This file was modified by Oracle on 2013-2020. |
7 | // Modifications copyright (c) 2013-2020 Oracle and/or its affiliates. | |
7c673cae FG |
8 | |
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_ALGORITHMS_DETAIL_RELATE_RESULT_HPP | |
16 | #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_RESULT_HPP | |
17 | ||
20effc67 | 18 | #include <algorithm> |
7c673cae | 19 | #include <cstddef> |
92f5a8d4 | 20 | #include <cstring> |
20effc67 | 21 | #include <type_traits> |
7c673cae | 22 | |
b32b8144 | 23 | #include <boost/throw_exception.hpp> |
7c673cae | 24 | #include <boost/tuple/tuple.hpp> |
7c673cae FG |
25 | |
26 | #include <boost/geometry/core/assert.hpp> | |
27 | #include <boost/geometry/core/coordinate_dimension.hpp> | |
28 | #include <boost/geometry/core/exception.hpp> | |
20effc67 | 29 | #include <boost/geometry/core/static_assert.hpp> |
7c673cae | 30 | #include <boost/geometry/util/condition.hpp> |
20effc67 | 31 | #include <boost/geometry/util/sequence.hpp> |
7c673cae FG |
32 | |
33 | namespace boost { namespace geometry { | |
34 | ||
35 | #ifndef DOXYGEN_NO_DETAIL | |
36 | namespace detail { namespace relate { | |
37 | ||
38 | enum field { interior = 0, boundary = 1, exterior = 2 }; | |
39 | ||
40 | // TODO: IF THE RESULT IS UPDATED WITH THE MAX POSSIBLE VALUE FOR SOME PAIR OF GEOEMTRIES | |
41 | // THE VALUE ALREADY STORED MUSN'T BE CHECKED | |
42 | // update() calls chould be replaced with set() in those cases | |
43 | // but for safety reasons (STATIC_ASSERT) we should check if parameter D is valid and set() doesn't do that | |
44 | // so some additional function could be added, e.g. set_dim() | |
45 | ||
46 | // --------------- MATRIX ---------------- | |
47 | ||
48 | // matrix | |
49 | ||
50 | template <std::size_t Height, std::size_t Width = Height> | |
51 | class matrix | |
52 | { | |
53 | public: | |
54 | typedef char value_type; | |
55 | typedef std::size_t size_type; | |
56 | typedef const char * const_iterator; | |
57 | typedef const_iterator iterator; | |
58 | ||
59 | static const std::size_t static_width = Width; | |
60 | static const std::size_t static_height = Height; | |
61 | static const std::size_t static_size = Width * Height; | |
62 | ||
63 | inline matrix() | |
64 | { | |
65 | ::memset(m_array, 'F', static_size); | |
66 | } | |
67 | ||
68 | template <field F1, field F2> | |
69 | inline char get() const | |
70 | { | |
71 | BOOST_STATIC_ASSERT(F1 < Height && F2 < Width); | |
72 | static const std::size_t index = F1 * Width + F2; | |
73 | BOOST_STATIC_ASSERT(index < static_size); | |
74 | return m_array[index]; | |
75 | } | |
76 | ||
77 | template <field F1, field F2, char V> | |
78 | inline void set() | |
79 | { | |
80 | BOOST_STATIC_ASSERT(F1 < Height && F2 < Width); | |
81 | static const std::size_t index = F1 * Width + F2; | |
82 | BOOST_STATIC_ASSERT(index < static_size); | |
83 | m_array[index] = V; | |
84 | } | |
85 | ||
86 | inline char operator[](std::size_t index) const | |
87 | { | |
88 | BOOST_GEOMETRY_ASSERT(index < static_size); | |
89 | return m_array[index]; | |
90 | } | |
91 | ||
92 | inline const_iterator begin() const | |
93 | { | |
94 | return m_array; | |
95 | } | |
96 | ||
97 | inline const_iterator end() const | |
98 | { | |
99 | return m_array + static_size; | |
100 | } | |
101 | ||
102 | inline static std::size_t size() | |
103 | { | |
104 | return static_size; | |
105 | } | |
106 | ||
107 | inline const char * data() const | |
108 | { | |
109 | return m_array; | |
110 | } | |
111 | ||
112 | inline std::string str() const | |
113 | { | |
114 | return std::string(m_array, static_size); | |
115 | } | |
116 | ||
117 | private: | |
118 | char m_array[static_size]; | |
119 | }; | |
120 | ||
121 | // matrix_handler | |
122 | ||
123 | template <typename Matrix> | |
124 | class matrix_handler | |
125 | { | |
126 | public: | |
127 | typedef Matrix result_type; | |
128 | ||
129 | static const bool interrupt = false; | |
130 | ||
131 | matrix_handler() | |
132 | {} | |
133 | ||
134 | result_type const& result() const | |
135 | { | |
136 | return m_matrix; | |
137 | } | |
138 | ||
139 | result_type const& matrix() const | |
140 | { | |
141 | return m_matrix; | |
142 | } | |
143 | ||
144 | result_type & matrix() | |
145 | { | |
146 | return m_matrix; | |
147 | } | |
148 | ||
149 | template <field F1, field F2, char D> | |
150 | inline bool may_update() const | |
151 | { | |
152 | BOOST_STATIC_ASSERT('0' <= D && D <= '9'); | |
153 | ||
154 | char const c = m_matrix.template get<F1, F2>(); | |
155 | return D > c || c > '9'; | |
156 | } | |
157 | ||
158 | template <field F1, field F2, char V> | |
159 | inline void set() | |
160 | { | |
161 | static const bool in_bounds = F1 < Matrix::static_height | |
162 | && F2 < Matrix::static_width; | |
20effc67 | 163 | typedef std::integral_constant<bool, in_bounds> in_bounds_t; |
7c673cae FG |
164 | set_dispatch<F1, F2, V>(in_bounds_t()); |
165 | } | |
166 | ||
167 | template <field F1, field F2, char D> | |
168 | inline void update() | |
169 | { | |
170 | static const bool in_bounds = F1 < Matrix::static_height | |
171 | && F2 < Matrix::static_width; | |
20effc67 | 172 | typedef std::integral_constant<bool, in_bounds> in_bounds_t; |
7c673cae FG |
173 | update_dispatch<F1, F2, D>(in_bounds_t()); |
174 | } | |
175 | ||
176 | private: | |
177 | template <field F1, field F2, char V> | |
20effc67 | 178 | inline void set_dispatch(std::true_type) |
7c673cae FG |
179 | { |
180 | static const std::size_t index = F1 * Matrix::static_width + F2; | |
181 | BOOST_STATIC_ASSERT(index < Matrix::static_size); | |
182 | BOOST_STATIC_ASSERT(('0' <= V && V <= '9') || V == 'T' || V == 'F'); | |
183 | m_matrix.template set<F1, F2, V>(); | |
184 | } | |
185 | template <field F1, field F2, char V> | |
20effc67 | 186 | inline void set_dispatch(std::false_type) |
7c673cae FG |
187 | {} |
188 | ||
189 | template <field F1, field F2, char D> | |
20effc67 | 190 | inline void update_dispatch(std::true_type) |
7c673cae FG |
191 | { |
192 | static const std::size_t index = F1 * Matrix::static_width + F2; | |
193 | BOOST_STATIC_ASSERT(index < Matrix::static_size); | |
194 | BOOST_STATIC_ASSERT('0' <= D && D <= '9'); | |
195 | char const c = m_matrix.template get<F1, F2>(); | |
196 | if ( D > c || c > '9') | |
197 | m_matrix.template set<F1, F2, D>(); | |
198 | } | |
199 | template <field F1, field F2, char D> | |
20effc67 | 200 | inline void update_dispatch(std::false_type) |
7c673cae FG |
201 | {} |
202 | ||
203 | Matrix m_matrix; | |
204 | }; | |
205 | ||
206 | // --------------- RUN-TIME MASK ---------------- | |
207 | ||
208 | // run-time mask | |
209 | ||
210 | template <std::size_t Height, std::size_t Width = Height> | |
211 | class mask | |
212 | { | |
213 | public: | |
214 | static const std::size_t static_width = Width; | |
215 | static const std::size_t static_height = Height; | |
216 | static const std::size_t static_size = Width * Height; | |
217 | ||
218 | inline mask(const char * s) | |
219 | { | |
220 | char * it = m_array; | |
221 | char * const last = m_array + static_size; | |
222 | for ( ; it != last && *s != '\0' ; ++it, ++s ) | |
223 | { | |
224 | char c = *s; | |
225 | check_char(c); | |
226 | *it = c; | |
227 | } | |
228 | if ( it != last ) | |
229 | { | |
230 | ::memset(it, '*', last - it); | |
231 | } | |
232 | } | |
233 | ||
234 | inline mask(const char * s, std::size_t count) | |
235 | { | |
236 | if ( count > static_size ) | |
237 | { | |
238 | count = static_size; | |
239 | } | |
240 | if ( count > 0 ) | |
241 | { | |
242 | std::for_each(s, s + count, check_char); | |
243 | ::memcpy(m_array, s, count); | |
244 | } | |
245 | if ( count < static_size ) | |
246 | { | |
247 | ::memset(m_array + count, '*', static_size - count); | |
248 | } | |
249 | } | |
250 | ||
251 | template <field F1, field F2> | |
252 | inline char get() const | |
253 | { | |
254 | BOOST_STATIC_ASSERT(F1 < Height && F2 < Width); | |
255 | static const std::size_t index = F1 * Width + F2; | |
256 | BOOST_STATIC_ASSERT(index < static_size); | |
257 | return m_array[index]; | |
258 | } | |
259 | ||
260 | private: | |
261 | static inline void check_char(char c) | |
262 | { | |
263 | bool const is_valid = c == '*' || c == 'T' || c == 'F' | |
264 | || ( c >= '0' && c <= '9' ); | |
265 | if ( !is_valid ) | |
266 | { | |
b32b8144 | 267 | BOOST_THROW_EXCEPTION(geometry::invalid_input_exception()); |
7c673cae FG |
268 | } |
269 | } | |
270 | ||
271 | char m_array[static_size]; | |
272 | }; | |
273 | ||
274 | // interrupt() | |
275 | ||
276 | template <typename Mask, bool InterruptEnabled> | |
277 | struct interrupt_dispatch | |
278 | { | |
279 | template <field F1, field F2, char V> | |
280 | static inline bool apply(Mask const&) | |
281 | { | |
282 | return false; | |
283 | } | |
284 | }; | |
285 | ||
286 | template <typename Mask> | |
287 | struct interrupt_dispatch<Mask, true> | |
288 | { | |
289 | template <field F1, field F2, char V> | |
290 | static inline bool apply(Mask const& mask) | |
291 | { | |
292 | char m = mask.template get<F1, F2>(); | |
293 | return check_element<V>(m); | |
294 | } | |
295 | ||
296 | template <char V> | |
297 | static inline bool check_element(char m) | |
298 | { | |
299 | if ( BOOST_GEOMETRY_CONDITION(V >= '0' && V <= '9') ) | |
300 | { | |
301 | return m == 'F' || ( m < V && m >= '0' && m <= '9' ); | |
302 | } | |
303 | else if ( BOOST_GEOMETRY_CONDITION(V == 'T') ) | |
304 | { | |
305 | return m == 'F'; | |
306 | } | |
307 | return false; | |
308 | } | |
309 | }; | |
310 | ||
20effc67 | 311 | template <typename Masks, int I = 0, int N = std::tuple_size<Masks>::value> |
7c673cae FG |
312 | struct interrupt_dispatch_tuple |
313 | { | |
314 | template <field F1, field F2, char V> | |
315 | static inline bool apply(Masks const& masks) | |
316 | { | |
20effc67 TL |
317 | typedef typename std::tuple_element<I, Masks>::type mask_type; |
318 | mask_type const& mask = std::get<I>(masks); | |
7c673cae FG |
319 | return interrupt_dispatch<mask_type, true>::template apply<F1, F2, V>(mask) |
320 | && interrupt_dispatch_tuple<Masks, I+1>::template apply<F1, F2, V>(masks); | |
321 | } | |
322 | }; | |
323 | ||
324 | template <typename Masks, int N> | |
325 | struct interrupt_dispatch_tuple<Masks, N, N> | |
326 | { | |
327 | template <field F1, field F2, char V> | |
328 | static inline bool apply(Masks const& ) | |
329 | { | |
330 | return true; | |
331 | } | |
332 | }; | |
333 | ||
20effc67 TL |
334 | template <typename ...Masks> |
335 | struct interrupt_dispatch<std::tuple<Masks...>, true> | |
7c673cae | 336 | { |
20effc67 | 337 | typedef std::tuple<Masks...> mask_type; |
7c673cae FG |
338 | |
339 | template <field F1, field F2, char V> | |
340 | static inline bool apply(mask_type const& mask) | |
341 | { | |
342 | return interrupt_dispatch_tuple<mask_type>::template apply<F1, F2, V>(mask); | |
343 | } | |
344 | }; | |
345 | ||
346 | template <field F1, field F2, char V, bool InterruptEnabled, typename Mask> | |
347 | inline bool interrupt(Mask const& mask) | |
348 | { | |
349 | return interrupt_dispatch<Mask, InterruptEnabled> | |
350 | ::template apply<F1, F2, V>(mask); | |
351 | } | |
352 | ||
353 | // may_update() | |
354 | ||
355 | template <typename Mask> | |
356 | struct may_update_dispatch | |
357 | { | |
358 | template <field F1, field F2, char D, typename Matrix> | |
359 | static inline bool apply(Mask const& mask, Matrix const& matrix) | |
360 | { | |
361 | BOOST_STATIC_ASSERT('0' <= D && D <= '9'); | |
362 | ||
363 | char const m = mask.template get<F1, F2>(); | |
364 | ||
365 | if ( m == 'F' ) | |
366 | { | |
367 | return true; | |
368 | } | |
369 | else if ( m == 'T' ) | |
370 | { | |
371 | char const c = matrix.template get<F1, F2>(); | |
372 | return c == 'F'; // if it's T or between 0 and 9, the result will be the same | |
373 | } | |
374 | else if ( m >= '0' && m <= '9' ) | |
375 | { | |
376 | char const c = matrix.template get<F1, F2>(); | |
377 | return D > c || c > '9'; | |
378 | } | |
379 | ||
380 | return false; | |
381 | } | |
382 | }; | |
383 | ||
20effc67 | 384 | template <typename Masks, int I = 0, int N = std::tuple_size<Masks>::value> |
7c673cae FG |
385 | struct may_update_dispatch_tuple |
386 | { | |
387 | template <field F1, field F2, char D, typename Matrix> | |
388 | static inline bool apply(Masks const& masks, Matrix const& matrix) | |
389 | { | |
20effc67 TL |
390 | typedef typename std::tuple_element<I, Masks>::type mask_type; |
391 | mask_type const& mask = std::get<I>(masks); | |
7c673cae FG |
392 | return may_update_dispatch<mask_type>::template apply<F1, F2, D>(mask, matrix) |
393 | || may_update_dispatch_tuple<Masks, I+1>::template apply<F1, F2, D>(masks, matrix); | |
394 | } | |
395 | }; | |
396 | ||
397 | template <typename Masks, int N> | |
398 | struct may_update_dispatch_tuple<Masks, N, N> | |
399 | { | |
400 | template <field F1, field F2, char D, typename Matrix> | |
401 | static inline bool apply(Masks const& , Matrix const& ) | |
402 | { | |
403 | return false; | |
404 | } | |
405 | }; | |
406 | ||
20effc67 TL |
407 | template <typename ...Masks> |
408 | struct may_update_dispatch<std::tuple<Masks...>> | |
7c673cae | 409 | { |
20effc67 | 410 | typedef std::tuple<Masks...> mask_type; |
7c673cae FG |
411 | |
412 | template <field F1, field F2, char D, typename Matrix> | |
413 | static inline bool apply(mask_type const& mask, Matrix const& matrix) | |
414 | { | |
415 | return may_update_dispatch_tuple<mask_type>::template apply<F1, F2, D>(mask, matrix); | |
416 | } | |
417 | }; | |
418 | ||
419 | template <field F1, field F2, char D, typename Mask, typename Matrix> | |
420 | inline bool may_update(Mask const& mask, Matrix const& matrix) | |
421 | { | |
422 | return may_update_dispatch<Mask> | |
423 | ::template apply<F1, F2, D>(mask, matrix); | |
424 | } | |
425 | ||
426 | // check_matrix() | |
427 | ||
428 | template <typename Mask> | |
429 | struct check_dispatch | |
430 | { | |
431 | template <typename Matrix> | |
432 | static inline bool apply(Mask const& mask, Matrix const& matrix) | |
433 | { | |
434 | return per_one<interior, interior>(mask, matrix) | |
435 | && per_one<interior, boundary>(mask, matrix) | |
436 | && per_one<interior, exterior>(mask, matrix) | |
437 | && per_one<boundary, interior>(mask, matrix) | |
438 | && per_one<boundary, boundary>(mask, matrix) | |
439 | && per_one<boundary, exterior>(mask, matrix) | |
440 | && per_one<exterior, interior>(mask, matrix) | |
441 | && per_one<exterior, boundary>(mask, matrix) | |
442 | && per_one<exterior, exterior>(mask, matrix); | |
443 | } | |
444 | ||
445 | template <field F1, field F2, typename Matrix> | |
446 | static inline bool per_one(Mask const& mask, Matrix const& matrix) | |
447 | { | |
448 | const char mask_el = mask.template get<F1, F2>(); | |
449 | const char el = matrix.template get<F1, F2>(); | |
450 | ||
451 | if ( mask_el == 'F' ) | |
452 | { | |
453 | return el == 'F'; | |
454 | } | |
455 | else if ( mask_el == 'T' ) | |
456 | { | |
457 | return el == 'T' || ( el >= '0' && el <= '9' ); | |
458 | } | |
459 | else if ( mask_el >= '0' && mask_el <= '9' ) | |
460 | { | |
461 | return el == mask_el; | |
462 | } | |
463 | ||
464 | return true; | |
465 | } | |
466 | }; | |
467 | ||
20effc67 | 468 | template <typename Masks, int I = 0, int N = std::tuple_size<Masks>::value> |
7c673cae FG |
469 | struct check_dispatch_tuple |
470 | { | |
471 | template <typename Matrix> | |
472 | static inline bool apply(Masks const& masks, Matrix const& matrix) | |
473 | { | |
20effc67 TL |
474 | typedef typename std::tuple_element<I, Masks>::type mask_type; |
475 | mask_type const& mask = std::get<I>(masks); | |
7c673cae FG |
476 | return check_dispatch<mask_type>::apply(mask, matrix) |
477 | || check_dispatch_tuple<Masks, I+1>::apply(masks, matrix); | |
478 | } | |
479 | }; | |
480 | ||
481 | template <typename Masks, int N> | |
482 | struct check_dispatch_tuple<Masks, N, N> | |
483 | { | |
484 | template <typename Matrix> | |
485 | static inline bool apply(Masks const&, Matrix const&) | |
486 | { | |
487 | return false; | |
488 | } | |
489 | }; | |
490 | ||
20effc67 TL |
491 | template <typename ...Masks> |
492 | struct check_dispatch<std::tuple<Masks...>> | |
7c673cae | 493 | { |
20effc67 | 494 | typedef std::tuple<Masks...> mask_type; |
7c673cae FG |
495 | |
496 | template <typename Matrix> | |
497 | static inline bool apply(mask_type const& mask, Matrix const& matrix) | |
498 | { | |
499 | return check_dispatch_tuple<mask_type>::apply(mask, matrix); | |
500 | } | |
501 | }; | |
502 | ||
503 | template <typename Mask, typename Matrix> | |
504 | inline bool check_matrix(Mask const& mask, Matrix const& matrix) | |
505 | { | |
506 | return check_dispatch<Mask>::apply(mask, matrix); | |
507 | } | |
508 | ||
509 | // matrix_width | |
510 | ||
511 | template <typename MatrixOrMask> | |
512 | struct matrix_width | |
513 | { | |
514 | static const std::size_t value = MatrixOrMask::static_width; | |
515 | }; | |
516 | ||
517 | template <typename Tuple, | |
518 | int I = 0, | |
20effc67 | 519 | int N = std::tuple_size<Tuple>::value> |
7c673cae FG |
520 | struct matrix_width_tuple |
521 | { | |
522 | static const std::size_t | |
20effc67 | 523 | current = matrix_width<typename std::tuple_element<I, Tuple>::type>::value; |
7c673cae FG |
524 | static const std::size_t |
525 | next = matrix_width_tuple<Tuple, I+1>::value; | |
526 | ||
527 | static const std::size_t | |
528 | value = current > next ? current : next; | |
529 | }; | |
530 | ||
531 | template <typename Tuple, int N> | |
532 | struct matrix_width_tuple<Tuple, N, N> | |
533 | { | |
534 | static const std::size_t value = 0; | |
535 | }; | |
536 | ||
20effc67 TL |
537 | template <typename ...Masks> |
538 | struct matrix_width<std::tuple<Masks...>> | |
7c673cae FG |
539 | { |
540 | static const std::size_t | |
20effc67 | 541 | value = matrix_width_tuple<std::tuple<Masks...>>::value; |
7c673cae FG |
542 | }; |
543 | ||
544 | // mask_handler | |
545 | ||
546 | template <typename Mask, bool Interrupt> | |
547 | class mask_handler | |
548 | : private matrix_handler | |
549 | < | |
550 | relate::matrix<matrix_width<Mask>::value> | |
551 | > | |
552 | { | |
553 | typedef matrix_handler | |
554 | < | |
555 | relate::matrix<matrix_width<Mask>::value> | |
556 | > base_t; | |
557 | ||
558 | public: | |
559 | typedef bool result_type; | |
560 | ||
561 | bool interrupt; | |
562 | ||
563 | inline explicit mask_handler(Mask const& m) | |
564 | : interrupt(false) | |
565 | , m_mask(m) | |
566 | {} | |
567 | ||
568 | result_type result() const | |
569 | { | |
570 | return !interrupt | |
571 | && check_matrix(m_mask, base_t::matrix()); | |
572 | } | |
573 | ||
574 | template <field F1, field F2, char D> | |
575 | inline bool may_update() const | |
576 | { | |
577 | return detail::relate::may_update<F1, F2, D>( | |
578 | m_mask, base_t::matrix() | |
579 | ); | |
580 | } | |
581 | ||
582 | template <field F1, field F2, char V> | |
583 | inline void set() | |
584 | { | |
585 | if ( relate::interrupt<F1, F2, V, Interrupt>(m_mask) ) | |
586 | { | |
587 | interrupt = true; | |
588 | } | |
589 | else | |
590 | { | |
591 | base_t::template set<F1, F2, V>(); | |
592 | } | |
593 | } | |
594 | ||
595 | template <field F1, field F2, char V> | |
596 | inline void update() | |
597 | { | |
598 | if ( relate::interrupt<F1, F2, V, Interrupt>(m_mask) ) | |
599 | { | |
600 | interrupt = true; | |
601 | } | |
602 | else | |
603 | { | |
604 | base_t::template update<F1, F2, V>(); | |
605 | } | |
606 | } | |
607 | ||
608 | private: | |
609 | Mask const& m_mask; | |
610 | }; | |
611 | ||
92f5a8d4 TL |
612 | // --------------- FALSE MASK ---------------- |
613 | ||
614 | struct false_mask {}; | |
615 | ||
7c673cae FG |
616 | // --------------- COMPILE-TIME MASK ---------------- |
617 | ||
618 | // static_check_characters | |
20effc67 TL |
619 | template <typename Seq> |
620 | struct static_check_characters {}; | |
621 | ||
622 | template <char C, char ...Cs> | |
623 | struct static_check_characters<std::integer_sequence<char, C, Cs...>> | |
624 | : static_check_characters<std::integer_sequence<char, Cs...>> | |
7c673cae | 625 | { |
20effc67 TL |
626 | typedef std::integer_sequence<char, C, Cs...> type; |
627 | static const bool is_valid = (C >= '0' && C <= '9') | |
628 | || C == 'T' || C == 'F' || C == '*'; | |
629 | BOOST_GEOMETRY_STATIC_ASSERT((is_valid), | |
630 | "Invalid static mask character", | |
631 | type); | |
7c673cae FG |
632 | }; |
633 | ||
20effc67 TL |
634 | template <char ...Cs> |
635 | struct static_check_characters<std::integral_constant<char, Cs...>> | |
7c673cae FG |
636 | {}; |
637 | ||
638 | // static_mask | |
639 | ||
20effc67 | 640 | template <typename Seq, std::size_t Height, std::size_t Width = Height> |
7c673cae FG |
641 | struct static_mask |
642 | { | |
643 | static const std::size_t static_width = Width; | |
644 | static const std::size_t static_height = Height; | |
645 | static const std::size_t static_size = Width * Height; | |
646 | ||
647 | BOOST_STATIC_ASSERT( | |
20effc67 | 648 | std::size_t(util::sequence_size<Seq>::value) == static_size); |
7c673cae FG |
649 | |
650 | template <detail::relate::field F1, detail::relate::field F2> | |
651 | struct static_get | |
652 | { | |
653 | BOOST_STATIC_ASSERT(std::size_t(F1) < static_height); | |
654 | BOOST_STATIC_ASSERT(std::size_t(F2) < static_width); | |
655 | ||
656 | static const char value | |
20effc67 | 657 | = util::sequence_element<F1 * static_width + F2, Seq>::value; |
7c673cae FG |
658 | }; |
659 | ||
660 | private: | |
661 | // check static_mask characters | |
662 | enum { mask_check = sizeof(static_check_characters<Seq>) }; | |
663 | }; | |
664 | ||
665 | // static_should_handle_element | |
666 | ||
20effc67 TL |
667 | template |
668 | < | |
669 | typename StaticMask, field F1, field F2, | |
670 | bool IsSequence = util::is_sequence<StaticMask>::value | |
671 | > | |
7c673cae FG |
672 | struct static_should_handle_element_dispatch |
673 | { | |
674 | static const char mask_el = StaticMask::template static_get<F1, F2>::value; | |
675 | static const bool value = mask_el == 'F' | |
676 | || mask_el == 'T' | |
677 | || ( mask_el >= '0' && mask_el <= '9' ); | |
678 | }; | |
679 | ||
20effc67 TL |
680 | template |
681 | < | |
682 | typename Seq, field F1, field F2, | |
683 | std::size_t I = 0, | |
684 | std::size_t N = util::sequence_size<Seq>::value | |
685 | > | |
7c673cae FG |
686 | struct static_should_handle_element_sequence |
687 | { | |
20effc67 | 688 | typedef typename util::sequence_element<I, Seq>::type StaticMask; |
7c673cae FG |
689 | |
690 | static const bool value | |
691 | = static_should_handle_element_dispatch | |
692 | < | |
20effc67 | 693 | StaticMask, F1, F2 |
7c673cae FG |
694 | >::value |
695 | || static_should_handle_element_sequence | |
696 | < | |
20effc67 | 697 | Seq, F1, F2, I + 1 |
7c673cae FG |
698 | >::value; |
699 | }; | |
700 | ||
20effc67 TL |
701 | template <typename Seq, field F1, field F2, std::size_t N> |
702 | struct static_should_handle_element_sequence<Seq, F1, F2, N, N> | |
7c673cae FG |
703 | { |
704 | static const bool value = false; | |
705 | }; | |
706 | ||
707 | template <typename StaticMask, field F1, field F2> | |
708 | struct static_should_handle_element_dispatch<StaticMask, F1, F2, true> | |
709 | { | |
710 | static const bool value | |
711 | = static_should_handle_element_sequence | |
712 | < | |
20effc67 | 713 | StaticMask, F1, F2 |
7c673cae FG |
714 | >::value; |
715 | }; | |
716 | ||
717 | template <typename StaticMask, field F1, field F2> | |
718 | struct static_should_handle_element | |
719 | { | |
720 | static const bool value | |
721 | = static_should_handle_element_dispatch | |
722 | < | |
20effc67 | 723 | StaticMask, F1, F2 |
7c673cae FG |
724 | >::value; |
725 | }; | |
726 | ||
727 | // static_interrupt | |
728 | ||
20effc67 TL |
729 | template |
730 | < | |
731 | typename StaticMask, char V, field F1, field F2, | |
732 | bool InterruptEnabled, | |
733 | bool IsSequence = util::is_sequence<StaticMask>::value | |
734 | > | |
7c673cae FG |
735 | struct static_interrupt_dispatch |
736 | { | |
737 | static const bool value = false; | |
738 | }; | |
739 | ||
740 | template <typename StaticMask, char V, field F1, field F2, bool IsSequence> | |
741 | struct static_interrupt_dispatch<StaticMask, V, F1, F2, true, IsSequence> | |
742 | { | |
743 | static const char mask_el = StaticMask::template static_get<F1, F2>::value; | |
744 | ||
745 | static const bool value | |
746 | = ( V >= '0' && V <= '9' ) ? | |
747 | ( mask_el == 'F' || ( mask_el < V && mask_el >= '0' && mask_el <= '9' ) ) : | |
748 | ( ( V == 'T' ) ? mask_el == 'F' : false ); | |
749 | }; | |
750 | ||
20effc67 TL |
751 | template |
752 | < | |
753 | typename Seq, char V, field F1, field F2, | |
754 | std::size_t I = 0, | |
755 | std::size_t N = util::sequence_size<Seq>::value | |
756 | > | |
7c673cae FG |
757 | struct static_interrupt_sequence |
758 | { | |
20effc67 | 759 | typedef typename util::sequence_element<I, Seq>::type StaticMask; |
7c673cae FG |
760 | |
761 | static const bool value | |
762 | = static_interrupt_dispatch | |
763 | < | |
20effc67 | 764 | StaticMask, V, F1, F2, true |
7c673cae FG |
765 | >::value |
766 | && static_interrupt_sequence | |
767 | < | |
20effc67 | 768 | Seq, V, F1, F2, I + 1 |
7c673cae FG |
769 | >::value; |
770 | }; | |
771 | ||
20effc67 TL |
772 | template <typename Seq, char V, field F1, field F2, std::size_t N> |
773 | struct static_interrupt_sequence<Seq, V, F1, F2, N, N> | |
7c673cae FG |
774 | { |
775 | static const bool value = true; | |
776 | }; | |
777 | ||
778 | template <typename StaticMask, char V, field F1, field F2> | |
779 | struct static_interrupt_dispatch<StaticMask, V, F1, F2, true, true> | |
780 | { | |
781 | static const bool value | |
782 | = static_interrupt_sequence | |
783 | < | |
20effc67 | 784 | StaticMask, V, F1, F2 |
7c673cae FG |
785 | >::value; |
786 | }; | |
787 | ||
788 | template <typename StaticMask, char V, field F1, field F2, bool EnableInterrupt> | |
789 | struct static_interrupt | |
790 | { | |
791 | static const bool value | |
792 | = static_interrupt_dispatch | |
793 | < | |
20effc67 | 794 | StaticMask, V, F1, F2, EnableInterrupt |
7c673cae FG |
795 | >::value; |
796 | }; | |
797 | ||
798 | // static_may_update | |
799 | ||
20effc67 TL |
800 | template |
801 | < | |
802 | typename StaticMask, char D, field F1, field F2, | |
803 | bool IsSequence = util::is_sequence<StaticMask>::value | |
804 | > | |
7c673cae FG |
805 | struct static_may_update_dispatch |
806 | { | |
807 | static const char mask_el = StaticMask::template static_get<F1, F2>::value; | |
808 | static const int version | |
809 | = mask_el == 'F' ? 0 | |
810 | : mask_el == 'T' ? 1 | |
811 | : mask_el >= '0' && mask_el <= '9' ? 2 | |
812 | : 3; | |
813 | ||
20effc67 TL |
814 | // TODO: use std::enable_if_t instead of std::integral_constant |
815 | ||
7c673cae FG |
816 | template <typename Matrix> |
817 | static inline bool apply(Matrix const& matrix) | |
818 | { | |
20effc67 | 819 | return apply_dispatch(matrix, std::integral_constant<int, version>()); |
7c673cae FG |
820 | } |
821 | ||
822 | // mask_el == 'F' | |
823 | template <typename Matrix> | |
20effc67 | 824 | static inline bool apply_dispatch(Matrix const& , std::integral_constant<int, 0>) |
7c673cae FG |
825 | { |
826 | return true; | |
827 | } | |
828 | // mask_el == 'T' | |
829 | template <typename Matrix> | |
20effc67 | 830 | static inline bool apply_dispatch(Matrix const& matrix, std::integral_constant<int, 1>) |
7c673cae FG |
831 | { |
832 | char const c = matrix.template get<F1, F2>(); | |
833 | return c == 'F'; // if it's T or between 0 and 9, the result will be the same | |
834 | } | |
835 | // mask_el >= '0' && mask_el <= '9' | |
836 | template <typename Matrix> | |
20effc67 | 837 | static inline bool apply_dispatch(Matrix const& matrix, std::integral_constant<int, 2>) |
7c673cae FG |
838 | { |
839 | char const c = matrix.template get<F1, F2>(); | |
840 | return D > c || c > '9'; | |
841 | } | |
842 | // else | |
843 | template <typename Matrix> | |
20effc67 | 844 | static inline bool apply_dispatch(Matrix const&, std::integral_constant<int, 3>) |
7c673cae FG |
845 | { |
846 | return false; | |
847 | } | |
848 | }; | |
849 | ||
20effc67 TL |
850 | template |
851 | < | |
852 | typename Seq, char D, field F1, field F2, | |
853 | std::size_t I = 0, | |
854 | std::size_t N = util::sequence_size<Seq>::value | |
855 | > | |
7c673cae FG |
856 | struct static_may_update_sequence |
857 | { | |
20effc67 | 858 | typedef typename util::sequence_element<I, Seq>::type StaticMask; |
7c673cae FG |
859 | |
860 | template <typename Matrix> | |
861 | static inline bool apply(Matrix const& matrix) | |
862 | { | |
863 | return static_may_update_dispatch | |
864 | < | |
20effc67 | 865 | StaticMask, D, F1, F2 |
7c673cae FG |
866 | >::apply(matrix) |
867 | || static_may_update_sequence | |
868 | < | |
20effc67 | 869 | Seq, D, F1, F2, I + 1 |
7c673cae FG |
870 | >::apply(matrix); |
871 | } | |
872 | }; | |
873 | ||
20effc67 TL |
874 | template <typename Seq, char D, field F1, field F2, std::size_t N> |
875 | struct static_may_update_sequence<Seq, D, F1, F2, N, N> | |
7c673cae FG |
876 | { |
877 | template <typename Matrix> | |
878 | static inline bool apply(Matrix const& /*matrix*/) | |
879 | { | |
880 | return false; | |
881 | } | |
882 | }; | |
883 | ||
884 | template <typename StaticMask, char D, field F1, field F2> | |
885 | struct static_may_update_dispatch<StaticMask, D, F1, F2, true> | |
886 | { | |
887 | template <typename Matrix> | |
888 | static inline bool apply(Matrix const& matrix) | |
889 | { | |
890 | return static_may_update_sequence | |
891 | < | |
20effc67 | 892 | StaticMask, D, F1, F2 |
7c673cae FG |
893 | >::apply(matrix); |
894 | } | |
895 | }; | |
896 | ||
897 | template <typename StaticMask, char D, field F1, field F2> | |
898 | struct static_may_update | |
899 | { | |
900 | template <typename Matrix> | |
901 | static inline bool apply(Matrix const& matrix) | |
902 | { | |
903 | return static_may_update_dispatch | |
904 | < | |
20effc67 | 905 | StaticMask, D, F1, F2 |
7c673cae FG |
906 | >::apply(matrix); |
907 | } | |
908 | }; | |
909 | ||
910 | // static_check_matrix | |
911 | ||
20effc67 TL |
912 | template |
913 | < | |
914 | typename StaticMask, | |
915 | bool IsSequence = util::is_sequence<StaticMask>::value | |
916 | > | |
7c673cae FG |
917 | struct static_check_dispatch |
918 | { | |
919 | template <typename Matrix> | |
920 | static inline bool apply(Matrix const& matrix) | |
921 | { | |
922 | return per_one<interior, interior>::apply(matrix) | |
923 | && per_one<interior, boundary>::apply(matrix) | |
924 | && per_one<interior, exterior>::apply(matrix) | |
925 | && per_one<boundary, interior>::apply(matrix) | |
926 | && per_one<boundary, boundary>::apply(matrix) | |
927 | && per_one<boundary, exterior>::apply(matrix) | |
928 | && per_one<exterior, interior>::apply(matrix) | |
929 | && per_one<exterior, boundary>::apply(matrix) | |
930 | && per_one<exterior, exterior>::apply(matrix); | |
931 | } | |
932 | ||
933 | template <field F1, field F2> | |
934 | struct per_one | |
935 | { | |
936 | static const char mask_el = StaticMask::template static_get<F1, F2>::value; | |
937 | static const int version | |
938 | = mask_el == 'F' ? 0 | |
939 | : mask_el == 'T' ? 1 | |
940 | : mask_el >= '0' && mask_el <= '9' ? 2 | |
941 | : 3; | |
942 | ||
20effc67 TL |
943 | // TODO: use std::enable_if_t instead of std::integral_constant |
944 | ||
7c673cae FG |
945 | template <typename Matrix> |
946 | static inline bool apply(Matrix const& matrix) | |
947 | { | |
948 | const char el = matrix.template get<F1, F2>(); | |
20effc67 | 949 | return apply_dispatch(el, std::integral_constant<int, version>()); |
7c673cae FG |
950 | } |
951 | ||
952 | // mask_el == 'F' | |
20effc67 | 953 | static inline bool apply_dispatch(char el, std::integral_constant<int, 0>) |
7c673cae FG |
954 | { |
955 | return el == 'F'; | |
956 | } | |
957 | // mask_el == 'T' | |
20effc67 | 958 | static inline bool apply_dispatch(char el, std::integral_constant<int, 1>) |
7c673cae FG |
959 | { |
960 | return el == 'T' || ( el >= '0' && el <= '9' ); | |
961 | } | |
962 | // mask_el >= '0' && mask_el <= '9' | |
20effc67 | 963 | static inline bool apply_dispatch(char el, std::integral_constant<int, 2>) |
7c673cae FG |
964 | { |
965 | return el == mask_el; | |
966 | } | |
967 | // else | |
20effc67 | 968 | static inline bool apply_dispatch(char /*el*/, std::integral_constant<int, 3>) |
7c673cae FG |
969 | { |
970 | return true; | |
971 | } | |
972 | }; | |
973 | }; | |
974 | ||
20effc67 TL |
975 | template |
976 | < | |
977 | typename Seq, | |
978 | std::size_t I = 0, | |
979 | std::size_t N = util::sequence_size<Seq>::value | |
980 | > | |
7c673cae FG |
981 | struct static_check_sequence |
982 | { | |
20effc67 | 983 | typedef typename util::sequence_element<I, Seq>::type StaticMask; |
7c673cae FG |
984 | |
985 | template <typename Matrix> | |
986 | static inline bool apply(Matrix const& matrix) | |
987 | { | |
988 | return static_check_dispatch | |
989 | < | |
20effc67 | 990 | StaticMask |
7c673cae FG |
991 | >::apply(matrix) |
992 | || static_check_sequence | |
993 | < | |
20effc67 | 994 | Seq, I + 1 |
7c673cae FG |
995 | >::apply(matrix); |
996 | } | |
997 | }; | |
998 | ||
20effc67 TL |
999 | template <typename Seq, std::size_t N> |
1000 | struct static_check_sequence<Seq, N, N> | |
7c673cae FG |
1001 | { |
1002 | template <typename Matrix> | |
1003 | static inline bool apply(Matrix const& /*matrix*/) | |
1004 | { | |
1005 | return false; | |
1006 | } | |
1007 | }; | |
1008 | ||
1009 | template <typename StaticMask> | |
1010 | struct static_check_dispatch<StaticMask, true> | |
1011 | { | |
1012 | template <typename Matrix> | |
1013 | static inline bool apply(Matrix const& matrix) | |
1014 | { | |
1015 | return static_check_sequence | |
1016 | < | |
20effc67 | 1017 | StaticMask |
7c673cae FG |
1018 | >::apply(matrix); |
1019 | } | |
1020 | }; | |
1021 | ||
1022 | template <typename StaticMask> | |
1023 | struct static_check_matrix | |
1024 | { | |
1025 | template <typename Matrix> | |
1026 | static inline bool apply(Matrix const& matrix) | |
1027 | { | |
1028 | return static_check_dispatch | |
1029 | < | |
20effc67 | 1030 | StaticMask |
7c673cae FG |
1031 | >::apply(matrix); |
1032 | } | |
1033 | }; | |
1034 | ||
1035 | // static_mask_handler | |
1036 | ||
1037 | template <typename StaticMask, bool Interrupt> | |
1038 | class static_mask_handler | |
1039 | : private matrix_handler< matrix<3> > | |
1040 | { | |
1041 | typedef matrix_handler< relate::matrix<3> > base_type; | |
1042 | ||
1043 | public: | |
1044 | typedef bool result_type; | |
1045 | ||
1046 | bool interrupt; | |
1047 | ||
1048 | inline static_mask_handler() | |
1049 | : interrupt(false) | |
1050 | {} | |
1051 | ||
1052 | inline explicit static_mask_handler(StaticMask const& /*dummy*/) | |
1053 | : interrupt(false) | |
1054 | {} | |
1055 | ||
1056 | result_type result() const | |
1057 | { | |
1058 | return (!Interrupt || !interrupt) | |
1059 | && static_check_matrix<StaticMask>::apply(base_type::matrix()); | |
1060 | } | |
1061 | ||
1062 | template <field F1, field F2, char D> | |
1063 | inline bool may_update() const | |
1064 | { | |
1065 | return static_may_update<StaticMask, D, F1, F2>:: | |
1066 | apply(base_type::matrix()); | |
1067 | } | |
1068 | ||
1069 | template <field F1, field F2> | |
1070 | static inline bool expects() | |
1071 | { | |
1072 | return static_should_handle_element<StaticMask, F1, F2>::value; | |
1073 | } | |
1074 | ||
1075 | template <field F1, field F2, char V> | |
1076 | inline void set() | |
1077 | { | |
1078 | static const bool interrupt_c = static_interrupt<StaticMask, V, F1, F2, Interrupt>::value; | |
1079 | static const bool should_handle = static_should_handle_element<StaticMask, F1, F2>::value; | |
1080 | static const int version = interrupt_c ? 0 | |
1081 | : should_handle ? 1 | |
1082 | : 2; | |
1083 | ||
1084 | set_dispatch<F1, F2, V>(integral_constant<int, version>()); | |
1085 | } | |
1086 | ||
1087 | template <field F1, field F2, char V> | |
1088 | inline void update() | |
1089 | { | |
1090 | static const bool interrupt_c = static_interrupt<StaticMask, V, F1, F2, Interrupt>::value; | |
1091 | static const bool should_handle = static_should_handle_element<StaticMask, F1, F2>::value; | |
1092 | static const int version = interrupt_c ? 0 | |
1093 | : should_handle ? 1 | |
1094 | : 2; | |
1095 | ||
1096 | update_dispatch<F1, F2, V>(integral_constant<int, version>()); | |
1097 | } | |
1098 | ||
1099 | private: | |
1100 | // Interrupt && interrupt | |
1101 | template <field F1, field F2, char V> | |
1102 | inline void set_dispatch(integral_constant<int, 0>) | |
1103 | { | |
1104 | interrupt = true; | |
1105 | } | |
1106 | // else should_handle | |
1107 | template <field F1, field F2, char V> | |
1108 | inline void set_dispatch(integral_constant<int, 1>) | |
1109 | { | |
1110 | base_type::template set<F1, F2, V>(); | |
1111 | } | |
1112 | // else | |
1113 | template <field F1, field F2, char V> | |
1114 | inline void set_dispatch(integral_constant<int, 2>) | |
1115 | {} | |
1116 | ||
1117 | // Interrupt && interrupt | |
1118 | template <field F1, field F2, char V> | |
1119 | inline void update_dispatch(integral_constant<int, 0>) | |
1120 | { | |
1121 | interrupt = true; | |
1122 | } | |
1123 | // else should_handle | |
1124 | template <field F1, field F2, char V> | |
1125 | inline void update_dispatch(integral_constant<int, 1>) | |
1126 | { | |
1127 | base_type::template update<F1, F2, V>(); | |
1128 | } | |
1129 | // else | |
1130 | template <field F1, field F2, char V> | |
1131 | inline void update_dispatch(integral_constant<int, 2>) | |
1132 | {} | |
1133 | }; | |
1134 | ||
1135 | // --------------- UTIL FUNCTIONS ---------------- | |
1136 | ||
1137 | // set | |
1138 | ||
1139 | template <field F1, field F2, char V, typename Result> | |
1140 | inline void set(Result & res) | |
1141 | { | |
1142 | res.template set<F1, F2, V>(); | |
1143 | } | |
1144 | ||
1145 | template <field F1, field F2, char V, bool Transpose> | |
1146 | struct set_dispatch | |
1147 | { | |
1148 | template <typename Result> | |
1149 | static inline void apply(Result & res) | |
1150 | { | |
1151 | res.template set<F1, F2, V>(); | |
1152 | } | |
1153 | }; | |
1154 | ||
1155 | template <field F1, field F2, char V> | |
1156 | struct set_dispatch<F1, F2, V, true> | |
1157 | { | |
1158 | template <typename Result> | |
1159 | static inline void apply(Result & res) | |
1160 | { | |
1161 | res.template set<F2, F1, V>(); | |
1162 | } | |
1163 | }; | |
1164 | ||
1165 | template <field F1, field F2, char V, bool Transpose, typename Result> | |
1166 | inline void set(Result & res) | |
1167 | { | |
1168 | set_dispatch<F1, F2, V, Transpose>::apply(res); | |
1169 | } | |
1170 | ||
1171 | // update | |
1172 | ||
1173 | template <field F1, field F2, char D, typename Result> | |
1174 | inline void update(Result & res) | |
1175 | { | |
1176 | res.template update<F1, F2, D>(); | |
1177 | } | |
1178 | ||
1179 | template <field F1, field F2, char D, bool Transpose> | |
1180 | struct update_result_dispatch | |
1181 | { | |
1182 | template <typename Result> | |
1183 | static inline void apply(Result & res) | |
1184 | { | |
1185 | update<F1, F2, D>(res); | |
1186 | } | |
1187 | }; | |
1188 | ||
1189 | template <field F1, field F2, char D> | |
1190 | struct update_result_dispatch<F1, F2, D, true> | |
1191 | { | |
1192 | template <typename Result> | |
1193 | static inline void apply(Result & res) | |
1194 | { | |
1195 | update<F2, F1, D>(res); | |
1196 | } | |
1197 | }; | |
1198 | ||
1199 | template <field F1, field F2, char D, bool Transpose, typename Result> | |
1200 | inline void update(Result & res) | |
1201 | { | |
1202 | update_result_dispatch<F1, F2, D, Transpose>::apply(res); | |
1203 | } | |
1204 | ||
1205 | // may_update | |
1206 | ||
1207 | template <field F1, field F2, char D, typename Result> | |
1208 | inline bool may_update(Result const& res) | |
1209 | { | |
1210 | return res.template may_update<F1, F2, D>(); | |
1211 | } | |
1212 | ||
1213 | template <field F1, field F2, char D, bool Transpose> | |
1214 | struct may_update_result_dispatch | |
1215 | { | |
1216 | template <typename Result> | |
1217 | static inline bool apply(Result const& res) | |
1218 | { | |
1219 | return may_update<F1, F2, D>(res); | |
1220 | } | |
1221 | }; | |
1222 | ||
1223 | template <field F1, field F2, char D> | |
1224 | struct may_update_result_dispatch<F1, F2, D, true> | |
1225 | { | |
1226 | template <typename Result> | |
1227 | static inline bool apply(Result const& res) | |
1228 | { | |
1229 | return may_update<F2, F1, D>(res); | |
1230 | } | |
1231 | }; | |
1232 | ||
1233 | template <field F1, field F2, char D, bool Transpose, typename Result> | |
1234 | inline bool may_update(Result const& res) | |
1235 | { | |
1236 | return may_update_result_dispatch<F1, F2, D, Transpose>::apply(res); | |
1237 | } | |
1238 | ||
1239 | // result_dimension | |
1240 | ||
1241 | template <typename Geometry> | |
1242 | struct result_dimension | |
1243 | { | |
1244 | BOOST_STATIC_ASSERT(geometry::dimension<Geometry>::value >= 0); | |
1245 | static const char value | |
1246 | = ( geometry::dimension<Geometry>::value <= 9 ) ? | |
1247 | ( '0' + geometry::dimension<Geometry>::value ) : | |
1248 | 'T'; | |
1249 | }; | |
1250 | ||
1251 | }} // namespace detail::relate | |
1252 | #endif // DOXYGEN_NO_DETAIL | |
1253 | ||
1254 | }} // namespace boost::geometry | |
1255 | ||
1256 | #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_RESULT_HPP |