1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2 // Robustness Test
3
4 // Copyright (c) 2009-2012 Barend Gehrels, Amsterdam, the Netherlands.
5
6 // Use, modification and distribution is subject to the Boost Software License,
7 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
8 // http://www.boost.org/LICENSE_1_0.txt)
9
10 #define BOOST_GEOMETRY_NO_BOOST_TEST
11
12 #include <test_overlay_p_q.hpp>
13
14 #include <boost/program_options.hpp>
15 #include <boost/random/linear_congruential.hpp>
16 #include <boost/random/uniform_int.hpp>
17 #include <boost/random/uniform_real.hpp>
18 #include <boost/random/variate_generator.hpp>
19 #include <boost/timer.hpp>
20
21
22 template <typename Polygon, typename Generator>
make_polygon(Polygon & polygon,Generator & generator,bool triangular)23 inline void make_polygon(Polygon& polygon, Generator& generator, bool triangular)
24 {
25 typedef typename bg::point_type<Polygon>::type point_type;
26 typedef typename bg::coordinate_type<Polygon>::type coordinate_type;
27
28 coordinate_type x, y;
29 x = generator();
30 y = generator();
31
32 typename bg::ring_type<Polygon>::type& ring = bg::exterior_ring(polygon);
33
34 point_type p;
35 bg::set<0>(p, x); bg::set<1>(p, y); ring.push_back(p);
36 bg::set<0>(p, x); bg::set<1>(p, y + 1); ring.push_back(p);
37 bg::set<0>(p, x + 1); bg::set<1>(p, y + 1); ring.push_back(p);
38 bg::set<0>(p, x + 1); bg::set<1>(p, y); ring.push_back(p);
39 bg::set<0>(p, x); bg::set<1>(p, y); ring.push_back(p);
40
41 if (triangular)
42 {
43 // Remove a point depending on generator
44 int c = generator() % 4;
45 if (c >= 1 && c <= 3)
46 {
47 ring.erase(ring.begin() + c);
48 }
49 }
50 }
51
52
53
54 template <typename MultiPolygon, typename Generator>
test_recursive_boxes(MultiPolygon & result,int & index,Generator & generator,int level,bool triangular,p_q_settings const & settings)55 bool test_recursive_boxes(MultiPolygon& result, int& index,
56 Generator& generator,
57 int level, bool triangular, p_q_settings const& settings)
58 {
59 MultiPolygon p, q;
60
61 // Generate two boxes
62 if (level == 0)
63 {
64 p.resize(1);
65 q.resize(1);
66 make_polygon(p.front(), generator, triangular);
67 make_polygon(q.front(), generator, triangular);
68 bg::correct(p);
69 bg::correct(q);
70 }
71 else
72 {
73 bg::correct(p);
74 bg::correct(q);
75 if (! test_recursive_boxes(p, index, generator, level - 1, triangular, settings)
76 || ! test_recursive_boxes(q, index, generator, level - 1, triangular, settings))
77 {
78 return false;
79 }
80 }
81
82 typedef typename boost::range_value<MultiPolygon>::type polygon;
83
84 std::ostringstream out;
85 out << "recursive_box_" << index++ << "_" << level;
86
87 if (! test_overlay_p_q
88 <
89 polygon,
90 typename bg::coordinate_type<MultiPolygon>::type
91 >(out.str(), p, q, settings))
92 {
93 return false;
94 }
95
96 MultiPolygon mp;
97 bg::detail::union_::union_insert
98 <
99 polygon
100 >(p, q, std::back_inserter(mp));
101
102 bg::unique(mp);
103 bg::simplify(mp, result, 0.01);
104 bg::correct(mp);
105 return true;
106 }
107
108
109 template <typename T, bool Clockwise, bool Closed>
test_all(int seed,int count,int field_size,int level,bool triangular,p_q_settings const & settings)110 void test_all(int seed, int count, int field_size, int level, bool triangular, p_q_settings const& settings)
111 {
112 boost::timer t;
113
114 typedef boost::minstd_rand base_generator_type;
115
116 base_generator_type generator(seed);
117
118 boost::uniform_int<> random_coordinate(0, field_size - 1);
119 boost::variate_generator<base_generator_type&, boost::uniform_int<> >
120 coordinate_generator(generator, random_coordinate);
121
122 typedef bg::model::polygon
123 <
124 bg::model::d2::point_xy<T>, Clockwise, Closed
125 > polygon;
126 typedef bg::model::multi_polygon<polygon> mp;
127
128
129 int index = 0;
130 for(int i = 0; i < count; i++)
131 {
132 mp p;
133 test_recursive_boxes<mp>(p, index, coordinate_generator, level, triangular, settings);
134 }
135 std::cout
136 << "polygons: " << index
137 << " type: " << string_from_type<T>::name()
138 << " time: " << t.elapsed() << std::endl;
139 }
140
main(int argc,char ** argv)141 int main(int argc, char** argv)
142 {
143 BoostGeometryWriteTestConfiguration();
144 try
145 {
146 namespace po = boost::program_options;
147 po::options_description description("=== recursive_polygons ===\nAllowed options");
148
149 int count = 1;
150 int seed = static_cast<unsigned int>(std::time(0));
151 int level = 3;
152 int field_size = 10;
153 bool ccw = false;
154 bool open = false;
155 p_q_settings settings;
156 std::string form = "box";
157
158 description.add_options()
159 ("help", "Help message")
160 ("seed", po::value<int>(&seed), "Initialization seed for random generator")
161 ("count", po::value<int>(&count)->default_value(1), "Number of tests")
162 ("diff", po::value<bool>(&settings.also_difference)->default_value(false), "Include testing on difference")
163 ("validity", po::value<bool>(&settings.validity)->default_value(true), "Include testing on validity")
164 ("level", po::value<int>(&level)->default_value(3), "Level to reach (higher->slower)")
165 ("size", po::value<int>(&field_size)->default_value(10), "Size of the field")
166 ("form", po::value<std::string>(&form)->default_value("box"), "Form of the polygons (box, triangle)")
167 ("ccw", po::value<bool>(&ccw)->default_value(false), "Counter clockwise polygons")
168 ("open", po::value<bool>(&open)->default_value(false), "Open polygons")
169 ("wkt", po::value<bool>(&settings.wkt)->default_value(false), "Create a WKT of the inputs, for all tests")
170 ("svg", po::value<bool>(&settings.svg)->default_value(false), "Create a SVG for all tests")
171 ;
172
173 po::variables_map varmap;
174 po::store(po::parse_command_line(argc, argv, description), varmap);
175 po::notify(varmap);
176
177 if (varmap.count("help")
178 || (form != "box" && form != "triangle"))
179 {
180 std::cout << description << std::endl;
181 return 1;
182 }
183
184 bool triangular = form != "box";
185
186
187 if (ccw && open)
188 {
189 test_all<double, false, false>(seed, count, field_size, level, triangular, settings);
190 }
191 else if (ccw)
192 {
193 test_all<double, false, true>(seed, count, field_size, level, triangular, settings);
194 }
195 else if (open)
196 {
197 test_all<double, true, false>(seed, count, field_size, level, triangular, settings);
198 }
199 else
200 {
201 test_all<double, true, true>(seed, count, field_size, level, triangular, settings);
202 }
203
204 #if defined(HAVE_TTMATH)
205 // test_all<ttmath_big, true, true>(seed, count, max, svg, level);
206 #endif
207 }
208 catch(std::exception const& e)
209 {
210 std::cout << "Exception " << e.what() << std::endl;
211 }
212 catch(...)
213 {
214 std::cout << "Other exception" << std::endl;
215 }
216
217 return 0;
218 }
219