]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Boost.Geometry (aka GGL, Generic Geometry Library) |
2 | ||
3 | // Copyright (c) 2015, 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_POLICIES_IS_VALID_FAILING_REASON_POLICY_HPP | |
12 | #define BOOST_GEOMETRY_POLICIES_IS_VALID_FAILING_REASON_POLICY_HPP | |
13 | ||
14 | #include <sstream> | |
15 | ||
16 | #include <boost/geometry/io/dsv/write.hpp> | |
17 | #include <boost/geometry/util/condition.hpp> | |
18 | #include <boost/geometry/util/range.hpp> | |
19 | #include <boost/geometry/algorithms/validity_failure_type.hpp> | |
20 | #include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp> | |
21 | ||
22 | ||
23 | namespace boost { namespace geometry | |
24 | { | |
25 | ||
26 | ||
27 | inline char const* validity_failure_type_message(validity_failure_type failure) | |
28 | { | |
29 | switch (failure) | |
30 | { | |
31 | case no_failure: | |
32 | return "Geometry is valid"; | |
33 | case failure_few_points: | |
34 | return "Geometry has too few points"; | |
35 | case failure_wrong_topological_dimension: | |
36 | return "Geometry has wrong topological dimension"; | |
37 | case failure_not_closed: | |
38 | return "Geometry is defined as closed but is open"; | |
39 | case failure_spikes: | |
40 | return "Geometry has spikes"; | |
41 | case failure_self_intersections: | |
42 | return "Geometry has invalid self-intersections"; | |
43 | case failure_wrong_orientation: | |
44 | return "Geometry has wrong orientation"; | |
45 | case failure_interior_rings_outside: | |
46 | return "Geometry has interior rings defined outside the outer boundary"; | |
47 | case failure_nested_interior_rings: | |
48 | return "Geometry has nested interior rings"; | |
49 | case failure_disconnected_interior: | |
50 | return "Geometry has disconnected interior"; | |
51 | case failure_intersecting_interiors: | |
52 | return "Multi-polygon has intersecting interiors"; | |
53 | case failure_duplicate_points: | |
54 | return "Geometry has duplicate (consecutive) points"; | |
55 | case failure_wrong_corner_order: | |
56 | return "Box has corners in wrong order"; | |
57 | case failure_invalid_coordinate: | |
58 | return "Geometry has point(s) with invalid coordinate(s)"; | |
59 | default: // to avoid -Wreturn-type warning | |
60 | return ""; | |
61 | } | |
62 | } | |
63 | ||
64 | ||
65 | template <bool AllowDuplicates = true, bool AllowSpikes = true> | |
66 | class failing_reason_policy | |
67 | { | |
68 | private: | |
69 | static inline | |
70 | validity_failure_type transform_failure_type(validity_failure_type failure) | |
71 | { | |
72 | if (BOOST_GEOMETRY_CONDITION( | |
73 | AllowDuplicates && failure == failure_duplicate_points)) | |
74 | { | |
75 | return no_failure; | |
76 | } | |
77 | return failure; | |
78 | } | |
79 | ||
80 | static inline | |
81 | validity_failure_type transform_failure_type(validity_failure_type failure, | |
82 | bool is_linear) | |
83 | { | |
84 | if (BOOST_GEOMETRY_CONDITION( | |
85 | is_linear && AllowSpikes && failure == failure_spikes)) | |
86 | { | |
87 | return no_failure; | |
88 | } | |
89 | return transform_failure_type(failure); | |
90 | } | |
91 | ||
92 | inline void set_failure_message(validity_failure_type failure) | |
93 | { | |
94 | m_oss.str(""); | |
95 | m_oss.clear(); | |
96 | m_oss << validity_failure_type_message(failure); | |
97 | } | |
98 | ||
99 | template | |
100 | < | |
101 | validity_failure_type Failure, | |
102 | typename Data1, | |
103 | typename Data2 = Data1, | |
104 | typename Dummy = void | |
105 | > | |
106 | struct process_data | |
107 | { | |
108 | static inline void apply(std::ostringstream&, Data1 const&) | |
109 | { | |
110 | } | |
111 | ||
112 | static inline void apply(std::ostringstream&, | |
113 | Data1 const&, | |
114 | Data2 const&) | |
115 | { | |
116 | } | |
117 | }; | |
118 | ||
119 | template <typename SpikePoint> | |
120 | struct process_data<failure_spikes, bool, SpikePoint> | |
121 | { | |
122 | static inline void apply(std::ostringstream& oss, | |
123 | bool is_linear, | |
124 | SpikePoint const& spike_point) | |
125 | { | |
126 | if (BOOST_GEOMETRY_CONDITION(is_linear && AllowSpikes)) | |
127 | { | |
128 | return; | |
129 | } | |
130 | ||
131 | oss << ". A spike point was found with apex at " | |
132 | << geometry::dsv(spike_point); | |
133 | } | |
134 | }; | |
135 | ||
136 | template <typename Turns> | |
137 | struct process_data<failure_self_intersections, Turns> | |
138 | { | |
139 | static inline | |
140 | void apply_to_segment_identifier(std::ostringstream& oss, | |
141 | segment_identifier seg_id) | |
142 | { | |
143 | oss << "{" << seg_id.source_index | |
144 | << ", " << seg_id.multi_index | |
145 | << ", " << seg_id.ring_index | |
146 | << ", " << seg_id.segment_index | |
147 | << "}"; | |
148 | } | |
149 | ||
150 | static inline void apply(std::ostringstream& oss, | |
151 | Turns const& turns) | |
152 | { | |
153 | typedef typename boost::range_value<Turns>::type turn_type; | |
154 | turn_type const& turn = range::front(turns); | |
155 | oss << ". A self-intersection point was found at " | |
156 | << geometry::dsv(turn.point); | |
157 | ||
158 | oss << "; method: " << method_char(turn.method) | |
159 | << "; operations: " | |
160 | << operation_char(turn.operations[0].operation) | |
161 | << "/" | |
162 | << operation_char(turn.operations[1].operation) | |
163 | << "; segment IDs {source, multi, ring, segment}: "; | |
164 | apply_to_segment_identifier(oss, turn.operations[0].seg_id); | |
165 | oss << "/"; | |
166 | apply_to_segment_identifier(oss, turn.operations[1].seg_id); | |
167 | } | |
168 | }; | |
169 | ||
170 | template <typename Point> | |
171 | struct process_data<failure_duplicate_points, Point> | |
172 | { | |
173 | static inline void apply(std::ostringstream& oss, | |
174 | Point const& point) | |
175 | { | |
176 | if (BOOST_GEOMETRY_CONDITION(AllowDuplicates)) | |
177 | { | |
178 | return; | |
179 | } | |
180 | oss << ". Duplicate points were found near point " | |
181 | << geometry::dsv(point); | |
182 | } | |
183 | }; | |
184 | ||
185 | public: | |
186 | failing_reason_policy(std::ostringstream& oss) | |
187 | : m_oss(oss) | |
188 | {} | |
189 | ||
190 | template <validity_failure_type Failure> | |
191 | inline bool apply() | |
192 | { | |
193 | validity_failure_type const failure = transform_failure_type(Failure); | |
194 | set_failure_message(failure); | |
195 | return failure == no_failure; | |
196 | } | |
197 | ||
198 | template <validity_failure_type Failure, typename Data> | |
199 | inline bool apply(Data const& data) | |
200 | { | |
201 | validity_failure_type const failure = transform_failure_type(Failure); | |
202 | set_failure_message(failure); | |
203 | process_data<Failure, Data>::apply(m_oss, data); | |
204 | return failure == no_failure; | |
205 | } | |
206 | ||
207 | template <validity_failure_type Failure, typename Data1, typename Data2> | |
208 | inline bool apply(Data1 const& data1, Data2 const& data2) | |
209 | { | |
210 | validity_failure_type const failure | |
211 | = transform_failure_type(Failure, data1); | |
212 | set_failure_message(failure); | |
213 | process_data<Failure, Data1, Data2>::apply(m_oss, data1, data2); | |
214 | return failure == no_failure; | |
215 | } | |
216 | ||
217 | private: | |
218 | std::ostringstream& m_oss; | |
219 | }; | |
220 | ||
221 | ||
222 | }} // namespace boost::geometry | |
223 | ||
224 | #endif // BOOST_GEOMETRY_POLICIES_IS_VALID_FAILING_REASON_POLICY_HPP |