]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Boost.Geometry (aka GGL, Generic Geometry Library) // Robustness Test |
2 | ||
3 | // Copyright (c) 2013-2015 Barend Gehrels, Amsterdam, the Netherlands. | |
4 | ||
1e59de90 TL |
5 | // This file was modified by Oracle on 2021. |
6 | // Modifications copyright (c) 2021, Oracle and/or its affiliates. | |
7 | // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle | |
8 | ||
7c673cae FG |
9 | // Use, modification and distribution is subject to the Boost Software License, |
10 | // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at | |
11 | // http://www.boost.org/LICENSE_1_0.txt) | |
12 | ||
13 | // Adapted from: the attachment of ticket 9081 | |
14 | ||
15 | #define CHECK_SELF_INTERSECTIONS | |
16 | #define LIST_WKT | |
17 | ||
1e59de90 TL |
18 | #include <fstream> |
19 | #include <iomanip> | |
20 | #include <iostream> | |
21 | #include <vector> | |
22 | ||
7c673cae | 23 | #include <boost/algorithm/string.hpp> |
1e59de90 TL |
24 | #include <boost/timer.hpp> |
25 | ||
26 | #include <boost/geometry/algorithms/correct.hpp> | |
27 | #include <boost/geometry/algorithms/detail/has_self_intersections.hpp> | |
28 | #include <boost/geometry/algorithms/difference.hpp> | |
29 | #include <boost/geometry/algorithms/intersection.hpp> | |
30 | #include <boost/geometry/algorithms/union.hpp> | |
31 | ||
32 | #include <boost/geometry/geometries/point_xy.hpp> | |
33 | #include <boost/geometry/geometries/polygon.hpp> | |
34 | #include <boost/geometry/geometries/register/point.hpp> | |
35 | #include <boost/geometry/geometries/register/ring.hpp> | |
36 | #include <boost/geometry/geometries/multi_polygon.hpp> | |
37 | ||
7c673cae | 38 | #include <boost/geometry/io/svg/svg_mapper.hpp> |
1e59de90 | 39 | #include <boost/geometry/io/wkt/wkt.hpp> |
7c673cae | 40 | |
1e59de90 | 41 | namespace bg = boost::geometry; |
7c673cae FG |
42 | |
43 | typedef boost::geometry::model::d2::point_xy<double> pt; | |
44 | typedef boost::geometry::model::polygon<pt> polygon; | |
45 | typedef boost::geometry::model::segment<pt> segment; | |
46 | typedef boost::geometry::model::multi_polygon<polygon> multi_polygon; | |
47 | ||
48 | template <typename Geometry> | |
49 | inline void debug_with_svg(int index, char method, Geometry const& a, Geometry const& b, std::string const& headera, std::string const& headerb) | |
50 | { | |
51 | multi_polygon output; | |
52 | try | |
53 | { | |
54 | switch(method) | |
55 | { | |
56 | case 'i': boost::geometry::intersection(a, b, output); break; | |
57 | case 'u': boost::geometry::union_(a, b, output); break; | |
58 | case 'd': boost::geometry::difference(a, b, output); break; | |
59 | case 'v': boost::geometry::difference(b, a, output); break; | |
60 | default : return; | |
61 | } | |
62 | } | |
63 | catch(...) | |
64 | {} | |
65 | ||
66 | std::ostringstream filename; | |
67 | filename << "ticket_9081_" << method << "_" << (1000000 + index) << ".svg"; | |
68 | std::ofstream svg(filename.str().c_str()); | |
69 | ||
70 | boost::geometry::svg_mapper<pt> mapper(svg, 400, 400); | |
71 | mapper.add(a); | |
72 | mapper.add(b); | |
73 | ||
74 | mapper.map(a, "fill-opacity:0.5;fill:rgb(153,204,0);stroke:rgb(153,204,0);stroke-width:2"); | |
75 | mapper.map(b, "fill-opacity:0.3;fill:rgb(51,51,153);stroke:rgb(51,51,153);stroke-width:2"); | |
1e59de90 | 76 | for(polygon const& g : output) |
7c673cae FG |
77 | { |
78 | mapper.map(g, "opacity:0.8;fill:none;stroke:rgb(255,128,0);stroke-width:4;stroke-dasharray:1,7;stroke-linecap:round"); | |
79 | } | |
80 | ||
81 | std::ostringstream out; | |
82 | out << headera << std::endl << headerb; | |
83 | mapper.map(boost::geometry::return_centroid<pt>(a), "fill:rgb(152,204,0);stroke:rgb(153,204,0);stroke-width:0.1", 3); | |
84 | mapper.map(boost::geometry::return_centroid<pt>(b), "fill:rgb(51,51,153);stroke:rgb(153,204,0);stroke-width:0.1", 3); | |
85 | mapper.text(boost::geometry::return_centroid<pt>(a), headera, "fill:rgb(0,0,0);font-family:Arial;font-size:10px"); | |
86 | mapper.text(boost::geometry::return_centroid<pt>(b), headerb, "fill:rgb(0,0,0);font-family:Arial;font-size:10px"); | |
87 | } | |
88 | ||
89 | int main() | |
90 | { | |
91 | int num_orig = 50; | |
92 | int num_rounds = 30000; | |
93 | srand(1234); | |
94 | std::cout << std::setprecision(16); | |
95 | std::map<int, std::string> genesis; | |
96 | int pj; | |
97 | ||
98 | ||
99 | std::string wkt1, wkt2, operation; | |
100 | ||
1e59de90 TL |
101 | |
102 | typename bg::strategies::relate::services::default_strategy | |
103 | < | |
104 | multi_polygon, multi_polygon | |
105 | >::type strategy; | |
106 | ||
107 | using rescale_policy_type = typename bg::rescale_policy_type<pt>::type; | |
108 | ||
7c673cae FG |
109 | try |
110 | { | |
111 | ||
112 | ||
113 | boost::timer t; | |
114 | std::vector<multi_polygon> poly_list; | |
115 | ||
1e59de90 | 116 | for (int i = 0 ; i < num_orig ; i++) |
7c673cae FG |
117 | { |
118 | multi_polygon mp; | |
119 | polygon p; | |
1e59de90 | 120 | for (int j = 0 ; j < 3 ; j++) |
7c673cae | 121 | { |
1e59de90 TL |
122 | double x = (double)rand()/RAND_MAX; |
123 | double y = (double)rand()/RAND_MAX; | |
7c673cae FG |
124 | p.outer().push_back(pt(x,y)); |
125 | } | |
1e59de90 | 126 | bg::correct(p); |
7c673cae | 127 | mp.push_back(p); |
1e59de90 TL |
128 | |
129 | rescale_policy_type robust_policy | |
130 | = bg::get_rescale_policy<rescale_policy_type>(mp, strategy); | |
131 | ||
132 | bg::detail::overlay::has_self_intersections(mp, strategy, robust_policy); | |
7c673cae FG |
133 | |
134 | std::ostringstream out; | |
135 | out << "original " << poly_list.size(); | |
136 | genesis[poly_list.size()] = out.str(); | |
137 | poly_list.push_back(mp); | |
138 | ||
139 | #ifdef LIST_WKT | |
140 | std::cout << "Original " << i << " " << boost::geometry::wkt(p) << std::endl; | |
141 | #endif | |
142 | } | |
143 | ||
144 | ||
1e59de90 | 145 | for (int j = 0 ; j < num_rounds ; j++) |
7c673cae FG |
146 | { |
147 | if (j % 100 == 0) { std::cout << " " << j; } | |
148 | pj = j; | |
149 | int a = rand() % poly_list.size(); | |
150 | int b = rand() % poly_list.size(); | |
151 | ||
152 | debug_with_svg(j, 'i', poly_list[a], poly_list[b], genesis[a], genesis[b]); | |
153 | ||
154 | { std::ostringstream out; out << boost::geometry::wkt(poly_list[a]); wkt1 = out.str(); } | |
155 | { std::ostringstream out; out << boost::geometry::wkt(poly_list[b]); wkt2 = out.str(); } | |
156 | ||
157 | multi_polygon mp_i, mp_u, mp_d, mp_e; | |
158 | operation = "intersection"; | |
159 | boost::geometry::intersection(poly_list[a],poly_list[b],mp_i); | |
160 | operation = "intersection"; | |
161 | boost::geometry::union_(poly_list[a],poly_list[b],mp_u); | |
162 | operation = "difference"; | |
163 | boost::geometry::difference(poly_list[a],poly_list[b],mp_d); | |
164 | boost::geometry::difference(poly_list[b],poly_list[a],mp_e); | |
165 | ||
166 | #ifdef LIST_WKT | |
167 | std::cout << j << std::endl; | |
168 | std::cout << " Genesis a " << genesis[a] << std::endl; | |
169 | std::cout << " Genesis b " << genesis[b] << std::endl; | |
170 | std::cout << " Intersection " << boost::geometry::wkt(mp_i) << std::endl; | |
171 | std::cout << " Difference a " << boost::geometry::wkt(mp_d) << std::endl; | |
172 | std::cout << " Difference b " << boost::geometry::wkt(mp_e) << std::endl; | |
173 | #endif | |
174 | ||
175 | #ifdef CHECK_SELF_INTERSECTIONS | |
1e59de90 TL |
176 | |
177 | rescale_policy_type robust_policy_i | |
178 | = bg::get_rescale_policy<rescale_policy_type>(mp_i, strategy); | |
179 | ||
7c673cae FG |
180 | try |
181 | { | |
1e59de90 | 182 | boost::geometry::detail::overlay::has_self_intersections(mp_i, strategy, robust_policy_i); |
7c673cae FG |
183 | } |
184 | catch(...) | |
185 | { | |
186 | std::cout << "FAILED TO INTERSECT " << j << std::endl; | |
187 | std::cout << boost::geometry::wkt(poly_list[a]) << std::endl; | |
188 | std::cout << boost::geometry::wkt(poly_list[b]) << std::endl; | |
189 | std::cout << boost::geometry::wkt(mp_i) << std::endl; | |
190 | try | |
191 | { | |
1e59de90 | 192 | boost::geometry::detail::overlay::has_self_intersections(mp_i, strategy, robust_policy_i); |
7c673cae FG |
193 | } |
194 | catch(...) | |
195 | { | |
196 | } | |
197 | break; | |
198 | } | |
199 | ||
1e59de90 TL |
200 | rescale_policy_type robust_policy_d |
201 | = bg::get_rescale_policy<rescale_policy_type>(mp_d, strategy); | |
202 | ||
7c673cae FG |
203 | try |
204 | { | |
1e59de90 | 205 | boost::geometry::detail::overlay::has_self_intersections(mp_d, strategy, robust_policy_d); |
7c673cae FG |
206 | } |
207 | catch(...) | |
208 | { | |
209 | std::cout << "FAILED TO SUBTRACT " << j << std::endl; | |
210 | std::cout << boost::geometry::wkt(poly_list[a]) << std::endl; | |
211 | std::cout << boost::geometry::wkt(poly_list[b]) << std::endl; | |
212 | std::cout << boost::geometry::wkt(mp_d) << std::endl; | |
213 | break; | |
214 | } | |
1e59de90 TL |
215 | |
216 | rescale_policy_type robust_policy_e | |
217 | = bg::get_rescale_policy<rescale_policy_type>(mp_e, strategy); | |
218 | ||
7c673cae FG |
219 | try |
220 | { | |
1e59de90 | 221 | boost::geometry::detail::overlay::has_self_intersections(mp_e, strategy, robust_policy_e); |
7c673cae FG |
222 | } |
223 | catch(...) | |
224 | { | |
225 | std::cout << "FAILED TO SUBTRACT " << j << std::endl; | |
226 | std::cout << boost::geometry::wkt(poly_list[b]) << std::endl; | |
227 | std::cout << boost::geometry::wkt(poly_list[a]) << std::endl; | |
228 | std::cout << boost::geometry::wkt(mp_e) << std::endl; | |
229 | break; | |
230 | } | |
231 | #endif | |
232 | ||
233 | if(boost::geometry::area(mp_i) > 0) | |
234 | { | |
235 | std::ostringstream out; | |
236 | out << j << " intersection(" << genesis[a] << " , " << genesis[b] << ")"; | |
237 | genesis[poly_list.size()] = out.str(); | |
238 | poly_list.push_back(mp_i); | |
239 | } | |
240 | if(boost::geometry::area(mp_d) > 0) | |
241 | { | |
242 | std::ostringstream out; | |
243 | out << j << " difference(" << genesis[a] << " - " << genesis[b] << ")"; | |
244 | genesis[poly_list.size()] = out.str(); | |
245 | poly_list.push_back(mp_d); | |
246 | } | |
247 | if(boost::geometry::area(mp_e) > 0) | |
248 | { | |
249 | std::ostringstream out; | |
250 | out << j << " difference(" << genesis[b] << " - " << genesis[a] << ")"; | |
251 | genesis[poly_list.size()] = out.str(); | |
252 | poly_list.push_back(mp_e); | |
253 | } | |
254 | } | |
255 | ||
256 | std::cout << "FINISHED " << t.elapsed() << std::endl; | |
257 | ||
258 | } | |
259 | catch(std::exception const& e) | |
260 | { | |
261 | std::cout << e.what() | |
262 | << " in " << operation << " at " << pj << std::endl | |
263 | << wkt1 << std::endl | |
264 | << wkt2 << std::endl | |
265 | << std::endl; | |
266 | } | |
267 | catch(...) | |
268 | { | |
269 | std::cout << "Other exception" << std::endl; | |
270 | } | |
271 | ||
272 | return 0; | |
273 | } |