• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2 // Unit Test
3 
4 // Copyright (c) 2015-2018, Oracle and/or its affiliates.
5 
6 // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
7 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
8 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
9 
10 // Licensed under the Boost Software License version 1.0.
11 // http://www.boost.org/users/license.html
12 
13 
14 #ifndef BOOST_TEST_MODULE
15 #define BOOST_TEST_MODULE test_envelope_on_sphere_or_spheroid
16 #endif
17 
18 #include <boost/test/included/unit_test.hpp>
19 
20 #include <cstddef>
21 #include <limits>
22 #include <iostream>
23 #include <string>
24 
25 #include <geometry_test_common.hpp>
26 #include <from_wkt.hpp>
27 
28 #include <boost/numeric/conversion/bounds.hpp>
29 #include <boost/type_traits/is_same.hpp>
30 
31 #include <boost/geometry/core/coordinate_dimension.hpp>
32 #include <boost/geometry/core/tag.hpp>
33 #include <boost/geometry/core/tags.hpp>
34 
35 #include <boost/geometry/geometries/geometries.hpp>
36 
37 #include <boost/geometry/util/condition.hpp>
38 
39 #include <boost/geometry/io/dsv/write.hpp>
40 #include <boost/geometry/io/wkt/wkt.hpp>
41 
42 #include <boost/geometry/algorithms/convert.hpp>
43 #include <boost/geometry/algorithms/envelope.hpp>
44 #include <boost/geometry/algorithms/reverse.hpp>
45 
46 #include <boost/geometry/index/detail/algorithms/is_valid.hpp>
47 
48 #include "test_envelope_expand_on_spheroid.hpp"
49 
50 
51 template <typename FormulaPolicy, typename CS_Tag>
52 struct test_envelope
53 {
54     template <typename Geometry, typename Box>
applytest_envelope55     static inline void apply(Geometry& geometry, Box& detected)
56     {
57         bg::envelope(geometry, detected);
58     }
59 };
60 
61 template <typename FormulaPolicy>
62 struct test_envelope<FormulaPolicy, bg::geographic_tag>
63 {
64     template <typename Geometry, typename Box>
applytest_envelope65     static inline void apply(Geometry& geometry,
66                              Box& detected)
67     {
68         typedef bg::strategy::envelope::spherical_point point_strategy_t;
69         typedef bg::strategy::envelope::spherical_multipoint multi_point_strategy_t;
70         typedef bg::strategy::envelope::spherical_box box_strategy_t;
71         typedef bg::strategy::envelope::geographic<FormulaPolicy, bg::srs::spheroid<double>, double> strategy_t;
72 
73         typename boost::mpl::if_c
74             <
75                 boost::is_same<typename bg::tag<Geometry>::type, bg::point_tag>::value,
76                 point_strategy_t,
77                 typename boost::mpl::if_c
78                     <
79                         boost::is_same<typename bg::tag<Geometry>::type, bg::multi_point_tag>::value,
80                         multi_point_strategy_t,
81                         typename boost::mpl::if_c
82                             <
83                                 boost::is_same<typename bg::tag<Geometry>::type, bg::box_tag>::value,
84                                 box_strategy_t,
85                                 strategy_t
86                             >::type
87                     >::type
88             >::type strategy;
89 
90         bg::envelope(geometry, detected, strategy);
91     }
92 };
93 
94 template <typename MBR, typename FormulaPolicy = bg::strategy::thomas>
95 class envelope_on_spheroid_basic_tester
96 {
97 private:
98     template
99     <
100         typename Geometry,
101         typename Tag = typename bg::tag<Geometry>::type
102     >
103     struct write_geometry
104     {
105         template <typename OutputStream>
applyenvelope_on_spheroid_basic_tester::write_geometry106         static inline OutputStream& apply(OutputStream& os,
107                                           Geometry const& geometry)
108         {
109             os << bg::wkt(geometry);
110             return os;
111         }
112     };
113 
114     template <typename Segment>
115     struct write_geometry<Segment, bg::segment_tag>
116     {
117         template <typename OutputStream>
applyenvelope_on_spheroid_basic_tester::write_geometry118         static inline OutputStream& apply(OutputStream& os,
119                                           Segment const& segment)
120         {
121             os << "SEGMENT" << bg::dsv(segment);
122             return os;
123         }
124     };
125 
126     template <typename Box>
127     struct write_geometry<Box, bg::box_tag>
128     {
129         template <typename OutputStream>
applyenvelope_on_spheroid_basic_tester::write_geometry130         static inline OutputStream& apply(OutputStream& os,
131                                           Box const& box)
132         {
133             os << "BOX" << bg::dsv(box);
134             return os;
135         }
136     };
137 
138     template <typename Geometry, typename Box>
check_message(bool same_boxes,std::string const & case_id,std::string const & units_str,Geometry const & geometry,Box const & expected,Box const & detected)139     static inline void check_message(bool same_boxes,
140                                      std::string const& case_id,
141                                      std::string const& units_str,
142                                      Geometry const& geometry,
143                                      Box const& expected,
144                                      Box const& detected)
145     {
146         std::ostringstream stream;
147         stream << "case ID: " << case_id << ", "
148                << "MBR units: " << units_str << "; "
149                << "geometry: ";
150 
151         write_geometry<Geometry>::apply(stream, geometry);
152 
153         stream << std::setprecision(17);
154 
155         stream << "; " << "expected: " << bg::dsv(expected)
156                << ", " << "detected: " << bg::dsv(detected);
157 
158         BOOST_CHECK_MESSAGE(same_boxes, stream.str());
159     }
160 
161     template
162     <
163         typename Geometry, typename Box,
164         typename T1, typename T2, typename T3, typename T4
165     >
check_message(bool same_boxes,std::string const & case_id,std::string const & units_str,Geometry const & geometry,T1 const & lon_min,T2 const & lat_min,double height_min,T3 const & lon_max,T4 const & lat_max,double height_max,Box const & detected)166     static inline void check_message(bool same_boxes,
167                                      std::string const& case_id,
168                                      std::string const& units_str,
169                                      Geometry const& geometry,
170                                      T1 const& lon_min, T2 const& lat_min, double height_min,
171                                      T3 const& lon_max, T4 const& lat_max, double height_max,
172                                      Box const& detected)
173     {
174         std::ostringstream stream;
175         stream << "case ID: " << case_id << ", "
176                << "MBR units: " << units_str << "; "
177                << "geometry: ";
178 
179         write_geometry<Geometry>::apply(stream, geometry);
180 
181         stream << std::setprecision(17);
182 
183         stream << "; " << "expected: ";
184 
185         if (BOOST_GEOMETRY_CONDITION(bg::dimension<Box>::value == 2))
186         {
187             stream << "(" << lon_min << " " << lat_min
188                    << ", " << lon_max << " " << lat_max << ")";
189         }
190         else
191         {
192             stream << "(" << lon_min << " " << lat_min << " " << height_min
193                    << ", " << lon_max << " " << lat_max << " " << height_max << ")";
194         }
195         stream << ", " << "detected: " << bg::dsv(detected);
196 
197         BOOST_CHECK_MESSAGE(same_boxes, stream.str());
198     }
199 
200     template
201     <
202         typename Box, typename Geometry,
203         typename T1, typename T2, typename T3, typename T4
204     >
base_test(std::string const & case_id,Geometry const & geometry,T1 const & lon_min,T2 const & lat_min,double height_min,T3 const & lon_max,T4 const & lat_max,double height_max,double tolerance)205     static inline void base_test(std::string const& case_id,
206         Geometry const& geometry,
207         T1 const& lon_min, T2 const& lat_min, double height_min,
208         T3 const& lon_max, T4 const& lat_max, double height_max,
209         double tolerance)
210     {
211         typedef typename bg::coordinate_system<Box>::type::units box_units_type;
212 
213         std::string const units_str = units2string<box_units_type>();
214 
215         Box detected;
216         test_envelope<FormulaPolicy, typename bg::cs_tag<Geometry>::type>
217             ::apply(geometry, detected);
218 
219 #ifdef BOOST_GEOMETRY_TEST_DEBUG
220         std::cout << "geometry: ";
221         write_geometry<Geometry>::apply(std::cout, geometry);
222 
223         std::cout << std::endl
224                   << "MBR units: " << units_str
225                   << std::endl;
226         std::cout << "expected: ";
227         if (BOOST_GEOMETRY_CONDITION(bg::dimension<Box>::value == 2))
228         {
229             std::cout << "(" << lon_min << " " << lat_min
230                       << ", " << lon_max << " " << lat_max << ")";
231         }
232         else
233         {
234             std::cout << "(" << lon_min << " " << lat_min << " " << height_min
235                       << ", " << lon_max << " " << lat_max << " " << height_max << ")";
236         }
237         std::cout << std::endl
238                   << "detected: " << bg::dsv(detected)
239                   << std::endl << std::endl;
240 #endif
241 
242         bool check = box_check_equals<Box>::apply(detected,
243                                                   lon_min, lat_min, height_min,
244                                                   lon_max, lat_max, height_max,
245                                                   tolerance);
246 
247         check_message(check,
248                       case_id, units_str,
249                       geometry,
250                       lon_min, lat_min, height_min,
251                       lon_max, lat_max, height_max,
252                       detected);
253 
254         // if valid box is expected, check the validity
255         if (lon_min <= lon_max && lat_min <= lat_max && height_min <= height_max)
256         {
257             BOOST_CHECK_MESSAGE(bg::index::detail::is_valid(detected),
258                                 "Case ID: " << case_id << ", "
259                              << "MBR units: " << units_str << "; "
260                              << "Invalid Box: " << bg::dsv(detected));
261         }
262     }
263 
264 public:
265     template
266     <
267         typename Geometry,
268         typename T1, typename T2, typename T3, typename T4
269     >
apply(std::string const & case_id,Geometry const & geometry,T1 const & lon_min,T2 const & lat_min,double height_min,T3 const & lon_max,T4 const & lat_max,double height_max,double tolerance)270     static inline void apply(std::string const& case_id,
271         Geometry const& geometry,
272         T1 const& lon_min, T2 const& lat_min, double height_min,
273         T3 const& lon_max, T4 const& lat_max, double height_max,
274         double tolerance)
275     {
276         typedef other_system_info
277             <
278                 typename bg::coordinate_system<MBR>::type
279             > other;
280 
281         typedef bg::model::box
282             <
283                 bg::model::point
284                     <
285                         typename bg::coordinate_type<MBR>::type,
286                         bg::dimension<MBR>::value,
287                         typename other::type
288                     >
289             > other_mbr_type;
290 
291 #ifdef BOOST_GEOMETRY_TEST_DEBUG
292         std::cout << std::endl << std::endl;
293         std::cout << "case ID: " << case_id << std::endl << std::endl;
294 #endif
295 
296         base_test<MBR>(case_id, geometry,
297                        lon_min, lat_min, height_min,
298                        lon_max, lat_max, height_max,
299                        tolerance);
300 
301         if (lon_max < lon_min)
302         {
303             // we are in the case were a special MBR is returned;
304             // makes no sense to change units
305             base_test<other_mbr_type>(case_id, geometry,
306                                       lon_min, lat_min, height_min,
307                                       lon_max, lat_max, height_max,
308                                       tolerance);
309         }
310         else
311         {
312             base_test<other_mbr_type>(case_id, geometry,
313                                       other::convert(lon_min),
314                                       other::convert(lat_min),
315                                       height_min,
316                                       other::convert(lon_max),
317                                       other::convert(lat_max),
318                                       height_max,
319                                       tolerance);
320         }
321     }
322 };
323 
324 
325 // test the reverse of a geometry if it is either linear or ring
326 template <typename Geometry, typename Tag = typename bg::tag<Geometry>::type>
327 struct test_reverse_geometry
328 {
329     static bool const is_linear =
330         boost::is_same<Tag, bg::segment_tag>::value
331         || boost::is_same<Tag, bg::linestring_tag>::value
332         || boost::is_same<Tag, bg::multi_linestring_tag>::value;
333 
334     // currently disable rings
335     static bool const is_ring = false;
336     //    static bool const is_ring = boost::is_same<Tag, bg::ring_tag>::value;
337 
338     typedef typename boost::mpl::if_c
339         <
340             is_linear || is_ring,
341             boost::true_type,
342             boost::false_type
343         >::type type;
344 
345     static bool const value = type::value;
346 };
347 
348 template
349 <
350     typename Geometry,
351     typename MBR,
352     typename Tag = typename bg::tag<Geometry>::type,
353     bool TestReverse = test_reverse_geometry<Geometry>::value,
354     typename FormulaPolicy = bg::strategy::thomas
355 >
356 struct test_envelope_on_sphere_or_spheroid
357 {
358     template <typename T1, typename T2, typename T3, typename T4,
359               typename T5, typename T6, typename T7, typename T8>
applytest_envelope_on_sphere_or_spheroid360     static inline void apply(std::string const& case_id,
361         Geometry const& geometry,
362         T1 const& lon_min1, T2 const& lat_min1, double height_min1,
363         T3 const& lon_max1, T4 const& lat_max1, double height_max1,
364         T5 const& lon_min2, T6 const& lat_min2, double height_min2,
365         T7 const& lon_max2, T8 const& lat_max2, double height_max2,
366         double tolerance = std::numeric_limits<double>::epsilon())
367     {
368         envelope_on_spheroid_basic_tester
369             <
370                 MBR, FormulaPolicy
371             >::apply(case_id, geometry,
372                      lon_min1, lat_min1, height_min1,
373                      lon_max1, lat_max1, height_max1,
374                      tolerance);
375 
376         if (BOOST_GEOMETRY_CONDITION(TestReverse))
377         {
378             std::string reversed_case_id = case_id + "-reverse";
379 
380             Geometry reversed_geometry = geometry;
381             bg::reverse(reversed_geometry);
382             envelope_on_spheroid_basic_tester
383                 <
384                     MBR, FormulaPolicy
385                 >::apply(reversed_case_id, reversed_geometry,
386                          lon_min2, lat_min2, height_min2,
387                          lon_max2, lat_max2, height_max2,
388                          tolerance);
389         }
390 
391 #ifdef BOOST_GEOMETRY_TEST_DEBUG
392         std::cout << "=================="
393                   << std::endl << std::endl;
394 #endif
395     }
396 
397     template <typename T1, typename T2, typename T3, typename T4,
398               typename T5, typename T6, typename T7, typename T8>
applytest_envelope_on_sphere_or_spheroid399     static inline void apply(std::string const& case_id,
400         Geometry const& geometry,
401         T1 const& lon_min1, T2 const& lat_min1,
402         T3 const& lon_max1, T4 const& lat_max1,
403         T5 const& lon_min2, T6 const& lat_min2,
404         T7 const& lon_max2, T8 const& lat_max2,
405         double tolerance = std::numeric_limits<double>::epsilon())
406     {
407         apply(case_id, geometry,
408               lon_min1, lat_min1, 0, lon_max1, lat_max1, 0,
409               lon_min2, lat_min2, 0, lon_max2, lat_max2, 0,
410               tolerance);
411     }
412 
413     template <typename T1, typename T2, typename T3, typename T4>
applytest_envelope_on_sphere_or_spheroid414     static inline void apply(std::string const& case_id,
415         Geometry const& geometry,
416         T1 const& lon_min, T2 const& lat_min, double height_min,
417         T3 const& lon_max, T4 const& lat_max, double height_max,
418         double tolerance = std::numeric_limits<double>::epsilon())
419     {
420         apply(case_id, geometry,
421               lon_min, lat_min, height_min,
422               lon_max, lat_max, height_max,
423               lon_min, lat_min, height_min,
424               lon_max, lat_max, height_max,
425               tolerance);
426     }
427 
428     template <typename T1, typename T2, typename T3, typename T4>
applytest_envelope_on_sphere_or_spheroid429     static inline void apply(std::string const& case_id,
430         Geometry const& geometry,
431         T1 const& lon_min, T2 const& lat_min,
432         T3 const& lon_max, T4 const& lat_max,
433         double tolerance = std::numeric_limits<double>::epsilon())
434     {
435         apply(case_id, geometry,
436               lon_min, lat_min, 0, lon_max, lat_max, 0,
437               tolerance);
438     }
439 };
440 
441 
442 // special tester for rings
443 template <typename Geometry, typename MBR, bool TestReverse>
444 struct test_envelope_on_sphere_or_spheroid<Geometry, MBR, bg::ring_tag, TestReverse>
445 {
446     template <typename T1, typename T2, typename T3, typename T4,
447               typename T5, typename T6, typename T7, typename T8>
applytest_envelope_on_sphere_or_spheroid448     static inline void apply(std::string const& case_id,
449         Geometry const& geometry,
450         T1 const& lon_min1, T2 const& lat_min1,
451         T3 const& lon_max1, T4 const& lat_max1,
452         T5 const& lon_min2, T6 const& lat_min2,
453         T7 const& lon_max2, T8 const& lat_max2,
454         double const& tolerance = std::numeric_limits<double>::epsilon())
455     {
456         envelope_on_spheroid_basic_tester
457             <
458                 MBR
459             >::apply(case_id, geometry,
460                      lon_min1, lat_min1, 0,
461                      lon_max1, lat_max1, 0,
462                      tolerance);
463 
464         std::string ccw_case_id = case_id + "-2ccw";
465 
466         bg::model::ring
467             <
468                 typename bg::point_type<Geometry>::type, false
469             > ccw_ring;
470         bg::convert(geometry, ccw_ring);
471 
472         envelope_on_spheroid_basic_tester
473             <
474                 MBR
475             >::apply(ccw_case_id, ccw_ring,
476                      lon_min2, lat_min2, 0,
477                      lon_max2, lat_max2, 0,
478                      tolerance);
479 
480 #ifdef BOOST_GEOMETRY_TEST_DEBUG
481         std::cout << "=================="
482                   << std::endl << std::endl;
483 #endif
484     }
485 
486     template <typename T1, typename T2, typename T3, typename T4>
applytest_envelope_on_sphere_or_spheroid487     static inline void apply(std::string const& case_id,
488         Geometry const& geometry,
489         T1 const& lon_min, T2 const& lat_min,
490         T3 const& lon_max, T4 const& lat_max,
491         double tolerance = std::numeric_limits<double>::epsilon())
492     {
493         apply(case_id, geometry,
494               lon_min, lat_min, lon_max, lat_max,
495               lon_min, lat_min, lon_max, lat_max,
496               tolerance);
497     }
498 };
499 
500 
501 template <typename CoordinateSystem, typename Geometry>
test_empty_geometry(std::string const & case_id,std::string const & wkt)502 void test_empty_geometry(std::string const& case_id, std::string const& wkt)
503 {
504     std::size_t const dim = bg::dimension<Geometry>::value;
505 
506     typedef bg::model::point<double, dim, CoordinateSystem> point_type;
507     typedef bg::model::box<point_type> B;
508     typedef test_envelope_on_sphere_or_spheroid<Geometry, B> tester;
509 
510     typedef typename bg::coordinate_type<Geometry>::type ct;
511     ct high_val = boost::numeric::bounds<ct>::highest();
512     ct low_val = boost::numeric::bounds<ct>::lowest();
513 
514     if (BOOST_GEOMETRY_CONDITION(dim == 2))
515     {
516         tester::apply(case_id,
517                       from_wkt<Geometry>(wkt),
518                       high_val, high_val, low_val, low_val);
519     }
520     else
521     {
522         tester::apply(case_id,
523                       from_wkt<Geometry>(wkt),
524                       high_val, high_val, high_val, low_val, low_val, low_val);
525     }
526 }
527 
528 
529 template <typename CoordinateSystem>
test_envelope_point()530 void test_envelope_point()
531 {
532     typedef bg::model::point<double, 2, CoordinateSystem> point_type;
533     typedef point_type G;
534     typedef bg::model::box<point_type> B;
535     typedef test_envelope_on_sphere_or_spheroid<G, B> tester;
536 
537     tester::apply("p01",
538                   from_wkt<G>("POINT(10 10)"),
539                   10, 10, 10, 10);
540 
541     tester::apply("p02",
542                   from_wkt<G>("POINT(370 10)"),
543                   10, 10, 10, 10);
544 
545 #ifdef BOOST_GEOMETRY_NORMALIZE_LATITUDE
546     tester::apply("p03",
547                   from_wkt<G>("POINT(370 -350)"),
548                   10, 10, 10, 10);
549 #endif
550 
551     // north and south poles
552     tester::apply("p04",
553                   from_wkt<G>("POINT(0 90)"),
554                   0, 90, 0, 90);
555 
556     tester::apply("p04a",
557                   from_wkt<G>("POINT(10 90)"),
558                   0, 90, 0, 90);
559 
560     tester::apply("p04b",
561                   from_wkt<G>("POINT(270 90)"),
562                   0, 90, 0, 90);
563 
564 #ifdef BOOST_GEOMETRY_NORMALIZE_LATITUDE
565     tester::apply("p04c",
566                   from_wkt<G>("POINT(270 450)"),
567                   0, 90, 0, 90);
568 #endif
569 
570     tester::apply("p04d",
571                   from_wkt<G>("POINT(190 90)"),
572                   0, 90, 0, 90);
573 
574     tester::apply("p04e",
575                   from_wkt<G>("POINT(-100 90)"),
576                   0, 90, 0, 90);
577 
578     tester::apply("p05",
579                   from_wkt<G>("POINT(0 -90)"),
580                   0, -90, 0, -90);
581 
582     tester::apply("p05a",
583                   from_wkt<G>("POINT(10 -90)"),
584                   0, -90, 0, -90);
585 
586     tester::apply("p05b",
587                   from_wkt<G>("POINT(270 -90)"),
588                   0, -90, 0, -90);
589 
590 #ifdef BOOST_GEOMETRY_NORMALIZE_LATITUDE
591     tester::apply("p05c",
592                   from_wkt<G>("POINT(270 -450)"),
593                   0, -90, 0, -90);
594 #endif
595 
596     tester::apply("p05d",
597                   from_wkt<G>("POINT(190 -90)"),
598                   0, -90, 0, -90);
599 
600     tester::apply("p05e",
601                   from_wkt<G>("POINT(-100 -90)"),
602                   0, -90, 0, -90);
603 
604     tester::apply("p05f",
605                   from_wkt<G>("POINT(-100 -90)"),
606                   0, -90, 0, -90);
607 }
608 
BOOST_AUTO_TEST_CASE(envelope_point)609 BOOST_AUTO_TEST_CASE( envelope_point )
610 {
611     test_envelope_point<bg::cs::spherical_equatorial<bg::degree> >();
612     test_envelope_point<bg::cs::geographic<bg::degree> >();
613 }
614 
615 
616 template <typename CoordinateSystem>
test_envelope_point_with_height()617 void test_envelope_point_with_height()
618 {
619     typedef bg::model::point<double, 3, CoordinateSystem> point_type;
620     typedef point_type G;
621     typedef bg::model::box<point_type> B;
622     typedef test_envelope_on_sphere_or_spheroid<G, B> tester;
623 
624     tester::apply("ph01",
625                   from_wkt<G>("POINT(10 10 1256)"),
626                   10, 10, 1256, 10, 10, 1256);
627 }
628 
BOOST_AUTO_TEST_CASE(envelope_point_with_height)629 BOOST_AUTO_TEST_CASE( envelope_point_with_height )
630 {
631     test_envelope_point_with_height
632         <
633             bg::cs::spherical_equatorial<bg::degree>
634         >();
635     test_envelope_point_with_height<bg::cs::geographic<bg::degree> >();
636 }
637 
638 
BOOST_AUTO_TEST_CASE(envelope_segment_sphere)639 BOOST_AUTO_TEST_CASE( envelope_segment_sphere )
640 {
641     typedef bg::cs::spherical_equatorial<bg::degree> coordinate_system_type;
642     typedef bg::model::point<double, 2, coordinate_system_type> P;
643     typedef bg::model::segment<P> G;
644     typedef bg::model::box<P> B;
645     typedef test_envelope_on_sphere_or_spheroid<G, B> tester;
646 
647     double const eps = std::numeric_limits<double>::epsilon();
648 
649     tester::apply("s01",
650                   from_wkt<G>("SEGMENT(10 10,40 40)"),
651                   10, 10, 40, 40);
652 
653     tester::apply("s02",
654                   from_wkt<G>("SEGMENT(10 10,40 10)"),
655                   10, 10, 40, 10.345270046149988);
656 /*
657     tester::apply("s02",
658                   from_wkt<G>("SEGMENT(1 2,70 1)"),
659                   1, 1, 70, 2.01);
660 */
661     tester::apply("s02a",
662                   from_wkt<G>("SEGMENT(40 10,10 10)"),
663                   10, 10, 40, 10.34527004614999);
664 
665     tester::apply("s03",
666                   from_wkt<G>("SEGMENT(160 10,-170 10)"),
667                   160, 10, 190, 10.34527004614999);
668 
669     tester::apply("s03a",
670                   from_wkt<G>("SEGMENT(-170 10,160 10)"),
671                   160, 10, 190, 10.34527004614999);
672 
673     tester::apply("s03b",
674                   from_wkt<G>("SEGMENT(-170 -10,160 -10)"),
675                   160,  -10.34527004614999, 190, -10);
676 
677     tester::apply("s04",
678                   from_wkt<G>("SEGMENT(-40 45,140 60)"),
679                   -40, 45, 140, 90);
680 
681     tester::apply("s04a",
682                   from_wkt<G>("SEGMENT(-40 45,140 25)"),
683                   -40, 25, 140, 90);
684 
685     // segment ending at the north pole
686     tester::apply("s05",
687                   from_wkt<G>("SEGMENT(40 45,80 90)"),
688                   40, 45, 40, 90);
689 
690     // segment starting at the north pole
691     tester::apply("s05a",
692                   from_wkt<G>("SEGMENT(80 90,40 45)"),
693                   40, 45, 40, 90);
694 
695     // segment ending at the north pole
696     tester::apply("s06",
697                   from_wkt<G>("SEGMENT(-40 45,80 90)"),
698                   -40, 45, -40, 90);
699 
700     // segment starting at the north pole
701     tester::apply("s06a",
702                   from_wkt<G>("SEGMENT(70 90,-40 45)"),
703                   -40, 45, -40, 90);
704 
705     // segment ending at the north pole
706     tester::apply("s07",
707                   from_wkt<G>("SEGMENT(40 -45,80 90)"),
708                   40, -45, 40, 90);
709 
710     // segment passing through the south pole
711     tester::apply("s08",
712                   from_wkt<G>("SEGMENT(-170 -45,10 -30)"),
713                   -170, -90, 10, -30);
714 
715     tester::apply("s09",
716                   from_wkt<G>("SEGMENT(1 -45,179 30)"),
717                   1, -85.28884376852969, 179, 30,
718                   3 * eps);
719 
720     tester::apply("s09a",
721                   from_wkt<G>("SEGMENT(2 -45,181 30)"),
722                   2, -87.63659983704832, 181, 30);
723 
724     // very long segment
725     tester::apply("s10",
726                   from_wkt<G>("SEGMENT(0 -45,181 30)"),
727                   -179, -87.636599837048323, 0, 30,
728                   2.0 * eps);
729 
730     tester::apply("s11",
731                   from_wkt<G>("SEGMENT(260 30,20 45)"),
732                   -100, 30, 20, 57.93195594009233);
733 
734     tester::apply("s11a",
735                   from_wkt<G>("SEGMENT(260 45,20 30)"),
736                   -100, 30, 20, 57.931955940092337);
737 
738     // segment degenerating to the north pole
739     tester::apply("s12",
740                   from_wkt<G>("SEGMENT(10 90,20 90)"),
741                   0, 90, 0, 90);
742 
743     // segment degenerating to the south pole
744     tester::apply("s13",
745                   from_wkt<G>("SEGMENT(10 -90,20 -90)"),
746                   0, -90, 0, -90);
747 
748     tester::apply("s14",
749                   from_wkt<G>("SEGMENT(20 20,10 30)"),
750                   10, 20, 20, 30);//48.87458730907602);
751 
752     tester::apply("s15",
753                   from_wkt<G>("SEGMENT(50 45,185 45)"),
754                   50, 45, 185, 69.05897952775615);
755 
756     // segment that lies on the equator
757     tester::apply("s16",
758                   from_wkt<G>("SEGMENT(0 0,50 0)"),
759                   0, 0, 50, 0);
760 
761     // segment that lies on the equator
762     tester::apply("s16a",
763                   from_wkt<G>("SEGMENT(-50 0,50 0)"),
764                   -50, 0, 50, 0);
765 
766     // segment that lies on the equator and touches antimeridian
767     tester::apply("s16b",
768                   from_wkt<G>("SEGMENT(50 0,180 0)"),
769                   50, 0, 180, 0);
770 
771     // segment that lies on the equator and crosses antimeridian
772     tester::apply("s16c",
773                   from_wkt<G>("SEGMENT(-170 0,160 0)"),
774                   160, 0, 190, 0);
775 
776     tester::apply("s17",
777                   from_wkt<G>("SEGMENT(140 10, -140 80)"),
778                   140, 10, 220, 80);
779 
780     tester::apply("s17-r",
781                   from_wkt<G>("SEGMENT(-140 80, 140 10)"),
782                   140, 10, 220, 80);
783 
784     tester::apply("s18",
785                   from_wkt<G>("SEGMENT(20 10, 100 80)"),
786                   20, 10, 100, 80);
787 
788     tester::apply("s18-r",
789                   from_wkt<G>("SEGMENT(100 80, 20 10)"),
790                   20, 10, 100, 80);
791 
792     // segment connecting the north and south pole
793     //
794     // this should be forbidden actually, as it is not well-defined
795     // with this test we demonstrate that the algorithm still returns
796     // something meaningful
797     tester::apply("s99",
798                   from_wkt<G>("SEGMENT(10 90,20 -90)"),
799                   0, -90, 0, 90);
800 
801     // https://svn.boost.org/trac/boost/ticket/12106
802     tester::apply("s100_ticket_12106",
803                   G(P(11.488323611111111, 53.687086666666673), P(11.488324166666667, 53.687086666666673)),
804                   11.488323611111111, 53.687086666666673, 11.488324166666667, 53.687086666666673);
805 
806     double const heps = eps / 2;
807 
808     tester::apply("s101",
809                   G(P(1, 1), P(1-heps, 1-heps)),
810                   1-heps, 1-heps, 1, 1);
811     tester::apply("s102",
812                   G(P(1, 1), P(1, 1-heps)),
813                   1, 1-heps, 1, 1);
814     tester::apply("s103",
815                   G(P(1, 1), P(1-heps, 1)),
816                   1-heps, 1, 1, 1);
817     tester::apply("s104",
818                   G(P(2, 1), P(1, 1-heps)),
819                   1, 1-heps, 2, 1.000038070652770505);
820     tester::apply("s105",
821                   G(P(1, 2), P(1-heps, 1)),
822                   1-heps, 1, 1, 2);
823 }
824 
BOOST_AUTO_TEST_CASE(envelope_segment_spherical_polar)825 BOOST_AUTO_TEST_CASE( envelope_segment_spherical_polar )
826 {
827     typedef bg::cs::spherical<bg::degree> coordinate_system_type;
828     typedef bg::model::point<double, 2, coordinate_system_type> P;
829     typedef bg::model::segment<P> G;
830     typedef bg::model::box<P> B;
831     typedef test_envelope_on_sphere_or_spheroid<G, B> tester;
832 
833     tester::apply("s01",
834                   from_wkt<G>("SEGMENT(10 10,40 40)"),
835                   10, 10, 40, 40);
836 
837     tester::apply("s02",
838                   from_wkt<G>("SEGMENT(10 80,40 80)"),
839                   10, 90 - 10.345270046149988, 40, 80);
840 
841     tester::apply("s03",
842                   from_wkt<G>("SEGMENT(160 80,-170 80)"),
843                   160, 90 - 10.34527004614999, 190, 80);
844 
845     // segment ending at the north pole
846     tester::apply("s05",
847                   from_wkt<G>("SEGMENT(40 45,80 0)"),
848                   40, 0, 40, 45);
849 }
850 
851 
BOOST_AUTO_TEST_CASE(envelope_segment_spheroid)852 BOOST_AUTO_TEST_CASE( envelope_segment_spheroid )
853 {
854     typedef bg::cs::geographic<bg::degree> coordinate_system_type;
855     typedef bg::model::point<double, 2, coordinate_system_type> P;
856     typedef bg::model::segment<P> G;
857     typedef bg::model::box<P> B;
858     typedef test_envelope_on_sphere_or_spheroid<G, B> tester;
859 
860     double const eps = std::numeric_limits<double>::epsilon();
861 
862     tester::apply("s01",
863                   from_wkt<G>("SEGMENT(10 10,40 40)"),
864                   10, 10, 40, 40);
865 
866     tester::apply("s02",
867                   from_wkt<G>("SEGMENT(10 10,40 10)"),
868                   10, 10, 40, 10.347587605817942);
869 
870     tester::apply("s02a",
871                   from_wkt<G>("SEGMENT(40 10,10 10)"),
872                   10, 10, 40, 10.347587605817942);
873 
874     tester::apply("s03",
875                   from_wkt<G>("SEGMENT(160 10,-170 10)"),
876                   160, 10, 190, 10.347587605817942);
877 
878     tester::apply("s03a",
879                   from_wkt<G>("SEGMENT(-170 10,160 10)"),
880                   160, 10, 190, 10.347587605817942);
881 
882     tester::apply("s03b",
883                   from_wkt<G>("SEGMENT(-170 -10,160 -10)"),
884                   160,  -10.347587605817942, 190, -10);
885 
886     tester::apply("s04",
887                   from_wkt<G>("SEGMENT(-40 45,140 60)"),
888                   -40, 45, 140, 90);
889 
890     tester::apply("s04a",
891                   from_wkt<G>("SEGMENT(-40 45,140 25)"),
892                   -40, 25, 140, 90);
893 
894     // segment ending at the north pole
895     tester::apply("s05",
896                   from_wkt<G>("SEGMENT(40 45,80 90)"),
897                   40, 45, 40, 90);
898 
899     // segment starting at the north pole
900     tester::apply("s05a",
901                   from_wkt<G>("SEGMENT(80 90,40 45)"),
902                   40, 45, 40, 90);
903 
904     // segment ending at the north pole
905     tester::apply("s06",
906                   from_wkt<G>("SEGMENT(-40 45,80 90)"),
907                   -40, 45, -40, 90);
908 
909     // segment starting at the north pole
910     tester::apply("s06a",
911                   from_wkt<G>("SEGMENT(70 90,-40 45)"),
912                   -40, 45, -40, 90);
913 
914     // segment ending at the north pole
915     tester::apply("s07",
916                   from_wkt<G>("SEGMENT(40 -45,80 90)"),
917                   40, -45, 40, 90);
918 
919     // segment passing through the south pole
920     tester::apply("s08",
921                   from_wkt<G>("SEGMENT(-170 -45,10 -30)"),
922                   -170, -90, 10, -30);
923 
924     tester::apply("s09",
925                   from_wkt<G>("SEGMENT(1 -45,179 30)"),
926                   1, rng(-85.392785243526134, -85.392785243525253), 179, 30);
927 
928     tester::apply("s09a",
929                   from_wkt<G>("SEGMENT(2 -45,181 30)"),
930                   2, rng(-87.689300911353811, -87.689300911353371), 181, 30);
931 
932     // very long segment
933     tester::apply("s10",
934                   from_wkt<G>("SEGMENT(0 -45,181 30)"),
935                   -179, rng(-87.689300911353797, -87.689300911353385), 0, 30);
936 
937     tester::apply("s11",
938                   from_wkt<G>("SEGMENT(260 30,20 45)"),
939                   -100, 30, 20, rng(57.990810958016482, 57.990810958016965));
940 
941     tester::apply("s11a",
942                   from_wkt<G>("SEGMENT(260 45,20 30)"),
943                   -100, 30, 20, rng(57.990810958016453, 57.990810958016965));
944 
945     // segment degenerating to the north pole
946     tester::apply("s12",
947                   from_wkt<G>("SEGMENT(10 90,20 90)"),
948                   0, 90, 0, 90);
949 
950     // segment degenerating to the south pole
951     tester::apply("s13",
952                   from_wkt<G>("SEGMENT(10 -90,20 -90)"),
953                   0, -90, 0, -90);
954 
955     tester::apply("s14",
956                   from_wkt<G>("SEGMENT(20 20,10 30)"),
957                   10, 20, 20, 30);//48.87458730907602);
958 
959     tester::apply("s15",
960                   from_wkt<G>("SEGMENT(50 45,185 45)"),
961                   50, 45, 185, rng(69.098479073902851, 69.098479073903178));
962 
963     // segment that lies on the equator
964     tester::apply("s16",
965                   from_wkt<G>("SEGMENT(0 0,50 0)"),
966                   0, 0, 50, 0);
967 
968     // segment that lies on the equator
969     tester::apply("s16a",
970                   from_wkt<G>("SEGMENT(-50 0,50 0)"),
971                   -50, 0, 50, 0);
972 
973     // segment that lies on the equator and touches antimeridian
974     tester::apply("s16b",
975                   from_wkt<G>("SEGMENT(50 0,180 0)"),
976                   50, 0, 180, 0);
977 
978     // segment that lies on the equator and crosses antimeridian
979     tester::apply("s16c",
980                   from_wkt<G>("SEGMENT(-170 0,160 0)"),
981                   160, 0, 190, 0);
982 
983     tester::apply("s17",
984                   from_wkt<G>("SEGMENT(140 10, -140 80)"),
985                   140, 10, 220, 80);
986 
987     tester::apply("s17-r",
988                   from_wkt<G>("SEGMENT(-140 80, 140 10)"),
989                   140, 10, 220, 80);
990 
991     tester::apply("s18",
992                   from_wkt<G>("SEGMENT(20 10, 100 80)"),
993                   20, 10, 100, 80);
994 
995     tester::apply("s18-r",
996                   from_wkt<G>("SEGMENT(100 80, 20 10)"),
997                   20, 10, 100, 80);
998 
999     // segment connecting the north and south pole
1000     //
1001     // this should be forbidden actually, as it is not well-defined
1002     // with this test we demonstrate that the algorithm still returns
1003     // something meaningful
1004     tester::apply("s99",
1005                   from_wkt<G>("SEGMENT(10 90,20 -90)"),
1006                   0, -90, 0, 90);
1007 
1008     // https://svn.boost.org/trac/boost/ticket/12106
1009     tester::apply("s100_ticket_12106",
1010                   G(P(11.488323611111111, 53.687086666666673), P(11.488324166666667, 53.687086666666673)),
1011                   11.488323611111111, 53.687086666666673, 11.488324166666667, 53.687086666666673);
1012 
1013     double const heps = eps / 2;
1014 
1015     tester::apply("s101",
1016                   G(P(1, 1), P(1-heps, 1-heps)),
1017                   1-heps, 1-heps, 1, 1);
1018     tester::apply("s102",
1019                   G(P(1, 1), P(1, 1-heps)),
1020                   1, 1-heps, 1, 1);
1021     tester::apply("s103",
1022                   G(P(1, 1), P(1-heps, 1)),
1023                   1-heps, 1, 1, 1);
1024     tester::apply("s104",
1025                   G(P(2, 1), P(1, 1-heps)),
1026                   1, 1-heps, 2, rng(1.0000383271568751, 1.0000383271569036));
1027     tester::apply("s105",
1028                   G(P(1, 2), P(1-heps, 1)),
1029                   1-heps, 1, 1, 2);
1030 }
1031 
BOOST_AUTO_TEST_CASE(envelope_segment_spheroid_with_strategy_thomas)1032 BOOST_AUTO_TEST_CASE( envelope_segment_spheroid_with_strategy_thomas )
1033 {
1034 
1035     typedef bg::cs::geographic<bg::degree> coordinate_system_type;
1036     typedef bg::model::point<double, 2, coordinate_system_type> P;
1037     typedef bg::model::segment<P> G;
1038     typedef bg::model::box<P> B;
1039     typedef test_envelope_on_sphere_or_spheroid
1040                           <
1041                             G, B,
1042                             bg::tag<G>::type,
1043                             test_reverse_geometry<G>::value,
1044                             bg::strategy::thomas
1045                           > tester;
1046 
1047     tester::apply("s01",
1048                   from_wkt<G>("SEGMENT(10 10,40 40)"),
1049                   10, 10, 40, 40);
1050 
1051     tester::apply("s02",
1052                   from_wkt<G>("SEGMENT(10 10,40 10)"),
1053                   10, 10, 40, 10.347587605817942);
1054 
1055     tester::apply("s02a",
1056                   from_wkt<G>("SEGMENT(40 10,10 10)"),
1057                   10, 10, 40, 10.347587605817942);
1058 
1059     tester::apply("s03",
1060                   from_wkt<G>("SEGMENT(160 10,-170 10)"),
1061                   160, 10, 190, 10.347587605817942);
1062 
1063     tester::apply("s03a",
1064                   from_wkt<G>("SEGMENT(-170 10,160 10)"),
1065                   160, 10, 190, 10.347587605817942);
1066 
1067     tester::apply("s03b",
1068                   from_wkt<G>("SEGMENT(-170 -10,160 -10)"),
1069                   160,  -10.347587605817942, 190, -10);
1070 
1071     tester::apply("s04",
1072                   from_wkt<G>("SEGMENT(-40 45,140 60)"),
1073                   -40, 45, 140, 90);
1074 
1075     tester::apply("s04a",
1076                   from_wkt<G>("SEGMENT(-40 45,140 25)"),
1077                   -40, 25, 140, 90);
1078 
1079     // segment ending at the north pole
1080     tester::apply("s05",
1081                   from_wkt<G>("SEGMENT(40 45,80 90)"),
1082                   40, 45, 40, 90);
1083 
1084     // segment starting at the north pole
1085     tester::apply("s05a",
1086                   from_wkt<G>("SEGMENT(80 90,40 45)"),
1087                   40, 45, 40, 90);
1088 
1089     // segment ending at the north pole
1090     tester::apply("s06",
1091                   from_wkt<G>("SEGMENT(-40 45,80 90)"),
1092                   -40, 45, -40, 90);
1093 
1094     // segment starting at the north pole
1095     tester::apply("s06a",
1096                   from_wkt<G>("SEGMENT(70 90,-40 45)"),
1097                   -40, 45, -40, 90);
1098 
1099     // segment ending at the north pole
1100     tester::apply("s07",
1101                   from_wkt<G>("SEGMENT(40 -45,80 90)"),
1102                   40, -45, 40, 90);
1103 
1104     // segment passing through the south pole
1105     tester::apply("s08",
1106                   from_wkt<G>("SEGMENT(-170 -45,10 -30)"),
1107                   -170, -90, 10, -30);
1108 
1109     tester::apply("s09",
1110                   from_wkt<G>("SEGMENT(1 -45,179 30)"),
1111                   1, rng(-85.392785243526134, -85.392785243525253), 179, 30);
1112 
1113     tester::apply("s09a",
1114                   from_wkt<G>("SEGMENT(2 -45,181 30)"),
1115                   2, rng(-87.689300911353811, -87.689300911353371), 181, 30);
1116 
1117     // very long segment
1118     tester::apply("s10",
1119                   from_wkt<G>("SEGMENT(0 -45,181 30)"),
1120                   -179, rng(-87.689300911353797, -87.689300911353385), 0, 30);
1121 
1122     tester::apply("s11",
1123                   from_wkt<G>("SEGMENT(260 30,20 45)"),
1124                   -100, 30, 20, rng(57.990810958016482, 57.990810958016965));
1125 
1126     tester::apply("s11a",
1127                   from_wkt<G>("SEGMENT(260 45,20 30)"),
1128                   -100, 30, 20, rng(57.990810958016453, 57.990810958016965));
1129 
1130     // segment degenerating to the north pole
1131     tester::apply("s12",
1132                   from_wkt<G>("SEGMENT(10 90,20 90)"),
1133                   0, 90, 0, 90);
1134 
1135     // segment degenerating to the south pole
1136     tester::apply("s13",
1137                   from_wkt<G>("SEGMENT(10 -90,20 -90)"),
1138                   0, -90, 0, -90);
1139 
1140     tester::apply("s14",
1141                   from_wkt<G>("SEGMENT(20 20,10 30)"),
1142                   10, 20, 20, 30);//48.87458730907602);
1143 
1144     tester::apply("s15",
1145                   from_wkt<G>("SEGMENT(50 45,185 45)"),
1146                   50, 45, 185, rng(69.098479073902851, 69.098479073903178));
1147 
1148     // segment that lies on the equator
1149     tester::apply("s16",
1150                   from_wkt<G>("SEGMENT(0 0,50 0)"),
1151                   0, 0, 50, 0);
1152 
1153     // segment that lies on the equator
1154     tester::apply("s16a",
1155                   from_wkt<G>("SEGMENT(-50 0,50 0)"),
1156                   -50, 0, 50, 0);
1157 
1158     // segment that lies on the equator and touches antimeridian
1159     tester::apply("s16b",
1160                   from_wkt<G>("SEGMENT(50 0,180 0)"),
1161                   50, 0, 180, 0);
1162 
1163     // segment that lies on the equator and crosses antimeridian
1164     tester::apply("s16c",
1165                   from_wkt<G>("SEGMENT(-170 0,160 0)"),
1166                   160, 0, 190, 0);
1167 
1168     tester::apply("s17",
1169                   from_wkt<G>("SEGMENT(140 10, -140 80)"),
1170                   140, 10, 220, 80);
1171 
1172     tester::apply("s17-r",
1173                   from_wkt<G>("SEGMENT(-140 80, 140 10)"),
1174                   140, 10, 220, 80);
1175 
1176     tester::apply("s18",
1177                   from_wkt<G>("SEGMENT(20 10, 100 80)"),
1178                   20, 10, 100, 80);
1179 
1180     tester::apply("s18-r",
1181                   from_wkt<G>("SEGMENT(100 80, 20 10)"),
1182                   20, 10, 100, 80);
1183 
1184 }
1185 
BOOST_AUTO_TEST_CASE(envelope_segment_spheroid_with_strategy_andoyer)1186 BOOST_AUTO_TEST_CASE( envelope_segment_spheroid_with_strategy_andoyer )
1187 {
1188 
1189     typedef bg::cs::geographic<bg::degree> coordinate_system_type;
1190     typedef bg::model::point<double, 2, coordinate_system_type> P;
1191     typedef bg::model::segment<P> G;
1192     typedef bg::model::box<P> B;
1193     typedef test_envelope_on_sphere_or_spheroid
1194                           <
1195                             G, B,
1196                             bg::tag<G>::type,
1197                             test_reverse_geometry<G>::value,
1198                             bg::strategy::andoyer
1199                           > tester;
1200 
1201     tester::apply("s01",
1202                   from_wkt<G>("SEGMENT(10 10,40 40)"),
1203                   10, 10, 40, 40);
1204 
1205     tester::apply("s02",
1206                   from_wkt<G>("SEGMENT(10 10,40 10)"),
1207                   10, 10, 40, 10.34758709960203);
1208 
1209     tester::apply("s02a",
1210                   from_wkt<G>("SEGMENT(40 10,10 10)"),
1211                   10, 10, 40, 10.34758709960203);
1212 
1213     tester::apply("s03",
1214                   from_wkt<G>("SEGMENT(160 10,-170 10)"),
1215                   160, 10, 190, 10.34758709960203);
1216 
1217     tester::apply("s03a",
1218                   from_wkt<G>("SEGMENT(-170 10,160 10)"),
1219                   160, 10, 190, 10.34758709960203);
1220 
1221     tester::apply("s03b",
1222                   from_wkt<G>("SEGMENT(-170 -10,160 -10)"),
1223                   160,  -10.34758709960203, 190, -10);
1224 
1225     tester::apply("s04",
1226                   from_wkt<G>("SEGMENT(-40 45,140 60)"),
1227                   -40, 45, 140, 90);
1228 
1229     tester::apply("s04a",
1230                   from_wkt<G>("SEGMENT(-40 45,140 25)"),
1231                   -40, 25, 140, 90);
1232 
1233     // segment ending at the north pole
1234     tester::apply("s05",
1235                   from_wkt<G>("SEGMENT(40 45,80 90)"),
1236                   40, 45, 40, 90);
1237 
1238     // segment starting at the north pole
1239     tester::apply("s05a",
1240                   from_wkt<G>("SEGMENT(80 90,40 45)"),
1241                   40, 45, 40, 90);
1242 
1243     // segment ending at the north pole
1244     tester::apply("s06",
1245                   from_wkt<G>("SEGMENT(-40 45,80 90)"),
1246                   -40, 45, -40, 90);
1247 
1248     // segment starting at the north pole
1249     tester::apply("s06a",
1250                   from_wkt<G>("SEGMENT(70 90,-40 45)"),
1251                   -40, 45, -40, 90);
1252 
1253     // segment ending at the north pole
1254     tester::apply("s07",
1255                   from_wkt<G>("SEGMENT(40 -45,80 90)"),
1256                   40, -45, 40, 90);
1257 
1258     // segment passing through the south pole
1259     tester::apply("s08",
1260                   from_wkt<G>("SEGMENT(-170 -45,10 -30)"),
1261                   -170, -90, 10, -30);
1262 
1263     tester::apply("s09",
1264                   from_wkt<G>("SEGMENT(1 -45,179 30)"),
1265                   1, rng(-85.394745211091248, -85.394745211090353), 179, 30);
1266 
1267     tester::apply("s09a",
1268                   from_wkt<G>("SEGMENT(2 -45,181 30)"),
1269                   2, rng(-87.690317839849726, -87.690317839849271), 181, 30);
1270 
1271     // very long segment
1272     tester::apply("s10",
1273                   from_wkt<G>("SEGMENT(0 -45,181 30)"),
1274                   -179, rng(-87.69031783984974, -87.690317839849271), 0, 30);
1275 
1276     tester::apply("s11",
1277                   from_wkt<G>("SEGMENT(260 30,20 45)"),
1278                   -100, 30, 20, rng(57.990742552279649, 57.990742552280153));
1279 
1280     tester::apply("s11a",
1281                   from_wkt<G>("SEGMENT(260 45,20 30)"),
1282                   -100, 30, 20, rng(57.99074255227962, 57.990742552280118));
1283 
1284     // segment degenerating to the north pole
1285     tester::apply("s12",
1286                   from_wkt<G>("SEGMENT(10 90,20 90)"),
1287                   0, 90, 0, 90);
1288 
1289     // segment degenerating to the south pole
1290     tester::apply("s13",
1291                   from_wkt<G>("SEGMENT(10 -90,20 -90)"),
1292                   0, -90, 0, -90);
1293 
1294     tester::apply("s14",
1295                   from_wkt<G>("SEGMENT(20 20,10 30)"),
1296                   10, 20, 20, 30);//48.87458730907602);
1297 
1298     tester::apply("s15",
1299                   from_wkt<G>("SEGMENT(50 45,185 45)"),
1300                   50, 45, 185, rng(69.098446893408124, 69.09844689340845));
1301 
1302     // segment that lies on the equator
1303     tester::apply("s16",
1304                   from_wkt<G>("SEGMENT(0 0,50 0)"),
1305                   0, 0, 50, 0);
1306 
1307     // segment that lies on the equator
1308     tester::apply("s16a",
1309                   from_wkt<G>("SEGMENT(-50 0,50 0)"),
1310                   -50, 0, 50, 0);
1311 
1312     // segment that lies on the equator and touches antimeridian
1313     tester::apply("s16b",
1314                   from_wkt<G>("SEGMENT(50 0,180 0)"),
1315                   50, 0, 180, 0);
1316 
1317     // segment that lies on the equator and crosses antimeridian
1318     tester::apply("s16c",
1319                   from_wkt<G>("SEGMENT(-170 0,160 0)"),
1320                   160, 0, 190, 0);
1321 
1322     tester::apply("s17",
1323                   from_wkt<G>("SEGMENT(140 10, -140 80)"),
1324                   140, 10, 220, 80);
1325 
1326     tester::apply("s17-r",
1327                   from_wkt<G>("SEGMENT(-140 80, 140 10)"),
1328                   140, 10, 220, 80);
1329 
1330     tester::apply("s18",
1331                   from_wkt<G>("SEGMENT(20 10, 100 80)"),
1332                   20, 10, 100, 80);
1333 
1334     tester::apply("s18-r",
1335                   from_wkt<G>("SEGMENT(100 80, 20 10)"),
1336                   20, 10, 100, 80);
1337 
1338     // segments intersecting pole
1339     tester::apply("s19",
1340                   from_wkt<G>("SEGMENT(0 0, 180 0)"),
1341                   0, 0, 180, 90);
1342     tester::apply("s20",
1343                   from_wkt<G>("SEGMENT(0 0, -180 0)"),
1344                   0, 0, 180, 90);
1345     tester::apply("s21",
1346                   from_wkt<G>("SEGMENT(0 1, 180 1)"),
1347                   0, 1, 180, 90,
1348                   std::numeric_limits<double>::epsilon() * 10);
1349     tester::apply("s22",
1350                   from_wkt<G>("SEGMENT(0 -1, 180 -1)"),
1351                   0, -90, 180, -1,
1352                   std::numeric_limits<double>::epsilon() * 10);
1353 
1354 }
1355 
BOOST_AUTO_TEST_CASE(envelope_segment_spheroid_with_strategy_vincenty)1356 BOOST_AUTO_TEST_CASE( envelope_segment_spheroid_with_strategy_vincenty )
1357 {
1358 
1359     typedef bg::cs::geographic<bg::degree> coordinate_system_type;
1360     typedef bg::model::point<double, 2, coordinate_system_type> P;
1361     typedef bg::model::segment<P> G;
1362     typedef bg::model::box<P> B;
1363     typedef test_envelope_on_sphere_or_spheroid
1364                           <
1365                             G, B,
1366                             bg::tag<G>::type,
1367                             test_reverse_geometry<G>::value,
1368                             bg::strategy::vincenty
1369                           > tester;
1370 
1371     tester::apply("s01",
1372                   from_wkt<G>("SEGMENT(10 10,40 40)"),
1373                   10, 10, 40, 40);
1374 
1375     tester::apply("s02",
1376                   from_wkt<G>("SEGMENT(10 10,40 10)"),
1377                   10, 10, 40, rng(10.347587628821937, 10.347587628821941));
1378 
1379     tester::apply("s02a",
1380                   from_wkt<G>("SEGMENT(40 10,10 10)"),
1381                   10, 10, 40, rng(10.347587628821937, 10.347587628821941));
1382 
1383     tester::apply("s03",
1384                   from_wkt<G>("SEGMENT(160 10,-170 10)"),
1385                   160, 10, 190, rng(10.347587628821937, 10.347587628821941));
1386 
1387     tester::apply("s03a",
1388                   from_wkt<G>("SEGMENT(-170 10,160 10)"),
1389                   160, 10, 190, rng(10.347587628821937, 10.347587628821941));
1390 
1391     tester::apply("s03b",
1392                   from_wkt<G>("SEGMENT(-170 -10,160 -10)"),
1393                   160, rng(-10.347587628821941, -10.347587628821937), 190, -10);
1394 
1395     tester::apply("s04",
1396                   from_wkt<G>("SEGMENT(-40 45,140 60)"),
1397                   -40, 45, 140, 90);
1398 
1399     tester::apply("s04a",
1400                   from_wkt<G>("SEGMENT(-40 45,140 25)"),
1401                   -40, 25, 140, 90);
1402 
1403     // segment ending at the north pole
1404     tester::apply("s05",
1405                   from_wkt<G>("SEGMENT(40 45,80 90)"),
1406                   40, 45, 40, 90);
1407 
1408     // segment starting at the north pole
1409     tester::apply("s05a",
1410                   from_wkt<G>("SEGMENT(80 90,40 45)"),
1411                   40, 45, 40, 90);
1412 
1413     // segment ending at the north pole
1414     tester::apply("s06",
1415                   from_wkt<G>("SEGMENT(-40 45,80 90)"),
1416                   -40, 45, -40, 90);
1417 
1418     // segment starting at the north pole
1419     tester::apply("s06a",
1420                   from_wkt<G>("SEGMENT(70 90,-40 45)"),
1421                   -40, 45, -40, 90);
1422 
1423     // segment ending at the north pole
1424     tester::apply("s07",
1425                   from_wkt<G>("SEGMENT(40 -45,80 90)"),
1426                   40, -45, 40, 90);
1427 
1428     // segment passing through the south pole
1429     tester::apply("s08",
1430                   from_wkt<G>("SEGMENT(-170 -45,10 -30)"),
1431                   -170, -90, 10, -30);
1432 
1433     tester::apply("s09",
1434                   from_wkt<G>("SEGMENT(1 -45,179 30)"),
1435                   1, rng(-85.392840929577218, -85.392840929576352), 179, 30);
1436 
1437     tester::apply("s09a",
1438                   from_wkt<G>("SEGMENT(2 -45,181 30)"),
1439                   2, rng(-87.689330275867817, -87.689330275867405), 181, 30);
1440 
1441     // very long segment
1442     tester::apply("s10",
1443                   from_wkt<G>("SEGMENT(0 -45,181 30)"),
1444                   -179, rng(-87.689330275867832, -87.689330275867405), 0, 30);
1445 
1446     tester::apply("s11",
1447                   from_wkt<G>("SEGMENT(260 30,20 45)"),
1448                   -100, 30, 20, rng(57.990810647056549, 57.990810647057032));
1449 
1450     tester::apply("s11a",
1451                   from_wkt<G>("SEGMENT(260 45,20 30)"),
1452                   -100, 30, 20, rng(57.990810647056541, 57.990810647057032));
1453 
1454     // segment degenerating to the north pole
1455     tester::apply("s12",
1456                   from_wkt<G>("SEGMENT(10 90,20 90)"),
1457                   0, 90, 0, 90);
1458 
1459     // segment degenerating to the south pole
1460     tester::apply("s13",
1461                   from_wkt<G>("SEGMENT(10 -90,20 -90)"),
1462                   0, -90, 0, -90);
1463 
1464     tester::apply("s14",
1465                   from_wkt<G>("SEGMENT(20 20,10 30)"),
1466                   10, 20, 20, 30);//48.87458730907602);
1467 
1468     tester::apply("s15",
1469                   from_wkt<G>("SEGMENT(50 45,185 45)"),
1470                   50, 45, 185, rng(69.098479136978156, 69.098479136978497));
1471 
1472     // segment that lies on the equator
1473     tester::apply("s16",
1474                   from_wkt<G>("SEGMENT(0 0,50 0)"),
1475                   0, 0, 50, 0);
1476 
1477     // segment that lies on the equator
1478     tester::apply("s16a",
1479                   from_wkt<G>("SEGMENT(-50 0,50 0)"),
1480                   -50, 0, 50, 0);
1481 
1482     // segment that lies on the equator and touches antimeridian
1483     tester::apply("s16b",
1484                   from_wkt<G>("SEGMENT(50 0,180 0)"),
1485                   50, 0, 180, 0);
1486 
1487     // segment that lies on the equator and crosses antimeridian
1488     tester::apply("s16c",
1489                   from_wkt<G>("SEGMENT(-170 0,160 0)"),
1490                   160, 0, 190, 0);
1491 
1492     tester::apply("s17",
1493                   from_wkt<G>("SEGMENT(140 10, -140 80)"),
1494                   140, 10, 220, 80);
1495 
1496     tester::apply("s17-r",
1497                   from_wkt<G>("SEGMENT(-140 80, 140 10)"),
1498                   140, 10, 220, 80);
1499 
1500     tester::apply("s18",
1501                   from_wkt<G>("SEGMENT(20 10, 100 80)"),
1502                   20, 10, 100, 80);
1503 
1504     tester::apply("s18-r",
1505                   from_wkt<G>("SEGMENT(100 80, 20 10)"),
1506                   20, 10, 100, 80);
1507 
1508 }
1509 
BOOST_AUTO_TEST_CASE(envelope_segment_sphere_with_height)1510 BOOST_AUTO_TEST_CASE( envelope_segment_sphere_with_height )
1511 {
1512     typedef bg::cs::spherical_equatorial<bg::degree> coordinate_system_type;
1513     typedef bg::model::point<double, 3, coordinate_system_type> point_type;
1514     typedef bg::model::segment<point_type> G;
1515     typedef bg::model::box<point_type> B;
1516     typedef test_envelope_on_sphere_or_spheroid<G, B> tester;
1517 
1518     tester::apply("sh01",
1519                   from_wkt<G>("SEGMENT(10 10 567,40 40 1356)"),
1520                   10, 10, 567, 40, 40, 1356);
1521 
1522     tester::apply("sh02",
1523                   from_wkt<G>("SEGMENT(10 10 1356,40 40 567)"),
1524                   10, 10, 567, 40, 40, 1356);
1525 }
1526 
BOOST_AUTO_TEST_CASE(envelope_segment_spheroid_with_height)1527 BOOST_AUTO_TEST_CASE( envelope_segment_spheroid_with_height )
1528 {
1529     typedef bg::cs::geographic<bg::degree> coordinate_system_type;
1530     typedef bg::model::point<double, 3, coordinate_system_type> point_type;
1531     typedef bg::model::segment<point_type> G;
1532     typedef bg::model::box<point_type> B;
1533     typedef test_envelope_on_sphere_or_spheroid<G, B> tester;
1534 
1535     tester::apply("sh01",
1536                   from_wkt<G>("SEGMENT(10 10 567,40 40 1356)"),
1537                   10, 10, 567, 40, 40, 1356);
1538 
1539     tester::apply("sh02",
1540                   from_wkt<G>("SEGMENT(10 10 1356,40 40 567)"),
1541                   10, 10, 567, 40, 40, 1356);
1542 }
1543 
1544 template <typename CoordinateSystem>
test_envelope_multipoint()1545 void test_envelope_multipoint()
1546 {
1547     typedef bg::model::point<double, 2, CoordinateSystem> P;
1548     typedef bg::model::multi_point<P> G;
1549     typedef bg::model::box<P> B;
1550     typedef test_envelope_on_sphere_or_spheroid<G, B> tester;
1551 
1552     // empty multipoint
1553     test_empty_geometry<CoordinateSystem, G>("mp00", "MULTIPOINT()");
1554 
1555     tester::apply("mp01",
1556                   from_wkt<G>("MULTIPOINT(0 0,10 10)"),
1557                   0, 0, 10, 10);
1558 
1559     tester::apply("mp02",
1560                   from_wkt<G>("MULTIPOINT(0 10,10 0)"),
1561                   0, 0, 10, 10);
1562 
1563     tester::apply("mp03",
1564                   from_wkt<G>("MULTIPOINT(-10 20,0 10,10 0)"),
1565                   -10, 0, 10, 20);
1566 
1567     tester::apply("mp04",
1568                   from_wkt<G>("MULTIPOINT(-10 20,0 10,10 -15)"),
1569                   -10, -15, 10, 20);
1570 
1571     tester::apply("mp05",
1572                   from_wkt<G>("MULTIPOINT(-85 10,85 -20)"),
1573                   -85, -20, 85, 10);
1574 
1575     tester::apply("mp06",
1576                   from_wkt<G>("MULTIPOINT(-95 10,85 -20)"),
1577                   -95, -20, 85, 10);
1578 
1579     tester::apply("mp07",
1580                   from_wkt<G>("MULTIPOINT(-96 10,85 -20)"),
1581                   85, -20, -96+360, 10);
1582 
1583     tester::apply("mp08",
1584                   from_wkt<G>("MULTIPOINT(175 15,-175 -20)"),
1585                   175, -20, -175+360, 15);
1586 
1587     tester::apply("mp09",
1588                   from_wkt<G>("MULTIPOINT(170 15,170 20,-175 10,-90 10,10 10)"),
1589                   170, 10, 10+360, 20);
1590 
1591     // this should fail
1592     tester::apply("mp09a",
1593                   from_wkt<G>("MULTIPOINT(10 10,170 15,170 20,-175 10,-90 10)"),
1594                   170, 10, 10+360, 20);
1595 
1596 
1597     tester::apply("mp10",
1598                   from_wkt<G>("MULTIPOINT(10 10,20 90,30 -90)"),
1599                   10, -90, 10, 90);
1600 
1601     // this should fail
1602     tester::apply("mp11",
1603                   from_wkt<G>("MULTIPOINT(179 90,-179 -90,10 10)"),
1604                   10, -90, 10, 90);
1605 
1606     tester::apply("mp11a",
1607                   from_wkt<G>("MULTIPOINT(10 10,179 90,-179 -90)"),
1608                   10, -90, 10, 90);
1609 
1610     // this should fail
1611     tester::apply("mp11b",
1612                   from_wkt<G>("MULTIPOINT(179 90,-179 -90,-90 0)"),
1613                   -90, -90, -90, 90);
1614 
1615     tester::apply("mp11c",
1616                   from_wkt<G>("MULTIPOINT(-90 0,179 90,-179 -90,-90 0)"),
1617                   -90, -90, -90, 90);
1618 
1619     tester::apply("mp12",
1620                   from_wkt<G>("MULTIPOINT(170 -30,175 60,-178 10)"),
1621                   170, -30, -178+360, 60);
1622 
1623     tester::apply("mp13",
1624                   from_wkt<G>("MULTIPOINT(-170 -30,-175 40,178 50)"),
1625                   178, -30, -170+360, 50);
1626 
1627     tester::apply("mp13a",
1628                   from_wkt<G>("MULTIPOINT(-170 -30,178 50)"),
1629                   178, -30, -170+360, 50);
1630 
1631     tester::apply("mp13b",
1632                   from_wkt<G>("MULTIPOINT(-170 -30,178 50,-175 40)"),
1633                   178, -30, -170+360, 50);
1634 
1635     tester::apply("mp15",
1636                   from_wkt<G>("MULTIPOINT(10 -20)"),
1637                   10, -20, 10, -20);
1638 
1639     tester::apply("mp16",
1640                   from_wkt<G>("MULTIPOINT(0 90,10 90)"),
1641                   0, 90, 0, 90);
1642 
1643     tester::apply("mp17",
1644                   from_wkt<G>("MULTIPOINT(179 80,-179 -80,10 10)"),
1645                   10, -80, -179+360, 80);
1646 
1647     tester::apply("mp17a",
1648                   from_wkt<G>("MULTIPOINT(10 10,179 80,-179 -80)"),
1649                   10, -80, -179+360, 80);
1650 
1651     tester::apply("mp17b",
1652                   from_wkt<G>("MULTIPOINT(179 80,-179 -80,-90 0)"),
1653                   179, -80, -90+360, 80);
1654 
1655     tester::apply("mp17c",
1656                   from_wkt<G>("MULTIPOINT(-90 0,179 80,-179 -80,-90 0)"),
1657                   179, -80, -90+360, 80);
1658 
1659     tester::apply("mp18",
1660                   from_wkt<G>("MULTIPOINT(-170 45,20 25,40 40)"),
1661                   20, 25, 190, 45);
1662 
1663 #ifdef BOOST_GEOMETRY_NORMALIZE_LATITUDE
1664     tester::apply("mp18a",
1665                   from_wkt<G>("MULTIPOINT(10 135,20 25,40 40)"),
1666                   20, 25, 190, 45);
1667 #endif
1668 
1669     tester::apply("mp19",
1670                   from_wkt<G>("MULTIPOINT(350 45,20 25,40 40)"),
1671                   -10, 25, 40, 45);
1672 
1673 #ifdef BOOST_GEOMETRY_NORMALIZE_LATITUDE
1674     tester::apply("mp19a",
1675                   from_wkt<G>("MULTIPOINT(170 135,20 25,40 40)"),
1676                   -10, 25, 40, 45);
1677 #endif
1678 
1679     double eps = std::numeric_limits<double>::epsilon();
1680     double heps = eps / 2;
1681     {
1682         G mp;
1683         mp.push_back(P(1, 1));
1684         mp.push_back(P(1-heps, 1-heps));
1685         tester::apply("mp20", mp, 1-heps, 1-heps, 1, 1);
1686     }
1687 }
1688 
BOOST_AUTO_TEST_CASE(envelope_multipoint)1689 BOOST_AUTO_TEST_CASE( envelope_multipoint )
1690 {
1691     test_envelope_multipoint<bg::cs::spherical_equatorial<bg::degree> >();
1692     test_envelope_multipoint<bg::cs::geographic<bg::degree> >();
1693 }
1694 
1695 
1696 template <typename CoordinateSystem>
test_envelope_multipoint_with_height()1697 void test_envelope_multipoint_with_height()
1698 {
1699     typedef bg::model::point<double, 3, CoordinateSystem> point_type;
1700     typedef bg::model::multi_point<point_type> G;
1701     typedef bg::model::box<point_type> B;
1702     typedef test_envelope_on_sphere_or_spheroid<G, B> tester;
1703 
1704     // empty multipoint
1705     test_empty_geometry<CoordinateSystem, G>("mph00", "MULTIPOINT()");
1706 
1707     tester::apply("mph01",
1708                   from_wkt<G>("MULTIPOINT(0 0 567,10 10 1456)"),
1709                   0, 0, 567, 10, 10, 1456);
1710 
1711     tester::apply("mph02",
1712                   from_wkt<G>("MULTIPOINT(0 0 567,10 10 1456,20 90 967)"),
1713                   0, 0, 567, 10, 90, 1456);
1714 }
1715 
BOOST_AUTO_TEST_CASE(envelope_multipoint_with_height)1716 BOOST_AUTO_TEST_CASE( envelope_multipoint_with_height )
1717 {
1718     test_envelope_multipoint_with_height
1719         <
1720             bg::cs::spherical_equatorial<bg::degree>
1721         >();
1722     test_envelope_multipoint_with_height<bg::cs::geographic<bg::degree> >();
1723 }
1724 
1725 
1726 template <typename CoordinateSystem>
test_envelope_box()1727 void test_envelope_box()
1728 {
1729     typedef bg::model::point<double, 2, CoordinateSystem> P;
1730     typedef bg::model::box<P> G;
1731     typedef bg::model::box<P> B;
1732     typedef test_envelope_on_sphere_or_spheroid<G, B> tester;
1733 
1734     tester::apply("b01",
1735                   from_wkt<G>("BOX(10 10,20 20)"),
1736                   10, 10, 20, 20);
1737 
1738 #ifdef BOOST_GEOMETRY_NORMALIZE_LATITUDE
1739     tester::apply("b02",
1740                   from_wkt<G>("BOX(10 370,20 20)"),
1741                   10, 10, 20, 20);
1742 #endif
1743 
1744     // box crosses anti-meridian
1745     tester::apply("b02a",
1746                   from_wkt<G>("BOX(170 10,-170 20)"),
1747                   170, 10, 190, 20);
1748 
1749     tester::apply("b03",
1750                   from_wkt<G>("BOX(-170 10,170 20)"),
1751                   -170, 10, 170, 20);
1752 
1753     tester::apply("b04",
1754                   from_wkt<G>("BOX(10 10,350 20)"),
1755                   10, 10, 350, 20);
1756 
1757     tester::apply("b04a",
1758                   from_wkt<G>("BOX(10 10,-10 20)"),
1759                   10, 10, 350, 20);
1760 
1761     // box is a band
1762     tester::apply("b05",
1763                   from_wkt<G>("BOX(0 10,360 20)"),
1764                   -180, 10, 180, 20);
1765 
1766     tester::apply("b05a",
1767                   from_wkt<G>("BOX(0 10,0 20)"),
1768                   0, 10, 0, 20);
1769 
1770     // box is almost a band
1771     tester::apply("b06",
1772                   from_wkt<G>("BOX(10 10,5 20)"),
1773                   10, 10, 365, 20);
1774 
1775     // initial box is a band that crosses itself
1776     tester::apply("b07",
1777                   from_wkt<G>("BOX(0 10,540 20)"),
1778                   -180, 10, 180, 20);
1779 
1780     // initial box is a band that crosses itself
1781     tester::apply("b08",
1782                   from_wkt<G>("BOX(0 10,720 20)"),
1783                   -180, 10, 180, 20);
1784 
1785     tester::apply("b09",
1786                   from_wkt<G>("BOX(10 10,10 10)"),
1787                   10, 10, 10, 10);
1788 
1789     tester::apply("b09a",
1790                   from_wkt<G>("BOX(370 10,370 10)"),
1791                   10, 10, 10, 10);
1792 
1793     // box contains north and south pole
1794     tester::apply("b10",
1795                   from_wkt<G>("BOX(0 -90,0 90)"),
1796                   0, -90, 0, 90);
1797 
1798     // box contains north and south pole
1799     tester::apply("b10a",
1800                   from_wkt<G>("BOX(10 -90,10 90)"),
1801                   10, -90, 10, 90);
1802 
1803     // box contains north and south pole
1804     tester::apply("b10b",
1805                   from_wkt<G>("BOX(0 -90,10 90)"),
1806                   0, -90, 10, 90);
1807 
1808     // box contains north and south pole
1809     tester::apply("b11",
1810                   from_wkt<G>("BOX(0 -90,180 90)"),
1811                   0, -90, 180, 90);
1812 
1813     // box contains north and south pole
1814     tester::apply("b11a",
1815                   from_wkt<G>("BOX(10 -90,190 90)"),
1816                   10, -90, 190, 90);
1817 
1818     // box contains north and south pole
1819     tester::apply("b11b",
1820                   from_wkt<G>("BOX(10 -90,110 90)"),
1821                   10, -90, 110, 90);
1822 
1823     // box contains north and south pole and is a band
1824     // (box covers the entire spheroid)
1825     tester::apply("b12",
1826                   from_wkt<G>("BOX(0 -90,360 90)"),
1827                   -180, -90, 180, 90);
1828 
1829     // box contains north and south pole and is a band
1830     // (box covers the entire spheroid)
1831     tester::apply("b12a",
1832                   from_wkt<G>("BOX(10 -90,370 90)"),
1833                   -180, -90, 180, 90);
1834 
1835     // box contains north and south pole and is a band
1836     // (box covers the entire spheroid)
1837     tester::apply("b12b",
1838                   from_wkt<G>("BOX(-175 -90,185 90)"),
1839                   -180, -90, 180, 90);
1840 
1841     // box contains north and south pole and is a band
1842     // (box covers the entire spheroid)
1843     tester::apply("b12c",
1844                   from_wkt<G>("BOX(-175 -90,185 90)"),
1845                   -180, -90, 180, 90);
1846 
1847     // box contains north and south pole and is a band and is self-intersecting
1848     // (box covers the entire spheroid)
1849     tester::apply("b12d",
1850                   from_wkt<G>("BOX(-175 -90,186 90)"),
1851                   -180, -90, 180, 90);
1852 
1853     // box contains north and south pole and is a band and is self-intersecting
1854     // (box covers the entire spheroid)
1855     tester::apply("b12e",
1856                   from_wkt<G>("BOX(0 -90,540 90)"),
1857                   -180, -90, 180, 90);
1858 
1859     // box contains north and south pole and is a band and is self-intersecting
1860     // (box covers the entire spheroid)
1861     tester::apply("b12f",
1862                   from_wkt<G>("BOX(10 -90,540 90)"),
1863                   -180, -90, 180, 90);
1864 
1865     // box is a band
1866     tester::apply("b13",
1867                   from_wkt<G>("BOX(180 -10,-180 10)"),
1868                   -180, -10, 180, 10);
1869 
1870     // box contains north and south pole and is a band
1871     // (box covers the entire spheroid)
1872     tester::apply("b13a",
1873                   from_wkt<G>("BOX(180 -90,-180 90)"),
1874                   -180, -90, 180, 90);
1875 
1876     tester::apply("b14",
1877                   from_wkt<G>("BOX(0 10,30 90)"),
1878                   0, 10, 30, 90);
1879 
1880     tester::apply("b15",
1881                   from_wkt<G>("BOX(179 10,178 70)"),
1882                   179, 10, 538, 70);
1883 
1884     // box contains north pole
1885     tester::apply("b16",
1886                   from_wkt<G>("BOX(10 40,20 90)"),
1887                   10, 40, 20, 90);
1888 
1889     tester::apply("b16a",
1890                   from_wkt<G>("BOX(170 40,-170 90)"),
1891                   170, 40, 190, 90);
1892 
1893     // box contains south pole
1894     tester::apply("b17",
1895                   from_wkt<G>("BOX(10 -90,20 40)"),
1896                   10, -90, 20, 40);
1897 
1898     tester::apply("b17a",
1899                   from_wkt<G>("BOX(150 -90,-150 40)"),
1900                   150, -90, 210, 40);
1901 
1902     // box degenerates to the north pole
1903     tester::apply("b98",
1904                   from_wkt<G>("BOX(10 90,20 90)"),
1905                   0, 90, 0, 90);
1906 
1907     // box degenerates to the south pole
1908     tester::apply("b99",
1909                   from_wkt<G>("BOX(10 -90,20 -90)"),
1910                   0, -90, 0, -90);
1911 
1912     double eps = std::numeric_limits<double>::epsilon();
1913     double heps = eps / 2;
1914 
1915     tester::apply("b100", G(P(1-heps, 1-heps), P(1, 1)), 1-heps, 1-heps, 1, 1);
1916 }
1917 
1918 template <typename CoordinateSystem>
test_envelope_box_polar()1919 void test_envelope_box_polar()
1920 {
1921     typedef bg::model::point<double, 2, CoordinateSystem> P;
1922     typedef bg::model::box<P> G;
1923     typedef bg::model::box<P> B;
1924     typedef test_envelope_on_sphere_or_spheroid<G, B> tester;
1925 
1926     tester::apply("b01",
1927                   from_wkt<G>("BOX(10 10,20 20)"),
1928                   10, 10, 20, 20);
1929 
1930     tester::apply("b02a",
1931                   from_wkt<G>("BOX(170 10,-170 20)"),
1932                   170, 10, 190, 20);
1933 
1934     tester::apply("b10b",
1935                   from_wkt<G>("BOX(0 0,10 180)"),
1936                   0, 0, 10, 180);
1937 
1938     tester::apply("b16a",
1939                   from_wkt<G>("BOX(170 40,-170 180)"),
1940                   170, 40, 190, 180);
1941 }
1942 
BOOST_AUTO_TEST_CASE(envelope_box)1943 BOOST_AUTO_TEST_CASE( envelope_box )
1944 {
1945     test_envelope_box<bg::cs::spherical_equatorial<bg::degree> >();
1946     test_envelope_box<bg::cs::geographic<bg::degree> >();
1947     test_envelope_box_polar<bg::cs::spherical<bg::degree> >();
1948 }
1949 
1950 
1951 template <typename CoordinateSystem>
test_envelope_box_with_height()1952 void test_envelope_box_with_height()
1953 {
1954     typedef bg::cs::spherical_equatorial<bg::degree> coordinate_system_type;
1955     typedef bg::model::point<double, 3, coordinate_system_type> point_type;
1956     typedef bg::model::box<point_type> G;
1957     typedef bg::model::box<point_type> B;
1958     typedef test_envelope_on_sphere_or_spheroid<G, B> tester;
1959 
1960     tester::apply("bh01",
1961                   from_wkt<G>("BOX(10 10 567,20 20 2834)"),
1962                   10, 10, 567, 20, 20, 2834);
1963 
1964     tester::apply("bh02",
1965                   from_wkt<G>("BOX(10 10 567,20 20 567)"),
1966                   10, 10, 567, 20, 20, 567);
1967 
1968     tester::apply("bh03",
1969                   from_wkt<G>("BOX(0 10 567,170 90 1567)"),
1970                   0, 10, 567, 170, 90, 1567);
1971 }
1972 
BOOST_AUTO_TEST_CASE(envelope_box_with_height)1973 BOOST_AUTO_TEST_CASE( envelope_box_with_height )
1974 {
1975     test_envelope_box_with_height<bg::cs::spherical_equatorial<bg::degree> >();
1976     test_envelope_box_with_height<bg::cs::geographic<bg::degree> >();
1977 }
1978 
1979 
BOOST_AUTO_TEST_CASE(envelope_sphere_linestring)1980 BOOST_AUTO_TEST_CASE( envelope_sphere_linestring )
1981 {
1982     typedef bg::cs::spherical_equatorial<bg::degree> coordinate_system_type;
1983     typedef bg::model::point<double, 2, coordinate_system_type> P;
1984     typedef bg::model::linestring<P> G;
1985     typedef bg::model::box<P> B;
1986     typedef test_envelope_on_sphere_or_spheroid<G, B> tester;
1987 
1988     // empty linestring
1989     test_empty_geometry<coordinate_system_type, G>("l00", "LINESTRING()");
1990 
1991     tester::apply("l01",
1992                   from_wkt<G>("LINESTRING(10 15)"),
1993                   10, 15, 10, 15);
1994 
1995     tester::apply("l01a",
1996                   from_wkt<G>("LINESTRING(370 15)"),
1997                   10, 15, 10, 15);
1998 
1999     tester::apply("l01b",
2000                   from_wkt<G>("LINESTRING(370 90)"),
2001                   0, 90, 0, 90);
2002 
2003     tester::apply("l02",
2004                   from_wkt<G>("LINESTRING(10 10,20 20,10 30)"),
2005                   10, 10, 20, 30);
2006 
2007     // linestring that circles the entire globe
2008     tester::apply("l03",
2009                   from_wkt<G>("LINESTRING(-185 0,-170 25,-50 10,10 10,20 20,100 5,180 15)"),
2010                   -180, 0, 180, 33.587539971516854,
2011                   4.0 * std::numeric_limits<double>::epsilon());
2012 
2013     // linestring that crosses the antimeridian but staying close to it
2014     tester::apply("l04",
2015                   from_wkt<G>("LINESTRING(-170 10,170 45,160 5,-160 25)"),
2016                   160, 5, 200, 45);
2017 
2018     // linestring that goes through the north pole (twice)
2019     tester::apply("l05",
2020                   from_wkt<G>("LINESTRING(-170 80,10 60,20 80,-160 30)"),
2021                   -170, 30, 20, 90);
2022 
2023     // linestring that goes through the north pole (three times)
2024     tester::apply("l05a",
2025                   from_wkt<G>("LINESTRING(-170 80,10 60,20 80,-160 30,-150 30,30 70)"),
2026                   -170, 30, 30, 90);
2027 
2028     // linestring that goes through the north pole (four times)
2029     tester::apply("l05b",
2030                   from_wkt<G>("LINESTRING(-170 80,10 60,20 80,-160 30,-150 30,30 70,40 85,-140 25)"),
2031                   -170, 25, 40, 90);
2032 
2033     // linestring that goes through the north pole (five times)
2034     tester::apply("l05c",
2035                   from_wkt<G>("LINESTRING(-170 80,10 60,20 80,-160 30,-150 30,30 70,40 85,-140 25,-130 25,50 45)"),
2036                   -170, 25, 50, 90);
2037 
2038     // linestring that goes through the north pole (five times)
2039     tester::apply("l05d",
2040                   from_wkt<G>("LINESTRING(-170 80,10 60,20 80,-160 30,-150 30,30 70,40 85,-140 25,-130 25,50 45,185 45)"),
2041                   -170, 25, 185, 90);
2042 
2043     // linestring that crosses the antimeridian
2044     tester::apply("l06",
2045                   from_wkt<G>("LINESTRING(-160 85,-170 80,170 40,160 80)"),
2046                   160, 40, 200, 85);
2047 
2048     // linestring that crosses the antimeridian
2049     tester::apply("l06a",
2050                   from_wkt<G>("LINESTRING(-130 85,-170 84,170 40,160 80)"),
2051                   160, 40, 230, 85.02629680862029);
2052 
2053     // linestring that goes through the north pole
2054     tester::apply("l07",
2055                   from_wkt<G>("LINESTRING(-160 40,-170 90,-140 40,-50 30)"),
2056                   -160, 30, -50, 90);
2057 
2058     // linestring that degenerates to the north pole
2059     tester::apply("l08",
2060                   from_wkt<G>("LINESTRING(-40 90,-30 90,-140 90,10 90)"),
2061                   0, 90, 0, 90);
2062 
2063     // linestring with duplicate points
2064     tester::apply("l09",
2065                   from_wkt<G>("LINESTRING(-40 20,-40 20,-140 85,-10 5,-10 5)"),
2066                   -140, 5, -10, 86.184540574427757);
2067 
2068     // linestring with duplicate points
2069     tester::apply("l09a",
2070                   from_wkt<G>("LINESTRING(-40 20,320 20,-140 85,-10 5,350 5)"),
2071                   -140, 5, -10, 86.184540574427757);
2072 
2073     // linestring that lies on the equator
2074     tester::apply("l10",
2075                   from_wkt<G>("LINESTRING(0 0,50 0)"),
2076                   0, 0, 50, 0);
2077 
2078     // linestring that lies on the equator
2079     tester::apply("l10a",
2080                   from_wkt<G>("LINESTRING(-50 0,50 0)"),
2081                   -50, 0, 50, 0);
2082 
2083     // linestring that lies on the equator and touches antimeridian
2084     tester::apply("l10b",
2085                   from_wkt<G>("LINESTRING(50 0,180 0)"),
2086                   50, 0, 180, 0);
2087 
2088     // linestring that lies on the equator and crosses antimeridian
2089     tester::apply("l10c",
2090                   from_wkt<G>("LINESTRING(-170 0,160 0)"),
2091                   160, 0, 190, 0);
2092 
2093     double eps = std::numeric_limits<double>::epsilon();
2094     double heps = eps / 2;
2095 
2096     {
2097         G l;
2098         l.push_back(P(1, 1));
2099         l.push_back(P(1-heps, 1-heps));
2100         tester::apply("l11", l, 1-heps, 1-heps, 1, 1);
2101     }
2102 
2103     {
2104         G l;
2105         l.push_back(P(0, 0));
2106         l.push_back(P(1-heps, 1-heps));
2107         l.push_back(P(0, 0));
2108         l.push_back(P(1, 1));
2109         tester::apply("l12", l, 0, 0, 1, 1);
2110     }
2111 }
2112 
BOOST_AUTO_TEST_CASE(envelope_spheroid_linestring)2113 BOOST_AUTO_TEST_CASE( envelope_spheroid_linestring )
2114 {
2115     typedef bg::cs::geographic<bg::degree> coordinate_system_type;
2116     typedef bg::model::point<double, 2, coordinate_system_type> P;
2117     typedef bg::model::linestring<P> G;
2118     typedef bg::model::box<P> B;
2119     typedef test_envelope_on_sphere_or_spheroid<G, B> tester;
2120 
2121     // empty linestring
2122     test_empty_geometry<coordinate_system_type, G>("l00", "LINESTRING()");
2123 
2124     tester::apply("l01",
2125                   from_wkt<G>("LINESTRING(10 15)"),
2126                   10, 15, 10, 15);
2127 
2128     tester::apply("l01a",
2129                   from_wkt<G>("LINESTRING(370 15)"),
2130                   10, 15, 10, 15);
2131 
2132     tester::apply("l01b",
2133                   from_wkt<G>("LINESTRING(370 90)"),
2134                   0, 90, 0, 90);
2135 
2136     tester::apply("l02",
2137                   from_wkt<G>("LINESTRING(10 10,20 20,10 30)"),
2138                   10, 10, 20, 30);
2139 
2140     // linestring that circles the entire globe
2141     tester::apply("l03",
2142                   from_wkt<G>("LINESTRING(-185 0,-170 25,-50 10,10 10,20 20,100 5,180 15)"),
2143                   -180, 0, 180, rng(33.702476580412359, 33.702476580413318));
2144 
2145     // linestring that crosses the antimeridian but staying close to it
2146     tester::apply("l04",
2147                   from_wkt<G>("LINESTRING(-170 10,170 45,160 5,-160 25)"),
2148                   160, 5, 200, 45);
2149 
2150     // linestring that goes through the north pole (twice)
2151     tester::apply("l05",
2152                   from_wkt<G>("LINESTRING(-170 80,10 60,20 80,-160 30)"),
2153                   -170, 30, 20, 90);
2154 
2155     // linestring that goes through the north pole (three times)
2156     tester::apply("l05a",
2157                   from_wkt<G>("LINESTRING(-170 80,10 60,20 80,-160 30,-150 30,30 70)"),
2158                   -170, 30, 30, 90);
2159 
2160     // linestring that goes through the north pole (four times)
2161     tester::apply("l05b",
2162                   from_wkt<G>("LINESTRING(-170 80,10 60,20 80,-160 30,-150 30,30 70,40 85,-140 25)"),
2163                   -170, 25, 40, 90);
2164 
2165     // linestring that goes through the north pole (five times)
2166     tester::apply("l05c",
2167                   from_wkt<G>("LINESTRING(-170 80,10 60,20 80,-160 30,-150 30,30 70,40 85,-140 25,-130 25,50 45)"),
2168                   -170, 25, 50, 90);
2169 
2170     // linestring that goes through the north pole (five times)
2171     tester::apply("l05d",
2172                   from_wkt<G>("LINESTRING(-170 80,10 60,20 80,-160 30,-150 30,30 70,40 85,-140 25,-130 25,50 45,185 45)"),
2173                   -170, 25, 185, 90);
2174 
2175     // linestring that crosses the antimeridian
2176     tester::apply("l06",
2177                   from_wkt<G>("LINESTRING(-160 85,-170 80,170 40,160 80)"),
2178                   160, 40, 200, 85);
2179 
2180     // linestring that crosses the antimeridian
2181     tester::apply("l06a",
2182                   from_wkt<G>("LINESTRING(-130 85,-170 84,170 40,160 80)"),
2183                   160, 40, 230, 85.02630556315151);
2184 
2185     // linestring that goes through the north pole
2186     tester::apply("l07",
2187                   from_wkt<G>("LINESTRING(-160 40,-170 90,-140 40,-50 30)"),
2188                   -160, 30, -50, 90);
2189 
2190     // linestring that degenerates to the north pole
2191     tester::apply("l08",
2192                   from_wkt<G>("LINESTRING(-40 90,-30 90,-140 90,10 90)"),
2193                   0, 90, 0, 90);
2194 
2195     // linestring with duplicate points
2196     tester::apply("l09",
2197                   from_wkt<G>("LINESTRING(-40 20,-40 20,-140 85,-10 5,-10 5)"),
2198                   -140, 5, -10, 86.18564770636192);
2199 
2200     // linestring with duplicate points
2201     tester::apply("l09a",
2202                   from_wkt<G>("LINESTRING(-40 20,320 20,-140 85,-10 5,350 5)"),
2203                   -140, 5, -10, 86.18564770636192);
2204 
2205     // linestring that lies on the equator
2206     tester::apply("l10",
2207                   from_wkt<G>("LINESTRING(0 0,50 0)"),
2208                   0, 0, 50, 0);
2209 
2210     // linestring that lies on the equator
2211     tester::apply("l10a",
2212                   from_wkt<G>("LINESTRING(-50 0,50 0)"),
2213                   -50, 0, 50, 0);
2214 
2215     // linestring that lies on the equator and touches antimeridian
2216     tester::apply("l10b",
2217                   from_wkt<G>("LINESTRING(50 0,180 0)"),
2218                   50, 0, 180, 0);
2219 
2220     // linestring that lies on the equator and crosses antimeridian
2221     tester::apply("l10c",
2222                   from_wkt<G>("LINESTRING(-170 0,160 0)"),
2223                   160, 0, 190, 0);
2224 
2225     double eps = std::numeric_limits<double>::epsilon();
2226     double heps = eps / 2;
2227 
2228     {
2229         G l;
2230         l.push_back(P(1, 1));
2231         l.push_back(P(1-heps, 1-heps));
2232         tester::apply("l11", l, 1-heps, 1-heps, 1, 1);
2233     }
2234 
2235     {
2236         G l;
2237         l.push_back(P(0, 0));
2238         l.push_back(P(1-heps, 1-heps));
2239         l.push_back(P(0, 0));
2240         l.push_back(P(1, 1));
2241         tester::apply("l12", l, 0, 0, 1, 1);
2242     }
2243 }
2244 
2245 
BOOST_AUTO_TEST_CASE(envelope_linestring_sphere_with_height)2246 BOOST_AUTO_TEST_CASE( envelope_linestring_sphere_with_height )
2247 {
2248     typedef bg::cs::spherical_equatorial<bg::degree> coordinate_system_type;
2249     typedef bg::model::point<double, 3, coordinate_system_type> point_type;
2250     typedef bg::model::linestring<point_type> G;
2251     typedef bg::model::box<point_type> B;
2252     typedef test_envelope_on_sphere_or_spheroid<G, B> tester;
2253 
2254     // empty linestring
2255     test_empty_geometry<coordinate_system_type, G>("lh00", "LINESTRING()");
2256 
2257     tester::apply("lh01",
2258                   from_wkt<G>("LINESTRING(10 15 30,20 25 434,30 35 186)"),
2259                   10, 15, 30, 30, 35, 434);
2260 }
2261 
BOOST_AUTO_TEST_CASE(envelope_linestring_spheroid_with_height)2262 BOOST_AUTO_TEST_CASE( envelope_linestring_spheroid_with_height )
2263 {
2264     typedef bg::cs::geographic<bg::degree> coordinate_system_type;
2265     typedef bg::model::point<double, 3, coordinate_system_type> point_type;
2266     typedef bg::model::linestring<point_type> G;
2267     typedef bg::model::box<point_type> B;
2268     typedef test_envelope_on_sphere_or_spheroid<G, B> tester;
2269 
2270     // empty linestring
2271     test_empty_geometry<coordinate_system_type, G>("lh00", "LINESTRING()");
2272 
2273     tester::apply("lh01",
2274                   from_wkt<G>("LINESTRING(10 15 30,20 25 434,30 35 186)"),
2275                   10, 15, 30, 30, 35, 434);
2276 }
2277 
BOOST_AUTO_TEST_CASE(envelope_sphere_multilinestring)2278 BOOST_AUTO_TEST_CASE( envelope_sphere_multilinestring )
2279 {
2280     typedef bg::cs::spherical_equatorial<bg::degree> coordinate_system_type;
2281     typedef bg::model::point<double, 2, coordinate_system_type> point_type;
2282     typedef bg::model::multi_linestring<bg::model::linestring<point_type> > G;
2283     typedef bg::model::box<point_type> B;
2284     typedef test_envelope_on_sphere_or_spheroid<G, B> tester;
2285 
2286     // empty multilinestring
2287     test_empty_geometry<coordinate_system_type, G>("ml00", "MULTILINESTRING()");
2288 
2289     // invalid multilinestring
2290     test_empty_geometry<coordinate_system_type, G>("ml00a",
2291                                                    "MULTILINESTRING(())");
2292 
2293     // invalid multilinestring
2294     test_empty_geometry<coordinate_system_type, G>("ml00b",
2295                                                    "MULTILINESTRING((),())");
2296 
2297     // invalid multilinestring
2298     tester::apply("ml00c",
2299                   from_wkt<G>("MULTILINESTRING((10 15),(),())"),
2300                   10, 15, 10, 15);
2301 
2302     // invalid multilinestring
2303     tester::apply("ml00d",
2304                   from_wkt<G>("MULTILINESTRING((),(10 15),())"),
2305                   10, 15, 10, 15);
2306 
2307     tester::apply("ml01",
2308                   from_wkt<G>("MULTILINESTRING((10 15))"),
2309                   10, 15, 10, 15);
2310 
2311 #ifdef BOOST_GEOMETRY_TEST_FAILURES
2312     tester::apply("ml01a",
2313                   from_wkt<G>("MULTILINESTRING((),(),(10 15),())"),
2314                   10, 15, 10, 15);
2315 #endif
2316 
2317     tester::apply("ml02",
2318                   from_wkt<G>("MULTILINESTRING((-170 40,-100 80,10 40),(-10 25,10 35,100 45),(50 30,150 45,-160 30))"),
2319                   -180, 25, 180, 81.113793608034072);
2320 
2321     tester::apply("ml03",
2322                   from_wkt<G>("MULTILINESTRING((-150 40,-100 80,10 40),(-10 25,10 35,100 45),(50 30,150 45,-160 30))"),
2323                   -150, 25, 200, 81.113793608034072);
2324 
2325     tester::apply("ml04",
2326                   from_wkt<G>("MULTILINESTRING((-150 40,-100 80),(10 35,100 80))"),
2327                   -150, 35, 100, 80.07385383411011);
2328 
2329     tester::apply("ml04a",
2330                   from_wkt<G>("MULTILINESTRING((-150 40,-100 80),(10 35,100 80),(170 25,-160 80))"),
2331                   10, 25, 260, 80.07385383411011);
2332 
2333     tester::apply("ml05",
2334                   from_wkt<G>("MULTILINESTRING((-140 40,-100 80),(10 35,100 80))"),
2335                   -140, 35, 100, 80.07385383411011);
2336 
2337     tester::apply("ml05a",
2338                   from_wkt<G>("MULTILINESTRING((-140 40,-100 80),(10 35,100 80),(170 25,-160 80))"),
2339                   10, 25, 260, 80.07385383411011);
2340 }
2341 
BOOST_AUTO_TEST_CASE(envelope_spheroid_multilinestring)2342 BOOST_AUTO_TEST_CASE( envelope_spheroid_multilinestring )
2343 {
2344     typedef bg::cs::geographic<bg::degree> coordinate_system_type;
2345     typedef bg::model::point<double, 2, coordinate_system_type> point_type;
2346     typedef bg::model::multi_linestring<bg::model::linestring<point_type> > G;
2347     typedef bg::model::box<point_type> B;
2348     typedef test_envelope_on_sphere_or_spheroid<G, B> tester;
2349 
2350     // empty multilinestring
2351     test_empty_geometry<coordinate_system_type, G>("ml00", "MULTILINESTRING()");
2352 
2353     // invalid multilinestring
2354     test_empty_geometry<coordinate_system_type, G>("ml00a",
2355                                                    "MULTILINESTRING(())");
2356 
2357     // invalid multilinestring
2358     test_empty_geometry<coordinate_system_type, G>("ml00b",
2359                                                    "MULTILINESTRING((),())");
2360 
2361     // invalid multilinestring
2362     tester::apply("ml00c",
2363                   from_wkt<G>("MULTILINESTRING((10 15),(),())"),
2364                   10, 15, 10, 15);
2365 
2366     // invalid multilinestring
2367     tester::apply("ml00d",
2368                   from_wkt<G>("MULTILINESTRING((),(10 15),())"),
2369                   10, 15, 10, 15);
2370 
2371     tester::apply("ml01",
2372                   from_wkt<G>("MULTILINESTRING((10 15))"),
2373                   10, 15, 10, 15);
2374 
2375 #ifdef BOOST_GEOMETRY_TEST_FAILURES
2376     tester::apply("ml01a",
2377                   from_wkt<G>("MULTILINESTRING((),(),(10 15),())"),
2378                   10, 15, 10, 15);
2379 #endif
2380 
2381     tester::apply("ml02",
2382                   from_wkt<G>("MULTILINESTRING((-170 40,-100 80,10 40),(-10 25,10 35,100 45),(50 30,150 45,-160 30))"),
2383                   -180, 25, 180, 81.115885076701147);
2384 
2385     tester::apply("ml03",
2386                   from_wkt<G>("MULTILINESTRING((-150 40,-100 80,10 40),(-10 25,10 35,100 45),(50 30,150 45,-160 30))"),
2387                   -150, 25, 200, 81.115885076701147);
2388 
2389     tester::apply("ml04",
2390                   from_wkt<G>("MULTILINESTRING((-150 40,-100 80),(10 35,100 80))"),
2391                   -150, 35, 100, rng(80.07385383411011, 80.082544902477267));
2392 
2393     tester::apply("ml04a",
2394                   from_wkt<G>("MULTILINESTRING((-150 40,-100 80),(10 35,100 80),(170 25,-160 80))"),
2395                   10, 25, 260, rng(80.07385383411011, 80.082544902477267));
2396 
2397     tester::apply("ml05",
2398                   from_wkt<G>("MULTILINESTRING((-140 40,-100 80),(10 35,100 80))"),
2399                   -140, 35, 100, rng(80.07385383411011, 80.082544902477267));
2400 
2401     tester::apply("ml05a",
2402                   from_wkt<G>("MULTILINESTRING((-140 40,-100 80),(10 35,100 80),(170 25,-160 80))"),
2403                   10, 25, 260, rng(80.07385383411011, 80.082544902477267));
2404 }
2405 
2406 
BOOST_AUTO_TEST_CASE(envelope_multilinestring_sphere_with_height)2407 BOOST_AUTO_TEST_CASE( envelope_multilinestring_sphere_with_height )
2408 {
2409     typedef bg::cs::spherical_equatorial<bg::degree> coordinate_system_type;
2410     typedef bg::model::point<double, 3, coordinate_system_type> point_type;
2411     typedef bg::model::multi_linestring<bg::model::linestring<point_type> > G;
2412     typedef bg::model::box<point_type> B;
2413     typedef test_envelope_on_sphere_or_spheroid<G, B> tester;
2414 
2415     tester::apply("mlh01",
2416                   from_wkt<G>("MULTILINESTRING((10 15 1000))"),
2417                   10, 15, 1000, 10, 15, 1000);
2418 
2419 #ifdef BOOST_GEOMETRY_TEST_FAILURES
2420     tester::apply("mlh01a",
2421                   from_wkt<G>("MULTILINESTRING((),(),(10 15 1000),())"),
2422                   10, 15, 1000, 10, 15, 1000);
2423 #endif
2424 
2425     tester::apply("mlh02",
2426                   from_wkt<G>("MULTILINESTRING((-170 40 400,-100 80 300),(-10 25 600,10 35 700,120 45 450))"),
2427                   -10, 25, 300, 260, 80, 700);
2428 }
2429 
BOOST_AUTO_TEST_CASE(envelope_multilinestring_spheroid_with_height)2430 BOOST_AUTO_TEST_CASE( envelope_multilinestring_spheroid_with_height )
2431 {
2432     typedef bg::cs::geographic<bg::degree> coordinate_system_type;
2433     typedef bg::model::point<double, 3, coordinate_system_type> point_type;
2434     typedef bg::model::multi_linestring<bg::model::linestring<point_type> > G;
2435     typedef bg::model::box<point_type> B;
2436     typedef test_envelope_on_sphere_or_spheroid<G, B> tester;
2437 
2438     tester::apply("mlh01",
2439                   from_wkt<G>("MULTILINESTRING((10 15 1000))"),
2440                   10, 15, 1000, 10, 15, 1000);
2441 
2442 #ifdef BOOST_GEOMETRY_TEST_FAILURES
2443     tester::apply("mlh01a",
2444                   from_wkt<G>("MULTILINESTRING((),(),(10 15 1000),())"),
2445                   10, 15, 1000, 10, 15, 1000);
2446 #endif
2447 
2448     tester::apply("mlh02",
2449                   from_wkt<G>("MULTILINESTRING((-170 40 400,-100 80 300),(-10 25 600,10 35 700,120 45 450))"),
2450                   -10, 25, 300, 260, 80, 700);
2451 }
2452 
2453 //Test spherical polygons and rings (geographic should be similar)
BOOST_AUTO_TEST_CASE(envelope_polygon)2454 BOOST_AUTO_TEST_CASE( envelope_polygon )
2455 {
2456     typedef bg::cs::spherical_equatorial<bg::degree> coordinate_system_type;
2457     typedef bg::model::point<double, 2, coordinate_system_type> point_type;
2458     typedef bg::model::polygon<point_type> G;
2459     typedef bg::model::box<point_type> B;
2460     typedef test_envelope_on_sphere_or_spheroid<G, B> tester;
2461 
2462     typedef bg::model::ring<point_type> R;
2463     typedef test_envelope_on_sphere_or_spheroid<R, B> testerR;
2464     R ring1;
2465     bg::append(ring1, point_type(0.0, 0.0));
2466     bg::append(ring1, point_type(0.0, 5.0));
2467     bg::append(ring1, point_type(5.0, 5.0));
2468     bg::append(ring1, point_type(5.0, 0.0));
2469     bg::append(ring1, point_type(0.0, 0.0));
2470 
2471     testerR::apply("r01",
2472                   ring1,
2473                   0, 0, 5, 5.0047392446083938);
2474     tester::apply("p01",
2475                   from_wkt<G>("POLYGON((0 0,1 0,1 1,0 1,0 0))"),
2476                   0, 0, 1, 1.0000380706527705);
2477     tester::apply("p02",
2478                   from_wkt<G>("POLYGON((0 0,1 0,1 1,0 1,0 0),(0.5 0.5,0.7 0.5,0.7 0.7,0.5 0.5))"),
2479                   0, 0, 1, 1.0000380706527705);
2480     tester::apply("p03",
2481                   from_wkt<G>("POLYGON((),(0.5 0.5,0.5 0.7,0.7 0.7,0.5 0.5))"),
2482                   0.5, 0.5, 0.7, 0.70000106605644807);
2483     tester::apply("p04",
2484                   from_wkt<G>("POLYGON((),(0.5 0.5,0.5 0.7,0.7 0.7,0.5 0.5),\
2485                               (0.7 0.5,0.9 0.5,0.9 0.7,0.7 0.5))"),
2486                   0.5, 0.5, 0.9, 0.70000106605644807);
2487 
2488     // https://github.com/boostorg/geometry/issues/466
2489     tester::apply("p5-issue466",
2490                   from_wkt<G>("POLYGON((2.4 48.9021,2.4 48.89,2.3 48.89,2.3 48.9021,2.4 48.9021))"),
2491                   2.3, 48.89, 2.4, 48.902110807274966);
2492     tester::apply("p6-issue466",
2493                   from_wkt<G>("POLYGON((2.4 48.90215,2.4 48.89,2.3 48.89,2.3 48.90215,2.4 48.90215))"),
2494                   2.3, 48.89, 2.4, 48.902160807272381);
2495     tester::apply("p7-issue466",
2496                   from_wkt<G>("POLYGON((2.4 48.9022,2.4 48.89,2.3 48.89,2.3 48.9022,2.4 48.9022))"),
2497                   2.3, 48.89, 2.4, 48.902210807269796);
2498 }
2499 
2500 // unit test for rings de-activated for now (current implementation
2501 // for area on the spherical equatorial coordinate system is not complete)
2502 // TODO: re-activate once implementation is done
2503 // right now implementation does not distinguish between ccw and cw rings
BOOST_AUTO_TEST_CASE(envelope_cw_ring)2504 BOOST_AUTO_TEST_CASE( envelope_cw_ring )
2505 {
2506     typedef bg::cs::spherical_equatorial<bg::degree> coordinate_system_type;
2507     typedef bg::model::point<double, 2, coordinate_system_type> point_type;
2508     typedef bg::model::polygon<point_type> G;
2509     typedef bg::model::box<point_type> B;
2510     typedef test_envelope_on_sphere_or_spheroid<G, B> tester;
2511 
2512     //double const eps = std::numeric_limits<double>::epsilon();
2513 
2514     tester::apply("r01cw",
2515                   from_wkt<G>("POLYGON((0 10,0 45,50 10,0 10))"),
2516                   0, 10, 50, 45);
2517 #if 0
2518     // ring that contains both the north and south poles in its interior
2519     tester::apply("r01cw-r",
2520                   from_wkt<G>("POLYGON((0 10,50 10,0 45,0 10))"),
2521                   -180, -90, 180, 90);
2522 
2523     // ring that contains the north pole in its interior
2524     tester::apply("r02cw",
2525                   from_wkt<G>("POLYGON((0 0,-50 0,-170 0,180 0,100 0,0 0))"),
2526                   -180, 0, 180, 90);
2527     //                  -180, -90, 180, 0);
2528 
2529     // ring that contains the south pole in its interior
2530     tester::apply("r02cw-r",
2531                   from_wkt<G>("POLYGON((0 0,100 0,180 0,-170 0,-50 0,0 0))"),
2532                   -180, -90, 180, 0);
2533                   //                  -180, 0, 180, 90);
2534 
2535     // ring that contains the north pole in its interior
2536     tester::apply("r03cw",
2537                   from_wkt<G>("POLYGON((0 -10,-50 -10,-170 -10,180 -10,100 -10,0 -10))"),
2538                   -180, -19.42540014068282, 180, 90);
2539                   //                  -180, -90, 180, -10);
2540 
2541     // ring that contains both the south and north poles in its interior
2542     tester::apply("r03cw-r",
2543                   from_wkt<G>("POLYGON((0 -10,100 -10,180 -10,-170 -10,-50 -10,0 -10))"),
2544                   -180, -90, 180, -10);
2545     //                  -180, -19.42540014068282, 180, 90);
2546 
2547     // ring that has the north pole as vertex and contains the south pole
2548     tester::apply("r04cw",
2549                   from_wkt<G>("POLYGON((0 0,-50 90,-50 0,0 0))"),
2550                   -180, -90, 180, 90);
2551 
2552     // ring that has the north pole as vertex
2553     tester::apply("r04cw-r",
2554                   from_wkt<G>("POLYGON((0 0,-50 0,-50 90,0 0))"),
2555                   -50, 0, 0, 90);
2556 
2557     // ring that crosses antimeridian but does not contain any pole
2558     tester::apply("r05cw",
2559                   from_wkt<G>("POLYGON((-140 0,140 10,-140 80,-140 0))"),
2560                   140, 0, 220, 80);
2561 
2562     // ring that crosses antimeridian multiple times but does not
2563     // contain any pole
2564     tester::apply("r06cw",
2565                   from_wkt<G>("POLYGON((-140 10,140 10,140 80,-140 80,-140 10))"),
2566                   140, 10, 220, 82.30737118075496,
2567                   2 * eps);
2568 
2569     // ring that crosses antimeridian multiple times but does not
2570     // contain any pole
2571     tester::apply("r07cw",
2572                   from_wkt<G>("POLYGON((-140 10,140 10,180 80,-140 10))"),
2573                   140, 10, 220, 80);
2574 
2575     // ring that goes through the north pole
2576     tester::apply("r08cw",
2577                   from_wkt<G>("POLYGON((0 0,-50 0,-50 90,0 0))"),
2578                   -50, 0, 0, 90);
2579 
2580     // ring that goes through the south pole and contains the north pole
2581     tester::apply("r09cw",
2582                   from_wkt<G>("POLYGON((0 0,0 -90,50 0,0 0))"),
2583                   -180, -90, 180, 90);
2584 
2585     // ring that goes through the south pole
2586     tester::apply("r09cw-r",
2587                   from_wkt<G>("POLYGON((0 0,50 0,50 -90,0 0))"),
2588                   0, -90, 50, 0);
2589 
2590     // ring that goes through both south and north pole
2591     tester::apply("r10cw",
2592                   from_wkt<G>("POLYGON((50 0,50 -90,40 0,40 90,50 0))"),
2593                   40, -90, 50, 90);
2594 
2595     // ring that goes through both south and north pole and crosses antimeridian
2596     tester::apply("r11cw",
2597                   from_wkt<G>("POLYGON((-170 0,-170 -90,160 0,160 90,-170 0))"),
2598                   160, -90, 190, 90);
2599 
2600     // ring with edge that goes through the north pole and contains
2601     // south pole (the bounding box is the entire globe)
2602     tester::apply("r12cw",
2603                   from_wkt<G>("POLYGON((-50 40,130 10,170 80,-50 40))"),
2604                   -180, -90, 180, 90);
2605                   //                  -180, 10, 180, 90);
2606 
2607     // ring with edge that goes through the north pole
2608     tester::apply("r12cw-r",
2609                   from_wkt<G>("POLYGON((-50 40,170 80,130 10,-50 40))"),
2610                   -180, 10, 180, 90);
2611     //                  -180, -90, 180, 90);
2612 
2613     // ring that represents a spherical cap near the north pole
2614     tester::apply("r13cw",
2615                   from_wkt<G>("POLYGON((100 45,0 45,-100 45,-100 90,100 45))"),
2616                   -100, 45, 100, 90);
2617 
2618     // ring that represents the complement of a spherical cap
2619     // near the north pole
2620     tester::apply("r13cw-r",
2621                   from_wkt<G>("POLYGON((-100 45,0 45,100 45,100 90,-100 45))"),
2622                   -180, -90, 180, 90);
2623 
2624     // ring that represents the complement of a spherical cap
2625     // that touches the south pole
2626     tester::apply("r14cw",
2627                   from_wkt<G>("POLYGON((-100 45,0 45,100 45,100 -90,-100 45))"),
2628                   -100, -90, 100, 57.26759279038765);
2629 
2630     // ring that represents a spherical cap that touches the south pole
2631     tester::apply("r14cw-r",
2632                   from_wkt<G>("POLYGON((100 45,0 45,-100 45,-100 -90,100 45))"),
2633                   -180, -90, 180, 90);
2634 
2635     // ring with edge that goes through the south pole
2636     tester::apply("r15cw",
2637                   from_wkt<G>("POLYGON((-50 -40,130 -10,170 -80,-50 -40))"),
2638                   -180, -90, 180, -10);
2639 
2640     // ring with edge that goes through the south pole and contains
2641     // north pole (the bounding box is the entire globe)
2642     tester::apply("r15cw-r",
2643                   from_wkt<G>("POLYGON((-50 -40,170 -80,130 -10,-50 -40))"),
2644                   -180, -90, 180, 90);
2645 
2646     // ring that does not contain any pole and lies in the lower hemisphere
2647     tester::apply("r16",
2648                   from_wkt<G>("POLYGON((-50 -80,-50 -40,-30 -40,-30 -80,-50 -80))"),
2649                   -50, -80.14892388341609, -30, -40);
2650 
2651     // ring that lies in the lower hemisphere and contains both poles
2652     tester::apply("r16-r",
2653                   from_wkt<G>("POLYGON((-50 -80,-30 -80,-30 -40,-50 -40,-50 -80))"),
2654                   -180, -90, 180, 90);
2655 
2656     // ring that goes through the south pole and contains the north pole
2657     tester::apply("r17cw",
2658                   from_wkt<G>("POLYGON((50 0,50 -90,100 0,50 0))"),
2659                   -180, -90, 180, 90);
2660 
2661     // ring that goes through the south pole
2662     tester::apply("r17cw-r",
2663                   from_wkt<G>("POLYGON((50 0,100 0,100 -90,50 0))"),
2664                   50, -90, 100, 0);
2665 
2666     // ring that goes through the south pole and contains the north pole
2667     tester::apply("r18cw",
2668                   from_wkt<G>("POLYGON((50 0,50 -90,460 0,50 0))"),
2669                   -180, -90, 180, 90);
2670 
2671     // ring that goes through the south pole
2672     tester::apply("r18cw-r",
2673                   from_wkt<G>("POLYGON((50 0,460 0,100 -90,50 0))"),
2674                   50, -90, 100, 0);
2675 
2676     // ring that goes through the south pole and contains the north pole
2677     tester::apply("r19cw",
2678                   from_wkt<G>("POLYGON((50 0,50 -90,-260 0,50 0))"),
2679                   -180, -90, 180, 90);
2680 
2681     // ring that goes through the south pole
2682     tester::apply("r19cw-r",
2683                   from_wkt<G>("POLYGON((50 0,-260 0,100 -90,50 0))"),
2684                   50, -90, 100, 0);
2685 
2686     // ring that goes through both poles
2687     tester::apply("r20cw",
2688                   from_wkt<G>("POLYGON((10 0,10 90,20 0,20 -90,10 0))"),
2689                   10, -90, 20, 90); // SUCCEEDS FOR WRONG REASON
2690 
2691     // ring that goes through both poles
2692     tester::apply("r20cw-r",
2693                   from_wkt<G>("POLYGON((10 0,10 -90,20 0,20 90,10 0))"),
2694         -180, -90, 180, 90); // FAILS NOW
2695 
2696     // ring that goes through both poles and its boundary forms
2697     // a great circle
2698     tester::apply("r21cw",
2699                   from_wkt<G>("POLYGON((-10 0,-10 90,170 0,170 -90,-10 0))"),
2700                   -10, -90, 170, 90); // SUCCEEDS FOR WRONG REASON
2701 
2702     // ring that goes through both poles and its boundary forms
2703     // a great circle
2704     tester::apply("r21cw-r",
2705                   from_wkt<G>("POLYGON((-10 0,-10 -90,170 0,170 90,-10 0))"),
2706                   170, -90, 350, 90); // FAILS NOW
2707 #endif
2708 }
2709 
2710