1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2
3 // Copyright (c) 2014-2020, Oracle and/or its affiliates.
4
5 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
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 #ifndef BOOST_GEOMETRY_TEST_SET_OPS_POINTLIKE_HPP
12 #define BOOST_GEOMETRY_TEST_SET_OPS_POINTLIKE_HPP
13
14
15 #include <boost/geometry/geometry.hpp>
16
17 namespace bg = ::boost::geometry;
18
19 #include <from_wkt.hpp>
20 #include <to_svg.hpp>
21
22 #include <algorithm>
23 #include <fstream>
24 #include <boost/core/ignore_unused.hpp>
25 #include <boost/typeof/typeof.hpp>
26
27 #include <boost/geometry/policies/compare.hpp>
28 #include <boost/geometry/algorithms/equals.hpp>
29
30 #include <boost/geometry/algorithms/union.hpp>
31 #include <boost/geometry/algorithms/difference.hpp>
32 #include <boost/geometry/algorithms/intersection.hpp>
33 #include <boost/geometry/algorithms/sym_difference.hpp>
34
35 #include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
36
37
38 //==================================================================
39 //==================================================================
40 // svg output
41 //==================================================================
42 //==================================================================
43
44 template <typename Output, typename G1, typename G2>
set_operation_output(std::string const & set_op_id,std::string const & caseid,G1 const & g1,G2 const & g2,Output const & output)45 void set_operation_output(std::string const& set_op_id,
46 std::string const& caseid,
47 G1 const& g1, G2 const& g2,
48 Output const& output)
49 {
50 boost::ignore_unused(set_op_id, caseid, g1, g2, output);
51
52 #if defined(TEST_WITH_SVG)
53 typedef typename bg::coordinate_type<G1>::type coordinate_type;
54 typedef typename bg::point_type<G1>::type point_type;
55
56 std::ostringstream filename;
57 filename << "svgs/" << set_op_id << "_" << caseid << ".svg";
58
59 std::ofstream svg(filename.str().c_str());
60
61 bg::svg_mapper<point_type> mapper(svg, 500, 500);
62
63 mapper.add(g1);
64 mapper.add(g2);
65
66 mapper.map(g2, "stroke-opacity:1;stroke:rgb(153,204,0);stroke-width:4");
67 mapper.map(g1, "stroke-opacity:1;stroke:rgb(51,51,153);stroke-width:2");
68
69 BOOST_AUTO_TPL(it, output.begin());
70 for (; it != output.end(); ++it)
71 {
72 mapper.map(*it,
73 "fill:rgb(255,0,255);stroke:rgb(0,0,0);stroke-width:1",
74 4);
75 }
76 #endif
77 }
78
79
80 //==================================================================
81 //==================================================================
82 // testing equality of multi-points
83 //==================================================================
84 //==================================================================
85
86
87 struct equals
88 {
89 template <typename MultiPoint1, typename MultiPoint2>
applyequals90 static inline bool apply(MultiPoint1 const& multipoint1,
91 MultiPoint2 const& multipoint2)
92 {
93 MultiPoint1 mp1(multipoint1);
94 MultiPoint2 mp2(multipoint2);
95
96 std::sort(mp1.begin(), mp1.end(),
97 bg::less<typename bg::point_type<MultiPoint1>::type>());
98 std::sort(mp2.begin(), mp2.end(),
99 bg::less<typename bg::point_type<MultiPoint2>::type>());
100
101 if ( boost::size(mp1) != boost::size(mp2) )
102 {
103 return false;
104 }
105
106 BOOST_AUTO_TPL(it1, boost::begin(mp1));
107 BOOST_AUTO_TPL(it2, boost::begin(mp2));
108 for (; it1 != boost::end(mp1); ++it1, ++it2)
109 {
110 if ( !bg::equals(*it1, *it2) )
111 {
112 return false;
113 }
114 }
115 return true;
116 }
117 };
118
119
120
121 //==================================================================
122 //==================================================================
123 // struct for calling the appropriate set op function
124 //==================================================================
125 //==================================================================
126
127 template <bg::overlay_type OverlayType> struct set_op;
128
129
130 template<>
131 struct set_op<bg::overlay_difference>
132 {
nameset_op133 static inline std::string name() { return "difference"; }
134
135 template <typename Geometry1, typename Geometry2, typename GeometryOut>
applyset_op136 static inline void apply(Geometry1 const& g1,
137 Geometry2 const& g2,
138 GeometryOut& gout)
139 {
140 bg::difference(g1, g2, gout);
141 }
142 };
143
144
145 template<>
146 struct set_op<bg::overlay_union>
147 {
nameset_op148 static inline std::string name() { return "union"; }
149
150 template <typename Geometry1, typename Geometry2, typename GeometryOut>
applyset_op151 static inline void apply(Geometry1 const& g1,
152 Geometry2 const& g2,
153 GeometryOut& gout)
154 {
155 bg::union_(g1, g2, gout);
156 }
157 };
158
159
160 template<>
161 struct set_op<bg::overlay_intersection>
162 {
nameset_op163 static inline std::string name() { return "intersection"; }
164
165 template <typename Geometry1, typename Geometry2, typename GeometryOut>
applyset_op166 static inline void apply(Geometry1 const& g1,
167 Geometry2 const& g2,
168 GeometryOut& gout)
169 {
170 bg::intersection(g1, g2, gout);
171 }
172 };
173
174
175 template
176 <
177 typename Geometry,
178 typename Tag = typename bg::tag<Geometry>::type
179 > struct geometry_info
180 {};
181
182 template <typename Point>
183 struct geometry_info<Point, bg::point_tag>
184 {
185 static std::size_t const topological_dimension = 0;
186
namegeometry_info187 static inline char const* name() { return "Pt"; }
188 };
189
190 template <typename MultiPoint>
191 struct geometry_info<MultiPoint, bg::multi_point_tag>
192 {
193 static std::size_t const topological_dimension = 0;
194
namegeometry_info195 static inline char const* name() { return "MPt"; }
196 };
197
198 template <typename Linestring>
199 struct geometry_info<Linestring, bg::linestring_tag>
200 {
201 static std::size_t const topological_dimension = 1;
202
namegeometry_info203 static inline char const* name() { return "L"; }
204 };
205
206 template <typename MultiLinestring>
207 struct geometry_info<MultiLinestring, bg::multi_linestring_tag>
208 {
209 static std::size_t const topological_dimension = 1;
210
namegeometry_info211 static inline char const* name() { return "ML"; }
212 };
213
214 template <typename Segment>
215 struct geometry_info<Segment, bg::segment_tag>
216 {
217 static std::size_t const topological_dimension = 1;
218
namegeometry_info219 static inline char const* name() { return "S"; }
220 };
221
222 template <typename Ring>
223 struct geometry_info<Ring, bg::ring_tag>
224 {
225 static std::size_t const topological_dimension = 2;
226
namegeometry_info227 static inline char const* name() { return "R"; }
228 };
229
230 template <typename Polygon>
231 struct geometry_info<Polygon, bg::polygon_tag>
232 {
233 static std::size_t const topological_dimension = 2;
234
namegeometry_info235 static inline char const* name() { return "Po"; }
236 };
237
238 template <typename MultiPolygon>
239 struct geometry_info<MultiPolygon, bg::multi_polygon_tag>
240 {
241 static std::size_t const topological_dimension = 2;
242
namegeometry_info243 static inline char const* name() { return "MPo"; }
244 };
245
246 //==================================================================
247 //==================================================================
248 // test the set operation of (point-like) geometries
249 //==================================================================
250 //==================================================================
251
252
253 template
254 <
255 typename Geometry1,
256 typename Geometry2,
257 typename MultiPoint,
258 bg::overlay_type OverlayType
259 >
260 class test_set_op_of_pointlike_geometries
261 {
262 private:
263 template <bool Enable, typename Dummy = void>
264 struct base_test
265 {
266 template <typename G1, typename G2, typename MP>
applytest_set_op_of_pointlike_geometries::base_test267 static inline void apply(std::string const& case_id,
268 G1 const& geometry1,
269 G2 const& geometry2,
270 MP const& mp_expected)
271 {
272 MultiPoint mp_output;
273
274 set_op<OverlayType>::apply(geometry1, geometry2, mp_output);
275
276 std::string op_name = set_op<OverlayType>::name();
277
278 BOOST_CHECK_MESSAGE(equals::apply(mp_expected, mp_output),
279 "case ID: " << case_id << ", "
280 << op_name << " "
281 << geometry_info<G1>::name() << "/"
282 << geometry_info<G2>::name() << ": "
283 << bg::wkt(geometry1)
284 << " " << bg::wkt(geometry2)
285 << " -> Expected: " << bg::wkt(mp_expected)
286 << " computed: " << bg::wkt(mp_output) );
287
288 set_operation_output(op_name, case_id,
289 geometry1, geometry2, mp_output);
290
291 #ifdef BOOST_GEOMETRY_TEST_DEBUG
292 std::cout << "Geometry #1: " << bg::wkt(geometry1) << std::endl;
293 std::cout << "Geometry #2: " << bg::wkt(geometry2) << std::endl;
294 std::cout << "expected " << op_name << " : "
295 << bg::wkt(mp_expected) << std::endl;
296 std::cout << op_name << " : " << bg::wkt(mp_output) << std::endl;
297 std::cout << std::endl;
298 std::cout << "************************************" << std::endl;
299 std::cout << std::endl;
300 std::cout << std::endl;
301 #endif
302 }
303 };
304
305 template <typename Dummy>
306 struct base_test<false, Dummy>
307 {
308 template <typename G1, typename G2, typename MP>
applytest_set_op_of_pointlike_geometries::base_test309 static inline void apply(std::string const&, G1 const&, G2 const&,
310 MP const&)
311 {
312 }
313 };
314
315 public:
apply(std::string const & case_id,Geometry1 const & geometry1,Geometry2 const & geometry2,MultiPoint const & mp_expected12,MultiPoint const & mp_expected21)316 static inline void apply(std::string const& case_id,
317 Geometry1 const& geometry1,
318 Geometry2 const& geometry2,
319 MultiPoint const& mp_expected12,
320 MultiPoint const& mp_expected21)
321 {
322 #ifdef BOOST_GEOMETRY_TEST_DEBUG
323 std::cout << "test case: " << case_id << std::endl;
324 #endif
325
326 base_test<true>::apply(case_id, geometry1, geometry2, mp_expected12);
327 // try the same set operation with the arguments' order
328 // reversed only if the two geometries are of the same
329 // topological dimension
330 base_test
331 <
332 (geometry_info<Geometry1>::topological_dimension
333 == geometry_info<Geometry2>::topological_dimension)
334 >::apply(case_id, geometry2, geometry1, mp_expected21);
335
336 #ifdef BOOST_GEOMETRY_TEST_DEBUG
337 std::cout << std::endl;
338 std::cout << std::endl;
339 #endif
340 }
341
apply(std::string const & case_id,Geometry1 const & geometry1,Geometry2 const & geometry2,MultiPoint const & mp_expected)342 static inline void apply(std::string const& case_id,
343 Geometry1 const& geometry1,
344 Geometry2 const& geometry2,
345 MultiPoint const& mp_expected)
346 {
347 apply(case_id, geometry1, geometry2, mp_expected, mp_expected);
348 }
349 };
350
351
352 #endif // BOOST_GEOMETRY_TEST_SET_OPS_POINTLIKE_HPP
353