File indexing completed on 2025-09-14 08:32:40
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CLIP_LINESTRING_HPP
0016 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CLIP_LINESTRING_HPP
0017
0018 #include <boost/range/begin.hpp>
0019 #include <boost/range/empty.hpp>
0020 #include <boost/range/end.hpp>
0021
0022 #include <boost/geometry/algorithms/clear.hpp>
0023 #include <boost/geometry/algorithms/convert.hpp>
0024
0025 #include <boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp>
0026
0027 #include <boost/geometry/util/select_coordinate_type.hpp>
0028 #include <boost/geometry/geometries/segment.hpp>
0029
0030 #include <boost/geometry/strategies/cartesian/point_in_point.hpp>
0031
0032 namespace boost { namespace geometry
0033 {
0034
0035 namespace strategy { namespace intersection
0036 {
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053 template<typename Box, typename Point>
0054 class liang_barsky
0055 {
0056 private:
0057 using segment_type = model::referring_segment<Point>;
0058
0059 template <typename CoordinateType, typename CalcType>
0060 inline bool check_edge(CoordinateType const& p, CoordinateType const& q, CalcType& t1, CalcType& t2) const
0061 {
0062 bool visible = true;
0063
0064 if(p < 0)
0065 {
0066 CalcType const r = static_cast<CalcType>(q) / p;
0067 if (r > t2)
0068 visible = false;
0069 else if (r > t1)
0070 t1 = r;
0071 }
0072 else if(p > 0)
0073 {
0074 CalcType const r = static_cast<CalcType>(q) / p;
0075 if (r < t1)
0076 visible = false;
0077 else if (r < t2)
0078 t2 = r;
0079 }
0080 else
0081 {
0082 if (q < 0)
0083 visible = false;
0084 }
0085
0086 return visible;
0087 }
0088
0089 public:
0090
0091
0092
0093 using equals_point_point_strategy_type = strategy::within::cartesian_point_point;
0094
0095 static inline equals_point_point_strategy_type get_equals_point_point_strategy()
0096 {
0097 return equals_point_point_strategy_type();
0098 }
0099
0100 inline bool clip_segment(Box const& b, segment_type& s, bool& sp1_clipped, bool& sp2_clipped) const
0101 {
0102 using coordinate_type = typename select_coordinate_type<Box, Point>::type;
0103 using calc_type = typename select_most_precise<coordinate_type, double>::type;
0104
0105 calc_type t1 = 0;
0106 calc_type t2 = 1;
0107
0108 coordinate_type const dx = get<1, 0>(s) - get<0, 0>(s);
0109 coordinate_type const dy = get<1, 1>(s) - get<0, 1>(s);
0110
0111 coordinate_type const p1 = -dx;
0112 coordinate_type const p2 = dx;
0113 coordinate_type const p3 = -dy;
0114 coordinate_type const p4 = dy;
0115
0116 coordinate_type const q1 = get<0, 0>(s) - get<min_corner, 0>(b);
0117 coordinate_type const q2 = get<max_corner, 0>(b) - get<0, 0>(s);
0118 coordinate_type const q3 = get<0, 1>(s) - get<min_corner, 1>(b);
0119 coordinate_type const q4 = get<max_corner, 1>(b) - get<0, 1>(s);
0120
0121 if (check_edge(p1, q1, t1, t2)
0122 && check_edge(p2, q2, t1, t2)
0123 && check_edge(p3, q3, t1, t2)
0124 && check_edge(p4, q4, t1, t2))
0125 {
0126 sp1_clipped = t1 > 0;
0127 sp2_clipped = t2 < 1;
0128
0129 if (sp2_clipped)
0130 {
0131 set<1, 0>(s, get<0, 0>(s) + t2 * dx);
0132 set<1, 1>(s, get<0, 1>(s) + t2 * dy);
0133 }
0134
0135 if(sp1_clipped)
0136 {
0137 set<0, 0>(s, get<0, 0>(s) + t1 * dx);
0138 set<0, 1>(s, get<0, 1>(s) + t1 * dy);
0139 }
0140
0141 return true;
0142 }
0143
0144 return false;
0145 }
0146
0147 template<typename Linestring, typename OutputIterator>
0148 inline void apply(Linestring& line_out, OutputIterator out) const
0149 {
0150 if (!boost::empty(line_out))
0151 {
0152 *out = line_out;
0153 ++out;
0154 geometry::clear(line_out);
0155 }
0156 }
0157 };
0158
0159
0160 }}
0161
0162
0163 #ifndef DOXYGEN_NO_DETAIL
0164 namespace detail { namespace intersection
0165 {
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178 template
0179 <
0180 typename OutputLinestring,
0181 typename OutputIterator,
0182 typename Range,
0183 typename Box,
0184 typename Strategy
0185 >
0186 OutputIterator clip_range_with_box(Box const& b, Range const& range,
0187 OutputIterator out, Strategy const& strategy)
0188 {
0189 if (boost::begin(range) == boost::end(range))
0190 {
0191 return out;
0192 }
0193
0194 using point_type = point_type_t<OutputLinestring>;
0195
0196 OutputLinestring line_out;
0197
0198 auto vertex = boost::begin(range);
0199 for (auto previous = vertex++;
0200 vertex != boost::end(range);
0201 ++previous, ++vertex)
0202 {
0203 point_type p1, p2;
0204 geometry::convert(*previous, p1);
0205 geometry::convert(*vertex, p2);
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219 bool c1 = false;
0220 bool c2 = false;
0221 model::referring_segment<point_type> s(p1, p2);
0222
0223 if (!strategy.clip_segment(b, s, c1, c2))
0224 {
0225 strategy.apply(line_out, out);
0226 }
0227 else
0228 {
0229
0230 if (c1)
0231 {
0232 strategy.apply(line_out, out);
0233 }
0234
0235
0236 if (boost::empty(line_out))
0237 {
0238 detail::overlay::append_with_duplicates(line_out, p1);
0239 }
0240 detail::overlay::append_no_duplicates(line_out, p2,
0241 strategy.get_equals_point_point_strategy());
0242
0243
0244 if (c2)
0245 {
0246 strategy.apply(line_out, out);
0247 }
0248 }
0249
0250 }
0251
0252
0253 strategy.apply(line_out, out);
0254 return out;
0255 }
0256
0257 }}
0258 #endif
0259
0260 }}
0261
0262 #endif