Imported Upstream version 1.57.0
[platform/upstream/boost.git] / boost / polygon / segment_concept.hpp
1 // Boost.Polygon library segment_concept.hpp header file
2
3 // Copyright (c) Intel Corporation 2008.
4 // Copyright (c) 2008-2012 Simonson Lucanus.
5 // Copyright (c) 2012-2012 Andrii Sydorchuk.
6
7 // See http://www.boost.org for updates, documentation, and revision history.
8 // Use, modification and distribution is subject to the Boost Software License,
9 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
10 // http://www.boost.org/LICENSE_1_0.txt)
11
12 #ifndef BOOST_POLYGON_SEGMENT_CONCEPT_HPP
13 #define BOOST_POLYGON_SEGMENT_CONCEPT_HPP
14
15 #include "isotropy.hpp"
16 #include "segment_traits.hpp"
17 #include "rectangle_concept.hpp"
18
19 namespace boost {
20 namespace polygon {
21
22 struct segment_concept {};
23
24 template <typename ConceptType>
25 struct is_segment_concept {
26   typedef gtl_no type;
27 };
28
29 template <>
30 struct is_segment_concept<segment_concept> {
31   typedef gtl_yes type;
32 };
33
34 template <typename ConceptType>
35 struct is_mutable_segment_concept {
36   typedef gtl_no type;
37 };
38
39 template <>
40 struct is_mutable_segment_concept<segment_concept> {
41   typedef gtl_yes type;
42 };
43
44 template <typename GeometryType, typename BoolType>
45 struct segment_distance_type_by_concept {
46   typedef void type;
47 };
48
49 template <typename GeometryType>
50 struct segment_distance_type_by_concept<GeometryType, gtl_yes> {
51   typedef typename coordinate_traits<
52     typename segment_traits<GeometryType>::coordinate_type
53   >::coordinate_distance type;
54 };
55
56 template <typename GeometryType>
57 struct segment_distance_type {
58   typedef typename segment_distance_type_by_concept<
59     GeometryType,
60     typename is_segment_concept<
61       typename geometry_concept<GeometryType>::type
62     >::type
63   >::type type;
64 };
65
66 template <typename GeometryType, typename BoolType>
67 struct segment_point_type_by_concept {
68   typedef void type;
69 };
70
71 template <typename GeometryType>
72 struct segment_point_type_by_concept<GeometryType, gtl_yes> {
73   typedef typename segment_traits<GeometryType>::point_type type;
74 };
75
76 template <typename GeometryType>
77 struct segment_point_type {
78   typedef typename segment_point_type_by_concept<
79     GeometryType,
80     typename is_segment_concept<
81       typename geometry_concept<GeometryType>::type
82     >::type
83   >::type type;
84 };
85
86 template <typename GeometryType, typename BoolType>
87 struct segment_coordinate_type_by_concept {
88   typedef void type;
89 };
90
91 template <typename GeometryType>
92 struct segment_coordinate_type_by_concept<GeometryType, gtl_yes> {
93   typedef typename segment_traits<GeometryType>::coordinate_type type;
94 };
95
96 template <typename GeometryType>
97 struct segment_coordinate_type {
98   typedef typename segment_coordinate_type_by_concept<
99     GeometryType,
100     typename is_segment_concept<
101       typename geometry_concept<GeometryType>::type
102     >::type
103   >::type type;
104 };
105
106 struct y_s_get : gtl_yes {};
107
108 template <typename Segment>
109 typename enable_if<
110   typename gtl_and<
111     y_s_get,
112     typename is_segment_concept<
113       typename geometry_concept<Segment>::type
114     >::type
115   >::type,
116 typename segment_point_type<Segment>::type>::type
117 get(const Segment& segment, direction_1d dir) {
118   return segment_traits<Segment>::get(segment, dir);
119 }
120
121 struct y_s_set : gtl_yes {};
122
123 template <typename Segment, typename Point>
124 typename enable_if<
125   typename gtl_and_3<
126     y_s_set,
127     typename is_mutable_segment_concept<
128       typename geometry_concept<Segment>::type
129     >::type,
130     typename is_point_concept<
131       typename geometry_concept<Point>::type
132     >::type
133   >::type,
134 void>::type set(Segment& segment, direction_1d dir, const Point& point) {
135   segment_mutable_traits<Segment>::set(segment, dir, point);
136 }
137
138 struct y_s_construct : gtl_yes {};
139
140 template <typename Segment, typename Point1, typename Point2>
141 typename enable_if<
142   typename gtl_and_4<
143     y_s_construct,
144     typename is_mutable_segment_concept<
145       typename geometry_concept<Segment>::type
146     >::type,
147     typename is_point_concept<
148       typename geometry_concept<Point1>::type
149     >::type,
150     typename is_point_concept<
151       typename geometry_concept<Point2>::type
152     >::type
153   >::type,
154 Segment>::type construct(const Point1& low, const Point2& high) {
155   return segment_mutable_traits<Segment>::construct(low, high);
156 }
157
158 struct y_s_copy_construct : gtl_yes {};
159
160 template <typename Segment1, typename Segment2>
161 typename enable_if<
162   typename gtl_and_3<
163     y_s_copy_construct,
164     typename is_mutable_segment_concept<
165       typename geometry_concept<Segment1>::type
166     >::type,
167     typename is_segment_concept<
168       typename geometry_concept<Segment2>::type
169     >::type
170   >::type,
171 Segment1>::type copy_construct(const Segment2& segment) {
172   return construct<Segment1>(get(segment, LOW), get(segment, HIGH));
173 }
174
175 struct y_s_assign : gtl_yes {};
176
177 template <typename Segment1, typename Segment2>
178 typename enable_if<
179   typename gtl_and_3<
180     y_s_assign,
181     typename is_mutable_segment_concept<
182       typename geometry_concept<Segment1>::type
183     >::type,
184     typename is_segment_concept<
185       typename geometry_concept<Segment2>::type
186     >::type
187   >::type,
188 Segment1>::type& assign(Segment1& segment1, const Segment2& segment2) {
189   return segment1 = copy_construct<Segment1>(segment2);
190 }
191
192 struct y_s_equivalence : gtl_yes {};
193
194 template <typename Segment1, typename Segment2>
195 typename enable_if<
196   typename gtl_and_3<
197     y_s_equivalence,
198     typename is_segment_concept<
199       typename geometry_concept<Segment1>::type
200     >::type,
201     typename is_segment_concept<
202       typename geometry_concept<Segment2>::type
203     >::type
204   >::type,
205 bool>::type equivalence(const Segment1& segment1, const Segment2& segment2) {
206   return get(segment1, LOW) == get(segment2, LOW) &&
207          get(segment1, HIGH) == get(segment2, HIGH);
208 }
209
210 struct y_s_low : gtl_yes {};
211
212 template <typename Segment>
213 typename enable_if<
214   typename gtl_and<
215     y_s_low,
216     typename is_segment_concept<
217       typename geometry_concept<Segment>::type
218     >::type
219   >::type,
220 typename segment_point_type<Segment>::type>::type low(const Segment& segment) {
221   return get(segment, LOW);
222 }
223
224 struct y_s_high : gtl_yes {};
225
226 template <typename Segment>
227 typename enable_if<
228   typename gtl_and<
229     y_s_high,
230     typename is_segment_concept<
231       typename geometry_concept<Segment>::type
232     >::type
233   >::type,
234 typename segment_point_type<Segment>::type>::type high(const Segment& segment) {
235   return get(segment, HIGH);
236 }
237
238 struct y_s_center : gtl_yes {};
239
240 template <typename Segment>
241 typename enable_if<
242   typename gtl_and<
243     y_s_center,
244     typename is_segment_concept<
245       typename geometry_concept<Segment>::type
246     >::type
247   >::type,
248 typename segment_point_type<Segment>::type>::type
249 center(const Segment& segment) {
250   return construct<typename segment_point_type<Segment>::type>(
251       (x(high(segment)) + x(low(segment)))/2,
252       (y(high(segment)) + y(low(segment)))/2);
253 }
254
255 struct y_s_low2 : gtl_yes {};
256
257 template <typename Segment, typename Point>
258 typename enable_if<
259   typename gtl_and_3<
260     y_s_low2,
261     typename is_mutable_segment_concept<
262       typename geometry_concept<Segment>::type
263     >::type,
264     typename is_point_concept<
265       typename geometry_concept<Point>::type
266     >::type
267   >::type,
268 void>::type low(Segment& segment, const Point& point) {
269   set(segment, LOW, point);
270 }
271
272 struct y_s_high2 : gtl_yes {};
273
274 template <typename Segment, typename Point>
275 typename enable_if<
276   typename gtl_and_3<
277     y_s_high2,
278     typename is_mutable_segment_concept<
279       typename geometry_concept<Segment>::type
280     >::type,
281     typename is_point_concept<
282       typename geometry_concept<Point>::type
283     >::type
284   >::type,
285 void>::type high(Segment& segment, const Point& point) {
286   set(segment, HIGH, point);
287 }
288
289 struct y_s_orientation1 : gtl_yes {};
290
291 // -1 for CW, 0 for collinear and 1 for CCW.
292 template <typename Segment1, typename Segment2>
293 typename enable_if<
294   typename gtl_and_3<
295     y_s_orientation1,
296     typename is_segment_concept<
297       typename geometry_concept<Segment1>::type
298     >::type,
299     typename is_segment_concept<
300       typename geometry_concept<Segment2>::type
301     >::type
302   >::type,
303 int>::type orientation(const Segment1& segment1, const Segment2& segment2) {
304   typedef typename coordinate_traits<
305     typename segment_traits<Segment1>::coordinate_type
306   >::manhattan_area_type int_x2;
307   typedef typename coordinate_traits<
308     typename segment_traits<Segment1>::coordinate_type
309   >::unsigned_area_type uint_x2;
310   int_x2 a1 = (int_x2)x(high(segment1)) - (int_x2)x(low(segment1));
311   int_x2 b1 = (int_x2)y(high(segment1)) - (int_x2)y(low(segment1));
312   int_x2 a2 = (int_x2)x(high(segment2)) - (int_x2)x(low(segment2));
313   int_x2 b2 = (int_x2)y(high(segment2)) - (int_x2)y(low(segment2));
314
315   int sign1 = 0;
316   int sign2 = 0;
317   if (a1 && b2)
318     sign1 = ((a1 > 0) ^ (b2 > 0)) ? -1 : 1;
319   if (a2 && b1)
320     sign2 = ((a2 > 0) ^ (b1 > 0)) ? -1 : 1;
321
322   if (sign1 != sign2)
323     return (sign1 < sign2) ? -1 : 1;
324   uint_x2 a3 = (uint_x2)(a1 < 0 ? -a1 : a1) * (uint_x2)(b2 < 0 ? -b2 : b2);
325   uint_x2 b3 = (uint_x2)(b1 < 0 ? -b1 : b1) * (uint_x2)(a2 < 0 ? -a2 : a2);
326   if (a3 == b3)
327     return 0;
328   return ((a3 < b3) ^ (sign1 == 1)) ? 1 : -1;
329 }
330
331 struct y_s_orientation2 : gtl_yes {};
332
333 // -1 for right, 0 for collinear and 1 for left.
334 template <typename Segment, typename Point>
335 typename enable_if<
336   typename gtl_and_3<
337     y_s_orientation2,
338     typename is_segment_concept<
339       typename geometry_concept<Segment>::type
340     >::type,
341     typename is_point_concept<
342       typename geometry_concept<Point>::type
343     >::type
344   >::type,
345 int>::type orientation(const Segment& segment, const Point& point) {
346   Segment segment2 = construct<Segment>(high(segment), point);
347   return orientation(segment, segment2);
348 }
349
350 struct y_s_contains : gtl_yes {};
351
352 template <typename Segment, typename Point>
353 typename enable_if<
354   typename gtl_and_3<
355     y_s_contains,
356     typename is_segment_concept<
357       typename geometry_concept<Segment>::type
358     >::type,
359     typename is_point_concept<
360       typename geometry_concept<Point>::type
361     >::type
362   >::type,
363 bool>::type contains(const Segment& segment,
364     const Point& point, bool consider_touch = true ) {
365   if (orientation(segment, point))
366     return false;
367   rectangle_data<typename segment_coordinate_type<Segment>::type> rect;
368   set_points(rect, low(segment), high(segment));
369   if (!contains(rect, point, true))
370     return false;
371   if (!consider_touch &&
372       (equivalence(low(segment), point) ||
373        equivalence(high(segment), point)))
374     return false;
375   return true;
376 }
377
378 struct y_s_contains2 : gtl_yes {};
379
380 template <typename Segment1, typename Segment2>
381 typename enable_if<
382   typename gtl_and_3<
383     y_s_contains2,
384     typename is_segment_concept<
385       typename geometry_concept<Segment1>::type
386     >::type,
387     typename is_segment_concept<
388       typename geometry_concept<Segment2>::type
389     >::type
390   >::type,
391 bool>::type contains(const Segment1& segment1,
392     const Segment2& segment2, bool consider_touch = true) {
393   return contains(segment1, get(segment2, LOW), consider_touch) &&
394          contains(segment1, get(segment2, HIGH), consider_touch);
395 }
396
397 struct y_s_length : gtl_yes {};
398
399 template <typename Segment>
400 typename enable_if<
401   typename gtl_and<
402     y_s_length,
403     typename is_segment_concept<
404       typename geometry_concept<Segment>::type
405     >::type
406   >::type,
407 typename segment_distance_type<Segment>::type>::type
408 length(const Segment& segment) {
409   return euclidean_distance(low(segment), high(segment));
410 }
411
412 struct y_s_scale_up : gtl_yes {};
413
414 template <typename Segment>
415 typename enable_if<
416   typename gtl_and<
417     y_s_scale_up,
418     typename is_mutable_segment_concept<
419       typename geometry_concept<Segment>::type
420     >::type
421   >::type,
422 Segment>::type& scale_up(Segment& segment,
423     typename coordinate_traits<
424       typename segment_coordinate_type<Segment>::type
425     >::unsigned_area_type factor) {
426   typename segment_point_type<Segment>::type l = low(segment);
427   typename segment_point_type<Segment>::type h = high(segment);
428   low(segment, scale_up(l, factor));
429   high(segment, scale_up(h, factor));
430   return segment;
431 }
432
433 struct y_s_scale_down : gtl_yes {};
434
435 template <typename Segment>
436 typename enable_if<
437   typename gtl_and<
438     y_s_scale_down,
439     typename is_mutable_segment_concept<
440       typename geometry_concept<Segment>::type
441     >::type
442   >::type,
443 Segment>::type& scale_down(Segment& segment,
444     typename coordinate_traits<
445       typename segment_coordinate_type<Segment>::type
446     >::unsigned_area_type factor) {
447   typename segment_point_type<Segment>::type l = low(segment);
448   typename segment_point_type<Segment>::type h = high(segment);
449   low(segment, scale_down(l, factor));
450   high(segment, scale_down(h, factor));
451   return segment;
452 }
453
454 struct y_s_scale : gtl_yes {};
455
456 template <typename Segment, typename Scale>
457 typename enable_if<
458   typename gtl_and<
459     y_s_scale,
460     typename is_mutable_segment_concept<
461       typename geometry_concept<Segment>::type
462     >::type
463   >::type,
464 Segment>::type& scale(Segment& segment, const Scale& sc) {
465   typename segment_point_type<Segment>::type l = low(segment);
466   typename segment_point_type<Segment>::type h = high(segment);
467   low(segment, scale(l, sc));
468   high(segment, scale(h, sc));
469   return segment;
470 }
471
472 struct y_s_transform : gtl_yes {};
473
474 template <typename Segment, typename Transform>
475 typename enable_if<
476   typename gtl_and<
477     y_s_transform,
478     typename is_mutable_segment_concept<
479       typename geometry_concept<Segment>::type
480     >::type
481   >::type,
482 Segment>::type& transform(Segment& segment, const Transform& tr) {
483   typename segment_point_type<Segment>::type l = low(segment);
484   typename segment_point_type<Segment>::type h = high(segment);
485   low(segment, transform(l, tr));
486   high(segment, transform(h, tr));
487   return segment;
488 }
489
490 struct y_s_move : gtl_yes {};
491
492 template <typename Segment>
493 typename enable_if<
494   typename gtl_and<
495     y_s_move,
496     typename is_mutable_segment_concept<
497       typename geometry_concept<Segment>::type
498     >::type
499   >::type,
500 Segment>::type& move(Segment& segment, orientation_2d orient,
501     typename segment_coordinate_type<Segment>::type displacement) {
502   typename segment_point_type<Segment>::type l = low(segment);
503   typename segment_point_type<Segment>::type h = high(segment);
504   low(segment, move(l, orient, displacement));
505   high(segment, move(h, orient, displacement));
506   return segment;
507 }
508
509 struct y_s_convolve : gtl_yes {};
510
511 template <typename Segment, typename Point>
512 typename enable_if<
513   typename gtl_and_3<
514     y_s_convolve,
515     typename is_mutable_segment_concept<
516       typename geometry_concept<Segment>::type
517     >::type,
518     typename is_point_concept<
519       typename geometry_concept<Point>::type
520     >::type
521   >::type,
522 Segment>::type& convolve(Segment& segment, const Point& point) {
523   typename segment_point_type<Segment>::type l = low(segment);
524   typename segment_point_type<Segment>::type h = high(segment);
525   low(segment, convolve(l, point));
526   high(segment, convolve(h, point));
527   return segment;
528 }
529
530 struct y_s_deconvolve : gtl_yes {};
531
532 template <typename Segment, typename Point>
533 typename enable_if<
534   typename gtl_and_3<
535     y_s_deconvolve,
536     typename is_mutable_segment_concept<
537       typename geometry_concept<Segment>::type
538     >::type,
539     typename is_point_concept<
540       typename geometry_concept<Point>::type
541     >::type
542   >::type,
543 Segment>::type& deconvolve(Segment& segment, const Point& point) {
544   typename segment_point_type<Segment>::type l = low(segment);
545   typename segment_point_type<Segment>::type h = high(segment);
546   low(segment, deconvolve(l, point));
547   high(segment, deconvolve(h, point));
548   return segment;
549 }
550
551 struct y_s_abuts1 : gtl_yes {};
552
553 template <typename Segment1, typename Segment2>
554 typename enable_if<
555   typename gtl_and_3<
556     y_s_abuts1,
557     typename is_segment_concept<
558       typename geometry_concept<Segment1>::type
559     >::type,
560     typename is_segment_concept<
561       typename geometry_concept<Segment2>::type
562     >::type
563   >::type,
564 bool>::type abuts(const Segment1& segment1,
565     const Segment2& segment2, direction_1d dir) {
566   return dir.to_int() ? equivalence(low(segment2) , high(segment1)) :
567                         equivalence(low(segment1) , high(segment2));
568 }
569
570 struct y_s_abuts2 : gtl_yes {};
571
572 template <typename Segment1, typename Segment2>
573 typename enable_if<
574   typename gtl_and_3<
575     y_s_abuts2,
576     typename is_segment_concept<
577       typename geometry_concept<Segment1>::type
578     >::type,
579     typename is_segment_concept<
580       typename geometry_concept<Segment2>::type
581     >::type
582   >::type,
583 bool>::type abuts(const Segment1& segment1, const Segment2& segment2) {
584   return abuts(segment1, segment2, HIGH) || abuts(segment1, segment2, LOW);
585 }
586
587 struct y_s_e_intersects : gtl_yes {};
588
589 template <typename Segment1, typename Segment2>
590 typename enable_if<
591   typename gtl_and_3<
592     y_s_e_intersects,
593     typename is_segment_concept<
594       typename geometry_concept<Segment1>::type
595     >::type,
596     typename is_segment_concept<
597       typename geometry_concept<Segment2>::type
598     >::type
599   >::type,
600 bool
601 >::type intersects(const Segment1& segment1, const Segment2& segment2,
602     bool consider_touch = true) {
603   rectangle_data<typename segment_coordinate_type<Segment1>::type> rect1, rect2;
604   set_points(rect1, low(segment1), high(segment1));
605   set_points(rect2, low(segment2), high(segment2));
606   // Check if axis-parallel rectangles containing segments intersect.
607   if (!intersects(rect1, rect2, true))
608     return false;
609   int or1_1 = orientation(segment1, low(segment2));
610   int or1_2 = orientation(segment1, high(segment2));
611   if (or1_1 * or1_2 > 0)
612     return false;
613   int or2_1 = orientation(segment2, low(segment1));
614   int or2_2 = orientation(segment2, high(segment1));
615   if (or2_1 * or2_2 > 0)
616     return false;
617   if (consider_touch || (or1_1 && or1_2) || (or2_1 && or2_2))
618     return true;
619   if (or1_1 || or1_2)
620     return false;
621   return intersects(vertical(rect1), vertical(rect2), false) ||
622          intersects(horizontal(rect1), horizontal(rect2), false);
623 }
624
625 struct y_s_e_dist : gtl_yes {};
626
627 template <typename Segment, typename Point>
628 typename enable_if<
629   typename gtl_and_3<
630     y_s_e_dist,
631     typename is_segment_concept<
632       typename geometry_concept<Segment>::type
633     >::type,
634     typename is_point_concept<
635       typename geometry_concept<Point>::type
636     >::type
637   >::type,
638 typename segment_distance_type<Segment>::type>::type
639 euclidean_distance(const Segment& segment, const Point& point) {
640   typedef typename segment_distance_type<Segment>::type Unit;
641   Unit x1 = x(low(segment));
642   Unit y1 = y(low(segment));
643   Unit x2 = x(high(segment));
644   Unit y2 = y(high(segment));
645   Unit X = x(point);
646   Unit Y = y(point);
647   Unit A = X - x1;
648   Unit B = Y - y1;
649   Unit C = x2 - x1;
650   Unit D = y2 - y1;
651   Unit param = (A * C + B * D);
652   Unit length_sq = C * C + D * D;
653   if (param > length_sq) {
654     return euclidean_distance(high(segment), point);
655   } else if (param < 0.0) {
656     return euclidean_distance(low(segment), point);
657   }
658   if (length_sq == 0.0)
659     return 0.0;
660   Unit denom = std::sqrt(length_sq);
661   Unit result = (A * D - C * B) / denom;
662   return (result < 0.0) ? -result : result;
663 }
664
665 struct y_s_e_dist2 : gtl_yes {};
666
667 template <typename Segment1, typename Segment2>
668 typename enable_if<
669   typename gtl_and_3<
670     y_s_e_dist2,
671     typename is_segment_concept<
672       typename geometry_concept<Segment1>::type
673     >::type,
674     typename is_segment_concept<
675       typename geometry_concept<Segment2>::type
676     >::type
677   >::type,
678 typename segment_distance_type<Segment1>::type>::type
679 euclidean_distance(const Segment1& segment1, const Segment2& segment2) {
680   if (intersects(segment1, segment2))
681     return 0.0;
682   typename segment_distance_type<Segment1>::type
683       result1 = euclidean_distance(segment1, low(segment2)),
684       result2 = euclidean_distance(segment1, high(segment2)),
685       result3 = euclidean_distance(segment2, low(segment1)),
686       result4 = euclidean_distance(segment2, high(segment1));
687   if (result2 < result1)
688     result1 = result2;
689   if (result4 < result3)
690     result3 = result4;
691   return (result1 < result3) ? result1 : result3;
692 }
693 }  // polygon
694 }  // boost
695
696 #endif  // BOOST_POLYGON_SEGMENT_CONCEPT_HPP