• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Boost.Geometry
2 // Unit Test
3 
4 // Copyright (c) 2019, Oracle and/or its affiliates.
5 
6 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
7 
8 // Licensed under the Boost Software License version 1.0.
9 // http://www.boost.org/users/license.html
10 
11 
12 #include <geometry_test_common.hpp>
13 
14 #include <boost/geometry/algorithms/detail/calculate_point_order.hpp>
15 
16 #include <boost/geometry/geometries/point.hpp>
17 #include <boost/geometry/geometries/ring.hpp>
18 
19 #include <boost/geometry/io/wkt/wkt.hpp>
20 
21 #include <boost/geometry/strategies/cartesian/point_order.hpp>
22 #include <boost/geometry/strategies/geographic/point_order.hpp>
23 #include <boost/geometry/strategies/spherical/point_order.hpp>
24 
25 
order_str(bg::order_selector o)26 inline const char * order_str(bg::order_selector o)
27 {
28     if (o == bg::clockwise)
29         return "clockwise";
30     else if (o == bg::counterclockwise)
31         return "counterclockwise";
32     else
33         return "order_undetermined";
34 }
35 
cs_str(bg::cartesian_tag)36 inline const char * cs_str(bg::cartesian_tag)
37 {
38     return "cartesian";
39 }
40 
cs_str(bg::spherical_equatorial_tag)41 inline const char * cs_str(bg::spherical_equatorial_tag)
42 {
43     return "spherical_equatorial";
44 }
45 
cs_str(bg::geographic_tag)46 inline const char * cs_str(bg::geographic_tag)
47 {
48     return "geographic";
49 }
50 
51 template <typename Ring>
test_one(Ring const & ring,bg::order_selector expected)52 inline void test_one(Ring const& ring, bg::order_selector expected)
53 {
54     typedef typename bg::cs_tag<Ring>::type cs_tag;
55 
56     bg::order_selector result = bg::detail::calculate_point_order(ring);
57 
58     BOOST_CHECK_MESSAGE(result == expected, "Expected: " << order_str(expected) << " for " << bg::wkt(ring) << " in " << cs_str(cs_tag()));
59 
60     if (expected != bg::order_undetermined && result != bg::order_undetermined)
61     {
62         Ring ring_rev = ring;
63 
64         std::reverse(boost::begin(ring_rev), boost::end(ring_rev));
65 
66         bg::order_selector result_rev = bg::detail::calculate_point_order(ring_rev);
67 
68         BOOST_CHECK_MESSAGE(result != result_rev, "Invalid order of reversed: " << bg::wkt(ring) << " in " << cs_str(cs_tag()));
69     }
70 }
71 
72 template <typename P>
test_one(std::string const & ring_wkt,bg::order_selector expected)73 inline void test_one(std::string const& ring_wkt, bg::order_selector expected)
74 {
75     //typedef typename bg::cs_tag<P>::type cs_tag;
76 
77     bg::model::ring<P> ring;
78     bg::read_wkt(ring_wkt, ring);
79 
80     std::size_t n = boost::size(ring);
81     for (size_t i = 1; i < n; ++i)
82     {
83         test_one(ring, expected);
84         std::rotate(boost::begin(ring), boost::begin(ring) + 1, boost::end(ring));
85 
86         // it seems that area method doesn't work for invalid "opened" polygons
87         //if (! boost::is_same<cs_tag, bg::geographic_tag>::value)
88         {
89             P p = bg::range::front(ring);
90             bg::range::push_back(ring, p);
91         }
92     }
93 }
94 
95 template <typename P>
test_all()96 void test_all()
97 {
98     // From correct() test, rings rotated and reversed in test_one()
99     test_one<P>("POLYGON((0 0,0 1,1 1,1 0,0 0))", bg::clockwise);
100     test_one<P>("POLYGON((0 0,0 1,1 1,1 0))", bg::clockwise);
101     test_one<P>("POLYGON((0 0,0 4,4 4,4 0,0 0))", bg::clockwise);
102     test_one<P>("POLYGON((1 1,2 1,2 2,1 2,1 1))", bg::counterclockwise);
103 
104    test_one<P>("POLYGON((0 5, 5 5, 5 0, 0 0, 0 5))", bg::clockwise);
105    test_one<P>("POLYGON((0 5, 0 5, 0 6, 0 6, 0 4, 0 5, 5 5, 5 0, 0 0, 0 6, 0 5))", bg::clockwise);
106    test_one<P>("POLYGON((2 0, 2 1, 2 -1, 2 0, 1 0, 1 -1, 0 -1, 0 1, 1 1, 1 0, 2 0))", bg::clockwise);
107    test_one<P>("POLYGON((2 0, 2 1, 2 -1, 2 0, 1 0, 1 -1, 0 -1, 0 1, 1 1, 1 0))", bg::clockwise);
108    test_one<P>("POLYGON((2 0, 2 1, 3 1, 3 -1, 2 -1, 2 0, 1 0, 1 -1, 0 -1, 0 1, 1 1, 1 0, 2 0))", bg::clockwise);
109    test_one<P>("POLYGON((0 85, 5 85, 5 84, 0 84, 0 85))", bg::clockwise);
110    test_one<P>("POLYGON((0 2, 170 2, 170 0, 0 0, 0 2))", bg::clockwise);
111    test_one<P>("POLYGON((0 2, 170 2, 170 1, 160 1, 10 1, 0 1, 0 2))", bg::clockwise);
112    test_one<P>("POLYGON((0 2, 170 2, 170 -2, 0 -2, 0 2))", bg::clockwise);
113    test_one<P>("POLYGON((5 5, 6 5, 6 6, 6 4, 6 5, 5 5, 5 4, 4 4, 4 6, 5 6, 5 5))", bg::clockwise);
114    test_one<P>("POLYGON((5 5, 6 5, 6 6, 6 4, 6 5, 5 5, 5 6, 4 6, 4 4, 5 4, 5 5))", bg::counterclockwise);
115    test_one<P>("POLYGON((5 5, 6 5, 6 5, 6 6, 6 5, 6 4, 6 5, 6 5, 5 5, 5 4, 4 4, 4 6, 5 6, 5 5))", bg::clockwise);
116 
117    // https://github.com/boostorg/geometry/pull/554
118    test_one<P>("POLYGON((9.8591674311151110 54.602813224425063, 9.8591651519791412 54.602359676428932, 9.8584586199249316 54.602359676428932, 9.8591674311151110 54.602813224425063))",
119                bg::clockwise);
120 }
121 
122 template <typename P>
test_cartesian()123 void test_cartesian()
124 {
125     test_one<P>("POLYGON((0 5, 1 5, 1 6, 1 4, 2 4, 0 4, 0 3, 0 5))", bg::clockwise);
126 }
127 
128 template <typename P>
test_spheroidal()129 void test_spheroidal()
130 {
131     test_one<P>("POLYGON((0 5, 1 5, 1 6, 1 4, 0 4, 0 3, 0 5))", bg::clockwise);
132 
133     test_one<P>("POLYGON((0 45, 120 45, -120 45, 0 45))", bg::counterclockwise);
134 }
135 
test_main(int,char * [])136 int test_main(int, char* [])
137 {
138     test_all<bg::model::point<double, 2, bg::cs::cartesian> >();
139     test_all<bg::model::point<double, 2, bg::cs::spherical_equatorial<bg::degree> > >();
140     test_all<bg::model::point<double, 2, bg::cs::geographic<bg::degree> > >();
141 
142     test_cartesian<bg::model::point<double, 2, bg::cs::cartesian> >();
143 
144     test_spheroidal<bg::model::point<double, 2, bg::cs::spherical_equatorial<bg::degree> > >();
145     test_spheroidal<bg::model::point<double, 2, bg::cs::geographic<bg::degree> > >();
146 
147     return 0;
148 }
149