• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2 
3 // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
4 // Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
5 // Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
6 
7 // This file was modified by Oracle on 2014, 2016, 2017, 2018.
8 // Modifications copyright (c) 2014-2018 Oracle and/or its affiliates.
9 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
10 
11 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
12 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
13 
14 // Use, modification and distribution is subject to the Boost Software License,
15 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
16 // http://www.boost.org/LICENSE_1_0.txt)
17 
18 #ifndef BOOST_GEOMETRY_TEST_ALGORITHMS_OVERLAY_TEST_GET_TURNS_HPP
19 #define BOOST_GEOMETRY_TEST_ALGORITHMS_OVERLAY_TEST_GET_TURNS_HPP
20 
21 #include <iostream>
22 #include <iomanip>
23 
24 #include <geometry_test_common.hpp>
25 
26 #include <boost/geometry/strategies/strategies.hpp>
27 
28 #include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
29 
30 #include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
31 
32 #include <boost/geometry/io/wkt/read.hpp>
33 #include <boost/geometry/io/wkt/write.hpp>
34 
35 struct expected_pusher
36     : std::vector<std::string>
37 {
operator ()expected_pusher38     expected_pusher & operator()(std::string const& ex)
39     {
40         std::vector<std::string>::push_back(ex);
41         return *this;
42     }
43 };
44 
expected(std::string const & ex)45 inline expected_pusher expected(std::string const& ex)
46 {
47     expected_pusher res;
48     return res(ex);
49 }
50 
51 struct equal_turn
52 {
equal_turnequal_turn53     equal_turn(std::string const& s) : turn_ptr(&s) {}
54 
55     template <typename T>
operator ()equal_turn56     bool operator()(T const& t) const
57     {
58         std::string const& s = (*turn_ptr);
59         std::string::size_type const count = s.size();
60 
61         return (count > 0
62                ? bg::method_char(t.method) == s[0]
63                : true)
64             && (count > 1
65                 ? bg::operation_char(t.operations[0].operation) == s[1]
66                 : true)
67             && (count > 2
68                 ? bg::operation_char(t.operations[1].operation) == s[2]
69                 : true)
70             && equal_operations_ex(t.operations[0], t.operations[1], s);
71     }
72 
73     template <typename P, typename R>
equal_operations_exequal_turn74     static bool equal_operations_ex(bg::detail::overlay::turn_operation<P, R> const& /*op0*/,
75                                     bg::detail::overlay::turn_operation<P, R> const& /*op1*/,
76                                     std::string const& /*s*/)
77     {
78         return true;
79     }
80 
81     template <typename P, typename R>
equal_operations_exequal_turn82     static bool equal_operations_ex(bg::detail::overlay::turn_operation_linear<P, R> const& op0,
83                                     bg::detail::overlay::turn_operation_linear<P, R> const& op1,
84                                     std::string const& s)
85     {
86         std::string::size_type const count = s.size();
87 
88         return (count > 3
89                ? is_colinear_char(op0.is_collinear) == s[3]
90                : true)
91             && (count > 4
92                ? is_colinear_char(op1.is_collinear) == s[4]
93                : true);
94     }
95 
is_colinear_charequal_turn96     static char is_colinear_char(bool is_collinear)
97     {
98         return is_collinear ? '=' : '+';
99     }
100 
101     const std::string * turn_ptr;
102 };
103 
104 template <typename Turns>
105 struct turns_printer
106 {
turns_printerturns_printer107     turns_printer(Turns const& t) : turns(t) {}
108 
operator <<(std::ostream & os,turns_printer const & tp)109     friend std::ostream & operator<<(std::ostream & os, turns_printer const& tp)
110     {
111         std::vector<std::string> vec(tp.turns.size());
112         std::transform(tp.turns.begin(), tp.turns.end(), vec.begin(), to_string());
113         std::sort(vec.begin(), vec.end());
114         std::copy(vec.begin(), vec.end(), std::ostream_iterator<std::string>(os, " "));
115         return os;
116     }
117 
118     struct to_string
119     {
120         template <typename P, typename R>
operator ()turns_printer::to_string121         std::string operator()(bg::detail::overlay::turn_info<P, R, bg::detail::overlay::turn_operation<P, R> > const& t) const
122         {
123             std::string res(3, ' ');
124             res[0] = bg::method_char(t.method);
125             res[1] = bg::operation_char(t.operations[0].operation);
126             res[2] = bg::operation_char(t.operations[1].operation);
127             return res;
128         }
129 
130         template <typename P, typename R>
operator ()turns_printer::to_string131         std::string operator()(bg::detail::overlay::turn_info<P, R, bg::detail::overlay::turn_operation_linear<P, R> > const& t) const
132         {
133             std::string res(5, ' ');
134             res[0] = bg::method_char(t.method);
135             res[1] = bg::operation_char(t.operations[0].operation);
136             res[2] = bg::operation_char(t.operations[1].operation);
137             res[3] = equal_turn::is_colinear_char(t.operations[0].is_collinear);
138             res[4] = equal_turn::is_colinear_char(t.operations[1].is_collinear);
139             return res;
140         }
141     };
142 
143     Turns const& turns;
144 };
145 
146 template <>
147 struct turns_printer<expected_pusher>
148 {
turns_printerturns_printer149     turns_printer(expected_pusher const& t) : turns(t) {}
150 
operator <<(std::ostream & os,turns_printer const & tp)151     friend std::ostream & operator<<(std::ostream & os, turns_printer const& tp)
152     {
153         std::vector<std::string> vec(tp.turns.size());
154         std::copy(tp.turns.begin(), tp.turns.end(), vec.begin());
155         std::sort(vec.begin(), vec.end());
156         std::copy(vec.begin(), vec.end(), std::ostream_iterator<std::string>(os, " "));
157         return os;
158     }
159 
160     expected_pusher const& turns;
161 };
162 
163 template <typename Geometry1, typename Geometry2, typename Expected, typename Strategy>
check_geometry_range(Geometry1 const & g1,Geometry2 const & g2,std::string const & wkt1,std::string const & wkt2,Expected const & expected,Strategy const & strategy)164 void check_geometry_range(Geometry1 const& g1,
165                           Geometry2 const& g2,
166                           std::string const& wkt1,
167                           std::string const& wkt2,
168                           Expected const& expected,
169                           Strategy const& strategy)
170 {
171     typedef bg::detail::no_rescale_policy robust_policy_type;
172     typedef typename bg::point_type<Geometry2>::type point_type;
173 
174     typedef typename bg::detail::segment_ratio_type
175         <
176             point_type, robust_policy_type
177         >::type segment_ratio_type;
178 
179     typedef bg::detail::overlay::turn_info
180         <
181             typename bg::point_type<Geometry2>::type,
182             segment_ratio_type,
183             typename bg::detail::get_turns::turn_operation_type
184             <
185                 Geometry1,
186                 Geometry2,
187                 segment_ratio_type
188             >::type
189         > turn_info;
190     typedef bg::detail::overlay::assign_null_policy assign_policy_t;
191     typedef bg::detail::get_turns::no_interrupt_policy interrupt_policy_t;
192 
193     std::vector<turn_info> detected;
194     interrupt_policy_t interrupt_policy;
195     robust_policy_type robust_policy;
196 
197     // Don't switch the geometries
198     typedef bg::detail::get_turns::get_turn_info_type
199         <
200             Geometry1, Geometry2, assign_policy_t
201         > turn_policy_t;
202 
203     bg::dispatch::get_turns
204         <
205             typename bg::tag<Geometry1>::type, typename bg::tag<Geometry2>::type,
206             Geometry1, Geometry2, false, false,
207             turn_policy_t
208         >::apply(0, g1, 1, g2, strategy, robust_policy, detected, interrupt_policy);
209 
210     bool ok = boost::size(expected) == detected.size();
211 
212     BOOST_CHECK_MESSAGE(ok,
213         "get_turns: " << wkt1 << " and " << wkt2
214         << " -> Expected turns #: " << boost::size(expected) << " detected turns #: " << detected.size());
215 
216     if (ok)
217     {
218         std::vector<turn_info> turns = detected;
219 
220         for ( typename boost::range_iterator<Expected const>::type sit = boost::begin(expected) ;
221               sit != boost::end(expected) ; ++sit)
222         {
223             typename std::vector<turn_info>::iterator
224                 it = std::find_if(turns.begin(), turns.end(), equal_turn(*sit));
225 
226             if ( it != turns.end() )
227             {
228                 turns.erase(it);
229             }
230             else
231             {
232                 ok = false;
233                 break;
234             }
235         }
236     }
237 
238     if ( !ok )
239     {
240         BOOST_CHECK_MESSAGE(false,
241             "get_turns: " << wkt1 << " and " << wkt2
242             << " -> Expected turns: " << turns_printer<Expected>(expected)
243             << "Detected turns: " << turns_printer<std::vector<turn_info> >(detected));
244 
245 #ifdef BOOST_GEOMETRY_TEST_DEBUG
246         std::cout << "Coordinates: "
247                   << typeid(typename bg::coordinate_type<Geometry1>::type).name()
248                   << ", "
249                   << typeid(typename bg::coordinate_type<Geometry2>::type).name()
250                   << std::endl;
251 #endif
252     }
253 }
254 
255 template <typename Geometry1, typename Geometry2, typename Expected>
check_geometry_range(Geometry1 const & g1,Geometry2 const & g2,std::string const & wkt1,std::string const & wkt2,Expected const & expected)256 void check_geometry_range(Geometry1 const& g1,
257                           Geometry2 const& g2,
258                           std::string const& wkt1,
259                           std::string const& wkt2,
260                           Expected const& expected)
261 {
262     typename bg::strategy::intersection::services::default_strategy
263         <
264             typename bg::cs_tag<Geometry1>::type
265         >::type strategy;
266 
267     check_geometry_range(g1, g2, wkt1, wkt2, expected, strategy);
268 }
269 
270 template <typename Geometry1, typename Geometry2, typename Expected, typename Strategy>
test_geometry_range(std::string const & wkt1,std::string const & wkt2,Expected const & expected,Strategy const & strategy)271 void test_geometry_range(std::string const& wkt1, std::string const& wkt2,
272                          Expected const& expected, Strategy const& strategy)
273 {
274     Geometry1 geometry1;
275     Geometry2 geometry2;
276     bg::read_wkt(wkt1, geometry1);
277     bg::read_wkt(wkt2, geometry2);
278     check_geometry_range(geometry1, geometry2, wkt1, wkt2, expected, strategy);
279 }
280 
281 template <typename Geometry1, typename Geometry2, typename Expected>
test_geometry_range(std::string const & wkt1,std::string const & wkt2,Expected const & expected)282 void test_geometry_range(std::string const& wkt1, std::string const& wkt2,
283                          Expected const& expected)
284 {
285     Geometry1 geometry1;
286     Geometry2 geometry2;
287     bg::read_wkt(wkt1, geometry1);
288     bg::read_wkt(wkt2, geometry2);
289     check_geometry_range(geometry1, geometry2, wkt1, wkt2, expected);
290 }
291 
292 template <typename G1, typename G2>
test_geometry(std::string const & wkt1,std::string const & wkt2,std::string const & ex0)293 void test_geometry(std::string const& wkt1, std::string const& wkt2,
294                    std::string const& ex0)
295 {
296     test_geometry_range<G1, G2>(wkt1, wkt2, expected(ex0));
297 }
298 
299 template <typename G1, typename G2>
test_geometry(std::string const & wkt1,std::string const & wkt2,std::string const & ex0,std::string const & ex1)300 void test_geometry(std::string const& wkt1, std::string const& wkt2,
301     std::string const& ex0, std::string const& ex1)
302 {
303     test_geometry_range<G1, G2>(wkt1, wkt2, expected(ex0)(ex1));
304 }
305 
306 template <typename G1, typename G2>
test_geometry(std::string const & wkt1,std::string const & wkt2,std::string const & ex0,std::string const & ex1,std::string const & ex2)307 void test_geometry(std::string const& wkt1, std::string const& wkt2,
308     std::string const& ex0, std::string const& ex1, std::string const& ex2)
309 {
310     test_geometry_range<G1, G2>(wkt1, wkt2, expected(ex0)(ex1)(ex2));
311 }
312 
313 template <typename G1, typename G2>
test_geometry(std::string const & wkt1,std::string const & wkt2,expected_pusher const & expected)314 void test_geometry(std::string const& wkt1, std::string const& wkt2,
315                    expected_pusher const& expected)
316 {
317     test_geometry_range<G1, G2>(wkt1, wkt2, expected);
318 }
319 
320 template <typename G1, typename G2, typename Strategy>
test_geometry(std::string const & wkt1,std::string const & wkt2,expected_pusher const & expected,Strategy const & strategy)321 void test_geometry(std::string const& wkt1, std::string const& wkt2,
322                    expected_pusher const& expected,
323                    Strategy const& strategy)
324 {
325     test_geometry_range<G1, G2>(wkt1, wkt2, expected, strategy);
326 }
327 
328 #endif // BOOST_GEOMETRY_TEST_ALGORITHMS_OVERLAY_TEST_GET_TURNS_HPP
329