File indexing completed on 2025-09-17 08:31:05
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef BOOST_GEOMETRY_POLICIES_ROBUSTNESS_SEGMENT_RATIO_HPP
0015 #define BOOST_GEOMETRY_POLICIES_ROBUSTNESS_SEGMENT_RATIO_HPP
0016
0017 #include <type_traits>
0018
0019 #include <boost/config.hpp>
0020 #include <boost/rational.hpp>
0021
0022 #include <boost/geometry/core/assert.hpp>
0023 #include <boost/geometry/core/coordinate_promotion.hpp>
0024 #include <boost/geometry/util/math.hpp>
0025 #include <boost/geometry/util/numeric_cast.hpp>
0026
0027
0028 namespace boost { namespace geometry
0029 {
0030
0031
0032 namespace detail { namespace segment_ratio
0033 {
0034
0035 template
0036 <
0037 typename Type,
0038 bool IsIntegral = std::is_integral<Type>::type::value
0039 >
0040 struct less {};
0041
0042 template <typename Type>
0043 struct less<Type, true>
0044 {
0045 template <typename Ratio>
0046 static inline bool apply(Ratio const& lhs, Ratio const& rhs)
0047 {
0048 return boost::rational<Type>(lhs.numerator(), lhs.denominator())
0049 < boost::rational<Type>(rhs.numerator(), rhs.denominator());
0050 }
0051 };
0052
0053 template <typename Type>
0054 struct less<Type, false>
0055 {
0056 template <typename Ratio>
0057 static inline bool apply(Ratio const& lhs, Ratio const& rhs)
0058 {
0059 BOOST_GEOMETRY_ASSERT(lhs.denominator() != Type(0));
0060 BOOST_GEOMETRY_ASSERT(rhs.denominator() != Type(0));
0061 Type const a = lhs.numerator() / lhs.denominator();
0062 Type const b = rhs.numerator() / rhs.denominator();
0063 return ! geometry::math::equals(a, b)
0064 && a < b;
0065 }
0066 };
0067
0068 template
0069 <
0070 typename Type,
0071 bool IsIntegral = std::is_integral<Type>::type::value
0072 >
0073 struct equal {};
0074
0075 template <typename Type>
0076 struct equal<Type, true>
0077 {
0078 template <typename Ratio>
0079 static inline bool apply(Ratio const& lhs, Ratio const& rhs)
0080 {
0081 return boost::rational<Type>(lhs.numerator(), lhs.denominator())
0082 == boost::rational<Type>(rhs.numerator(), rhs.denominator());
0083 }
0084 };
0085
0086 template <typename Type>
0087 struct equal<Type, false>
0088 {
0089 template <typename Ratio>
0090 static inline bool apply(Ratio const& lhs, Ratio const& rhs)
0091 {
0092 BOOST_GEOMETRY_ASSERT(lhs.denominator() != Type(0));
0093 BOOST_GEOMETRY_ASSERT(rhs.denominator() != Type(0));
0094 Type const a = lhs.numerator() / lhs.denominator();
0095 Type const b = rhs.numerator() / rhs.denominator();
0096 return geometry::math::equals(a, b);
0097 }
0098 };
0099
0100 template
0101 <
0102 typename Type,
0103 bool IsFloatingPoint = std::is_floating_point<Type>::type::value
0104 >
0105 struct possibly_collinear {};
0106
0107 template <typename Type>
0108 struct possibly_collinear<Type, true>
0109 {
0110 template <typename Ratio, typename Threshold>
0111 static inline bool apply(Ratio const& ratio, Threshold threshold)
0112 {
0113 return std::abs(ratio.denominator()) < threshold;
0114 }
0115 };
0116
0117
0118
0119 template <typename Type>
0120 struct possibly_collinear<Type, false>
0121 {
0122 template <typename Ratio, typename Threshold>
0123 static inline bool apply(Ratio const& ratio, Threshold)
0124 {
0125 static Type const zero = 0;
0126 return ratio.denominator() == zero;
0127 }
0128 };
0129
0130 }}
0131
0132
0133
0134
0135
0136
0137
0138
0139 template <typename Type>
0140 class segment_ratio
0141 {
0142
0143
0144 using floating_point_type =
0145 typename detail::promoted_to_floating_point<Type>::type;
0146
0147
0148 using thistype = segment_ratio<Type>;
0149
0150 public:
0151 using int_type = Type;
0152
0153 inline segment_ratio()
0154 : m_numerator(0)
0155 , m_denominator(1)
0156 , m_approximation(0)
0157 {}
0158
0159 inline segment_ratio(Type const& numerator, Type const& denominator)
0160 : m_numerator(numerator)
0161 , m_denominator(denominator)
0162 {
0163 initialize();
0164 }
0165
0166 segment_ratio(segment_ratio const&) = default;
0167 segment_ratio& operator=(segment_ratio const&) = default;
0168 segment_ratio(segment_ratio&&) = default;
0169 segment_ratio& operator=(segment_ratio&&) = default;
0170
0171
0172
0173
0174
0175
0176
0177
0178 template<typename T> friend class segment_ratio;
0179 template <typename T>
0180 segment_ratio(segment_ratio<T> const& r)
0181 : m_numerator(r.m_numerator)
0182 , m_denominator(r.m_denominator)
0183 {
0184 initialize();
0185 }
0186 template <typename T>
0187 segment_ratio& operator=(segment_ratio<T> const& r)
0188 {
0189 m_numerator = r.m_numerator;
0190 m_denominator = r.m_denominator;
0191 initialize();
0192 return *this;
0193 }
0194 template <typename T>
0195 segment_ratio(segment_ratio<T> && r)
0196 : m_numerator(std::move(r.m_numerator))
0197 , m_denominator(std::move(r.m_denominator))
0198 {
0199 initialize();
0200 }
0201 template <typename T>
0202 segment_ratio& operator=(segment_ratio<T> && r)
0203 {
0204 m_numerator = std::move(r.m_numerator);
0205 m_denominator = std::move(r.m_denominator);
0206 initialize();
0207 return *this;
0208 }
0209
0210 inline Type const& numerator() const { return m_numerator; }
0211 inline Type const& denominator() const { return m_denominator; }
0212
0213 inline void assign(Type const& numerator, Type const& denominator)
0214 {
0215 m_numerator = numerator;
0216 m_denominator = denominator;
0217 initialize();
0218 }
0219
0220 inline void initialize()
0221 {
0222
0223
0224 if (m_denominator < zero_instance())
0225 {
0226 m_numerator = -m_numerator;
0227 m_denominator = -m_denominator;
0228 }
0229
0230 m_approximation =
0231 m_denominator == zero_instance() ? floating_point_type{0}
0232 : (
0233 util::numeric_cast<floating_point_type>(m_numerator) * scale()
0234 / util::numeric_cast<floating_point_type>(m_denominator)
0235 );
0236 }
0237
0238 inline bool is_zero() const { return math::equals(m_numerator, Type(0)); }
0239 inline bool is_one() const { return math::equals(m_numerator, m_denominator); }
0240 inline bool on_segment() const
0241 {
0242
0243 return m_numerator >= zero_instance() && m_numerator <= m_denominator;
0244 }
0245 inline bool in_segment() const
0246 {
0247
0248 return m_numerator > zero_instance() && m_numerator < m_denominator;
0249 }
0250 inline bool on_end() const
0251 {
0252
0253 return is_zero() || is_one();
0254 }
0255 inline bool left() const
0256 {
0257
0258 return m_numerator < zero_instance();
0259 }
0260 inline bool right() const
0261 {
0262
0263 return m_numerator > m_denominator;
0264 }
0265
0266
0267
0268
0269 inline floating_point_type edge_value() const
0270 {
0271 using fp = floating_point_type;
0272 fp const one{1.0};
0273 floating_point_type const result
0274 = fp(2) * geometry::math::abs(fp(0.5) - m_approximation / scale());
0275 return result > one ? one : result;
0276 }
0277
0278 template <typename Threshold>
0279 inline bool possibly_collinear(Threshold threshold) const
0280 {
0281 return detail::segment_ratio::possibly_collinear<Type>::apply(*this, threshold);
0282 }
0283
0284 inline bool operator< (thistype const& other) const
0285 {
0286 return close_to(other)
0287 ? detail::segment_ratio::less<Type>::apply(*this, other)
0288 : m_approximation < other.m_approximation;
0289 }
0290
0291 inline bool operator== (thistype const& other) const
0292 {
0293 return close_to(other)
0294 && detail::segment_ratio::equal<Type>::apply(*this, other);
0295 }
0296
0297 static inline thistype zero()
0298 {
0299 static thistype result(0, 1);
0300 return result;
0301 }
0302
0303 static inline thistype one()
0304 {
0305 static thistype result(1, 1);
0306 return result;
0307 }
0308
0309 #if defined(BOOST_GEOMETRY_DEFINE_STREAM_OPERATOR_SEGMENT_RATIO)
0310 friend std::ostream& operator<<(std::ostream &os, segment_ratio const& ratio)
0311 {
0312 os << ratio.m_numerator << "/" << ratio.m_denominator
0313 << " (" << (static_cast<double>(ratio.m_numerator)
0314 / static_cast<double>(ratio.m_denominator))
0315 << ")";
0316 return os;
0317 }
0318 #endif
0319
0320 private :
0321
0322 Type m_numerator;
0323 Type m_denominator;
0324
0325
0326
0327
0328
0329
0330 floating_point_type m_approximation;
0331
0332 inline bool close_to(thistype const& other) const
0333 {
0334 static floating_point_type const threshold{50.0};
0335 return geometry::math::abs(m_approximation - other.m_approximation)
0336 < threshold;
0337 }
0338
0339 static inline floating_point_type scale()
0340 {
0341 static floating_point_type const fp_scale{1000000.0};
0342 return fp_scale;
0343 }
0344
0345 static inline Type zero_instance()
0346 {
0347 return 0;
0348 }
0349 };
0350
0351 template <typename Point>
0352 struct segment_ratio_type
0353 {
0354 using type = segment_ratio<geometry::coordinate_type_t<Point>>;
0355 };
0356
0357 }}
0358
0359 #endif