File indexing completed on 2025-01-18 09:35:08
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 typedef model::referring_segment<Point> segment_type;
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 typedef strategy::within::cartesian_point_point equals_point_point_strategy_type;
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 typedef typename select_coordinate_type<Box, Point>::type coordinate_type;
0103 typedef typename select_most_precise<coordinate_type, double>::type calc_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 RobustPolicy,
0184 typename Box,
0185 typename Strategy
0186 >
0187 OutputIterator clip_range_with_box(Box const& b, Range const& range,
0188 RobustPolicy const&,
0189 OutputIterator out, Strategy const& strategy)
0190 {
0191 if (boost::begin(range) == boost::end(range))
0192 {
0193 return out;
0194 }
0195
0196 typedef typename point_type<OutputLinestring>::type point_type;
0197
0198 OutputLinestring line_out;
0199
0200 auto vertex = boost::begin(range);
0201 for (auto previous = vertex++;
0202 vertex != boost::end(range);
0203 ++previous, ++vertex)
0204 {
0205 point_type p1, p2;
0206 geometry::convert(*previous, p1);
0207 geometry::convert(*vertex, p2);
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221 bool c1 = false;
0222 bool c2 = false;
0223 model::referring_segment<point_type> s(p1, p2);
0224
0225 if (!strategy.clip_segment(b, s, c1, c2))
0226 {
0227 strategy.apply(line_out, out);
0228 }
0229 else
0230 {
0231
0232 if (c1)
0233 {
0234 strategy.apply(line_out, out);
0235 }
0236
0237
0238 if (boost::empty(line_out))
0239 {
0240 detail::overlay::append_with_duplicates(line_out, p1);
0241 }
0242 detail::overlay::append_no_duplicates(line_out, p2,
0243 strategy.get_equals_point_point_strategy());
0244
0245
0246 if (c2)
0247 {
0248 strategy.apply(line_out, out);
0249 }
0250 }
0251
0252 }
0253
0254
0255 strategy.apply(line_out, out);
0256 return out;
0257 }
0258
0259 }}
0260 #endif
0261
0262 }}
0263
0264 #endif