1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2
3 // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
4
5 // This file was modified by Oracle on 2017.
6 // Modifications copyright (c) 2017, Oracle and/or its affiliates.
7 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
8
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 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_BACKTRACK_CHECK_SI_HPP
14 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_BACKTRACK_CHECK_SI_HPP
15
16 #include <cstddef>
17 #include <string>
18
19 #include <boost/range.hpp>
20
21 #include <boost/geometry/core/access.hpp>
22 #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
23 #include <boost/geometry/algorithms/detail/has_self_intersections.hpp>
24 #if defined(BOOST_GEOMETRY_DEBUG_INTERSECTION) || defined(BOOST_GEOMETRY_OVERLAY_REPORT_WKT)
25 # include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
26 # include <boost/geometry/io/wkt/wkt.hpp>
27 #endif
28
29 namespace boost { namespace geometry
30 {
31
32 #ifndef DOXYGEN_NO_DETAIL
33 namespace detail { namespace overlay
34 {
35
36 template <typename Turns>
clear_visit_info(Turns & turns)37 inline void clear_visit_info(Turns& turns)
38 {
39 typedef typename boost::range_value<Turns>::type tp_type;
40
41 for (typename boost::range_iterator<Turns>::type
42 it = boost::begin(turns);
43 it != boost::end(turns);
44 ++it)
45 {
46 for (typename boost::range_iterator
47 <
48 typename tp_type::container_type
49 >::type op_it = boost::begin(it->operations);
50 op_it != boost::end(it->operations);
51 ++op_it)
52 {
53 op_it->visited.clear();
54 }
55 }
56 }
57
58 struct backtrack_state
59 {
60 bool m_good;
61
backtrack_stateboost::geometry::detail::overlay::backtrack_state62 inline backtrack_state() : m_good(true) {}
resetboost::geometry::detail::overlay::backtrack_state63 inline void reset() { m_good = true; }
goodboost::geometry::detail::overlay::backtrack_state64 inline bool good() const { return m_good; }
65 };
66
67
68 enum traverse_error_type
69 {
70 traverse_error_none,
71 traverse_error_no_next_ip_at_start,
72 traverse_error_no_next_ip,
73 traverse_error_dead_end_at_start,
74 traverse_error_dead_end,
75 traverse_error_visit_again,
76 traverse_error_endless_loop
77 };
78
traverse_error_string(traverse_error_type error)79 inline std::string traverse_error_string(traverse_error_type error)
80 {
81 switch (error)
82 {
83 case traverse_error_none : return "";
84 case traverse_error_no_next_ip_at_start : return "No next IP at start";
85 case traverse_error_no_next_ip : return "No next IP";
86 case traverse_error_dead_end_at_start : return "Dead end at start";
87 case traverse_error_dead_end : return "Dead end";
88 case traverse_error_visit_again : return "Visit again";
89 case traverse_error_endless_loop : return "Endless loop";
90 default : return "";
91 }
92 return "";
93 }
94
95
96 template
97 <
98 typename Geometry1,
99 typename Geometry2
100 >
101 class backtrack_check_self_intersections
102 {
103 struct state : public backtrack_state
104 {
105 bool m_checked;
stateboost::geometry::detail::overlay::backtrack_check_self_intersections::state106 inline state()
107 : m_checked(true)
108 {}
109 };
110 public :
111 typedef state state_type;
112
113 template
114 <
115 typename Operation,
116 typename Rings, typename Ring, typename Turns,
117 typename Strategy,
118 typename RobustPolicy,
119 typename Visitor
120 >
apply(std::size_t size_at_start,Rings & rings,Ring & ring,Turns & turns,typename boost::range_value<Turns>::type const & turn,Operation & operation,traverse_error_type traverse_error,Geometry1 const & geometry1,Geometry2 const & geometry2,Strategy const & strategy,RobustPolicy const & robust_policy,state_type & state,Visitor & visitor)121 static inline void apply(std::size_t size_at_start,
122 Rings& rings,
123 Ring& ring,
124 Turns& turns,
125 typename boost::range_value<Turns>::type const& turn,
126 Operation& operation,
127 traverse_error_type traverse_error,
128 Geometry1 const& geometry1,
129 Geometry2 const& geometry2,
130 Strategy const& strategy,
131 RobustPolicy const& robust_policy,
132 state_type& state,
133 Visitor& visitor)
134 {
135 visitor.visit_traverse_reject(turns, turn, operation, traverse_error);
136
137 state.m_good = false;
138
139 // Check self-intersections and throw exception if appropriate
140 if (! state.m_checked)
141 {
142 state.m_checked = true;
143 has_self_intersections(geometry1, strategy, robust_policy);
144 has_self_intersections(geometry2, strategy, robust_policy);
145 }
146
147 // Make bad output clean
148 rings.resize(size_at_start);
149 geometry::traits::clear<typename boost::range_value<Rings>::type>::apply(ring);
150
151 // Reject this as a starting point
152 operation.visited.set_rejected();
153
154 // And clear all visit info
155 clear_visit_info(turns);
156 }
157 };
158
159 #ifdef BOOST_GEOMETRY_OVERLAY_REPORT_WKT
160 template
161 <
162 typename Geometry1,
163 typename Geometry2
164 >
165 class backtrack_debug
166 {
167 public :
168 typedef backtrack_state state_type;
169
170 template <typename Operation, typename Rings, typename Turns>
apply(std::size_t size_at_start,Rings & rings,typename boost::range_value<Rings>::type & ring,Turns & turns,Operation & operation,std::string const & reason,Geometry1 const & geometry1,Geometry2 const & geometry2,state_type & state)171 static inline void apply(std::size_t size_at_start,
172 Rings& rings, typename boost::range_value<Rings>::type& ring,
173 Turns& turns, Operation& operation,
174 std::string const& reason,
175 Geometry1 const& geometry1,
176 Geometry2 const& geometry2,
177 state_type& state
178 )
179 {
180 std::cout << " REJECT " << reason << std::endl;
181
182 state.m_good = false;
183
184 rings.resize(size_at_start);
185 ring.clear();
186 operation.visited.set_rejected();
187 clear_visit_info(turns);
188
189 int c = 0;
190 for (int i = 0; i < turns.size(); i++)
191 {
192 for (int j = 0; j < 2; j++)
193 {
194 if (turns[i].operations[j].visited.rejected())
195 {
196 c++;
197 }
198 }
199 }
200 std::cout << "BACKTRACK (" << reason << " )"
201 << " " << c << " of " << turns.size() << " rejected"
202 << std::endl;
203 std::cout
204 << geometry::wkt(geometry1) << std::endl
205 << geometry::wkt(geometry2) << std::endl;
206 }
207 };
208 #endif // BOOST_GEOMETRY_OVERLAY_REPORT_WKT
209
210 }} // namespace detail::overlay
211 #endif // DOXYGEN_NO_DETAIL
212
213 }} // namespace boost::geometry
214
215 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_BACKTRACK_CHECK_SI_HPP
216