File indexing completed on 2025-01-18 09:35:36
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #ifndef BOOST_GEOMETRY_POLICIES_IS_VALID_FAILING_REASON_POLICY_HPP
0013 #define BOOST_GEOMETRY_POLICIES_IS_VALID_FAILING_REASON_POLICY_HPP
0014
0015 #include <sstream>
0016
0017 #include <boost/geometry/io/dsv/write.hpp>
0018 #include <boost/geometry/util/constexpr.hpp>
0019 #include <boost/geometry/util/range.hpp>
0020 #include <boost/geometry/algorithms/validity_failure_type.hpp>
0021 #include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
0022
0023
0024 namespace boost { namespace geometry
0025 {
0026
0027
0028 inline char const* validity_failure_type_message(validity_failure_type failure)
0029 {
0030 switch (failure)
0031 {
0032 case no_failure:
0033 return "Geometry is valid";
0034 case failure_few_points:
0035 return "Geometry has too few points";
0036 case failure_wrong_topological_dimension:
0037 return "Geometry has wrong topological dimension";
0038 case failure_not_closed:
0039 return "Geometry is defined as closed but is open";
0040 case failure_spikes:
0041 return "Geometry has spikes";
0042 case failure_self_intersections:
0043 return "Geometry has invalid self-intersections";
0044 case failure_wrong_orientation:
0045 return "Geometry has wrong orientation";
0046 case failure_interior_rings_outside:
0047 return "Geometry has interior rings defined outside the outer boundary";
0048 case failure_nested_interior_rings:
0049 return "Geometry has nested interior rings";
0050 case failure_disconnected_interior:
0051 return "Geometry has disconnected interior";
0052 case failure_intersecting_interiors:
0053 return "Multi-polygon has intersecting interiors";
0054 case failure_duplicate_points:
0055 return "Geometry has duplicate (consecutive) points";
0056 case failure_wrong_corner_order:
0057 return "Box has corners in wrong order";
0058 case failure_invalid_coordinate:
0059 return "Geometry has point(s) with invalid coordinate(s)";
0060 default:
0061 return "";
0062 }
0063 }
0064
0065
0066 template <bool AllowDuplicates = true, bool AllowSpikes = true>
0067 class failing_reason_policy
0068 {
0069 private:
0070 static inline
0071 validity_failure_type transform_failure_type(validity_failure_type failure)
0072 {
0073 if BOOST_GEOMETRY_CONSTEXPR (AllowDuplicates)
0074 {
0075 if (failure == failure_duplicate_points)
0076 {
0077 return no_failure;
0078 }
0079 }
0080 return failure;
0081 }
0082
0083 static inline
0084 validity_failure_type transform_failure_type(validity_failure_type failure,
0085 bool is_linear)
0086 {
0087 if BOOST_GEOMETRY_CONSTEXPR (AllowSpikes)
0088 {
0089 if (is_linear && failure == failure_spikes)
0090 {
0091 return no_failure;
0092 }
0093 }
0094 return transform_failure_type(failure);
0095 }
0096
0097 inline void set_failure_message(validity_failure_type failure)
0098 {
0099 m_oss.str("");
0100 m_oss.clear();
0101 m_oss << validity_failure_type_message(failure);
0102 }
0103
0104 template
0105 <
0106 validity_failure_type Failure,
0107 typename Data1,
0108 typename Data2 = Data1,
0109 typename Dummy = void
0110 >
0111 struct process_data
0112 {
0113 static inline void apply(std::ostringstream&, Data1 const&)
0114 {
0115 }
0116
0117 static inline void apply(std::ostringstream&,
0118 Data1 const&,
0119 Data2 const&)
0120 {
0121 }
0122 };
0123
0124 template <typename SpikePoint>
0125 struct process_data<failure_spikes, bool, SpikePoint>
0126 {
0127 static inline void apply(std::ostringstream& oss,
0128 bool is_linear,
0129 SpikePoint const& spike_point)
0130 {
0131 if BOOST_GEOMETRY_CONSTEXPR (AllowSpikes)
0132 {
0133 if (is_linear)
0134 {
0135 return;
0136 }
0137 }
0138
0139 oss << ". A spike point was found with apex at "
0140 << geometry::dsv(spike_point);
0141 }
0142 };
0143
0144 template <typename Turns>
0145 struct process_data<failure_self_intersections, Turns>
0146 {
0147 static inline
0148 void apply_to_segment_identifier(std::ostringstream& oss,
0149 segment_identifier seg_id)
0150 {
0151 oss << "{" << seg_id.source_index
0152 << ", " << seg_id.multi_index
0153 << ", " << seg_id.ring_index
0154 << ", " << seg_id.segment_index
0155 << "}";
0156 }
0157
0158 static inline void apply(std::ostringstream& oss,
0159 Turns const& turns)
0160 {
0161 typedef typename boost::range_value<Turns>::type turn_type;
0162 turn_type const& turn = range::front(turns);
0163 oss << ". A self-intersection point was found at "
0164 << geometry::dsv(turn.point);
0165
0166 oss << "; method: " << method_char(turn.method)
0167 << "; operations: "
0168 << operation_char(turn.operations[0].operation)
0169 << "/"
0170 << operation_char(turn.operations[1].operation)
0171 << "; segment IDs {source, multi, ring, segment}: ";
0172 apply_to_segment_identifier(oss, turn.operations[0].seg_id);
0173 oss << "/";
0174 apply_to_segment_identifier(oss, turn.operations[1].seg_id);
0175 }
0176 };
0177
0178 template <typename Point>
0179 struct process_data<failure_duplicate_points, Point>
0180 {
0181 static inline void apply(std::ostringstream& oss,
0182 Point const& point)
0183 {
0184 if BOOST_GEOMETRY_CONSTEXPR (AllowDuplicates)
0185 {
0186 return;
0187 }
0188 oss << ". Duplicate points were found near point "
0189 << geometry::dsv(point);
0190 }
0191 };
0192
0193 public:
0194 failing_reason_policy(std::ostringstream& oss)
0195 : m_oss(oss)
0196 {}
0197
0198 template <validity_failure_type Failure>
0199 inline bool apply()
0200 {
0201 validity_failure_type const failure = transform_failure_type(Failure);
0202 set_failure_message(failure);
0203 return failure == no_failure;
0204 }
0205
0206 template <validity_failure_type Failure, typename Data>
0207 inline bool apply(Data const& data)
0208 {
0209 validity_failure_type const failure = transform_failure_type(Failure);
0210 set_failure_message(failure);
0211 process_data<Failure, Data>::apply(m_oss, data);
0212 return failure == no_failure;
0213 }
0214
0215 template <validity_failure_type Failure, typename Data1, typename Data2>
0216 inline bool apply(Data1 const& data1, Data2 const& data2)
0217 {
0218 validity_failure_type const failure
0219 = transform_failure_type(Failure, data1);
0220 set_failure_message(failure);
0221 process_data<Failure, Data1, Data2>::apply(m_oss, data1, data2);
0222 return failure == no_failure;
0223 }
0224
0225 private:
0226 std::ostringstream& m_oss;
0227 };
0228
0229
0230 }}
0231
0232 #endif