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