Chris@102
|
1 // Boost.Geometry (aka GGL, Generic Geometry Library)
|
Chris@102
|
2
|
Chris@102
|
3 // Copyright (c) 2012-2015 Barend Gehrels, Amsterdam, the Netherlands.
|
Chris@102
|
4
|
Chris@102
|
5 // Use, modification and distribution is subject to the Boost Software License,
|
Chris@102
|
6 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
Chris@102
|
7 // http://www.boost.org/LICENSE_1_0.txt)
|
Chris@102
|
8
|
Chris@102
|
9 #ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_JOIN_ROUND_HPP
|
Chris@102
|
10 #define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_JOIN_ROUND_HPP
|
Chris@102
|
11
|
Chris@102
|
12 #include <algorithm>
|
Chris@102
|
13
|
Chris@102
|
14 #include <boost/assert.hpp>
|
Chris@102
|
15 #include <boost/geometry/core/cs.hpp>
|
Chris@102
|
16 #include <boost/geometry/policies/compare.hpp>
|
Chris@102
|
17 #include <boost/geometry/strategies/buffer.hpp>
|
Chris@102
|
18 #include <boost/geometry/util/math.hpp>
|
Chris@102
|
19 #include <boost/geometry/util/select_most_precise.hpp>
|
Chris@102
|
20
|
Chris@102
|
21 #ifdef BOOST_GEOMETRY_DEBUG_BUFFER_WARN
|
Chris@102
|
22 #include <boost/geometry/io/wkt/wkt.hpp>
|
Chris@102
|
23 #endif
|
Chris@102
|
24
|
Chris@102
|
25
|
Chris@102
|
26 namespace boost { namespace geometry
|
Chris@102
|
27 {
|
Chris@102
|
28
|
Chris@102
|
29
|
Chris@102
|
30 namespace strategy { namespace buffer
|
Chris@102
|
31 {
|
Chris@102
|
32
|
Chris@102
|
33 /*!
|
Chris@102
|
34 \brief Let the buffer create rounded corners
|
Chris@102
|
35 \ingroup strategies
|
Chris@102
|
36 \details This strategy can be used as JoinStrategy for the buffer algorithm.
|
Chris@102
|
37 It creates a rounded corners around each convex vertex. It can be applied
|
Chris@102
|
38 for (multi)linestrings and (multi)polygons.
|
Chris@102
|
39 This strategy is only applicable for Cartesian coordinate systems.
|
Chris@102
|
40
|
Chris@102
|
41 \qbk{
|
Chris@102
|
42 [heading Example]
|
Chris@102
|
43 [buffer_join_round]
|
Chris@102
|
44 [heading Output]
|
Chris@102
|
45 [$img/strategies/buffer_join_round.png]
|
Chris@102
|
46 [heading See also]
|
Chris@102
|
47 \* [link geometry.reference.algorithms.buffer.buffer_7_with_strategies buffer (with strategies)]
|
Chris@102
|
48 \* [link geometry.reference.strategies.strategy_buffer_join_miter join_miter]
|
Chris@102
|
49 }
|
Chris@102
|
50 */
|
Chris@102
|
51 class join_round
|
Chris@102
|
52 {
|
Chris@102
|
53 public :
|
Chris@102
|
54
|
Chris@102
|
55 //! \brief Constructs the strategy
|
Chris@102
|
56 //! \param points_per_circle points which would be used for a full circle
|
Chris@102
|
57 explicit inline join_round(std::size_t points_per_circle = 90)
|
Chris@102
|
58 : m_points_per_circle(points_per_circle)
|
Chris@102
|
59 {}
|
Chris@102
|
60
|
Chris@102
|
61 private :
|
Chris@102
|
62 template
|
Chris@102
|
63 <
|
Chris@102
|
64 typename PromotedType,
|
Chris@102
|
65 typename Point,
|
Chris@102
|
66 typename DistanceType,
|
Chris@102
|
67 typename RangeOut
|
Chris@102
|
68 >
|
Chris@102
|
69 inline void generate_points(Point const& vertex,
|
Chris@102
|
70 Point const& perp1, Point const& perp2,
|
Chris@102
|
71 DistanceType const& buffer_distance,
|
Chris@102
|
72 RangeOut& range_out) const
|
Chris@102
|
73 {
|
Chris@102
|
74 PromotedType const dx1 = get<0>(perp1) - get<0>(vertex);
|
Chris@102
|
75 PromotedType const dy1 = get<1>(perp1) - get<1>(vertex);
|
Chris@102
|
76 PromotedType const dx2 = get<0>(perp2) - get<0>(vertex);
|
Chris@102
|
77 PromotedType const dy2 = get<1>(perp2) - get<1>(vertex);
|
Chris@102
|
78
|
Chris@102
|
79 PromotedType const two = 2.0;
|
Chris@102
|
80 PromotedType const two_pi = two * geometry::math::pi<PromotedType>();
|
Chris@102
|
81
|
Chris@102
|
82 PromotedType const angle1 = atan2(dy1, dx1);
|
Chris@102
|
83 PromotedType angle2 = atan2(dy2, dx2);
|
Chris@102
|
84 while (angle2 > angle1)
|
Chris@102
|
85 {
|
Chris@102
|
86 angle2 -= two_pi;
|
Chris@102
|
87 }
|
Chris@102
|
88 PromotedType const angle_diff = angle1 - angle2;
|
Chris@102
|
89
|
Chris@102
|
90 // Divide the angle into an integer amount of steps to make it
|
Chris@102
|
91 // visually correct also for a low number of points / circle
|
Chris@102
|
92
|
Chris@102
|
93 // If a full circle is divided into 3 parts (e.g. angle is 125),
|
Chris@102
|
94 // the one point in between must still be generated
|
Chris@102
|
95 // The calculation below:
|
Chris@102
|
96 // - generates 1 point in between for an angle of 125 based on 3 points
|
Chris@102
|
97 // - generates 0 points in between for an angle of 90 based on 4 points
|
Chris@102
|
98
|
Chris@102
|
99 int const n = (std::max)(static_cast<int>(
|
Chris@102
|
100 ceil(m_points_per_circle * angle_diff / two_pi)), 1);
|
Chris@102
|
101
|
Chris@102
|
102 PromotedType const diff = angle_diff / static_cast<PromotedType>(n);
|
Chris@102
|
103 PromotedType a = angle1 - diff;
|
Chris@102
|
104
|
Chris@102
|
105 // Walk to n - 1 to avoid generating the last point
|
Chris@102
|
106 for (int i = 0; i < n - 1; i++, a -= diff)
|
Chris@102
|
107 {
|
Chris@102
|
108 Point p;
|
Chris@102
|
109 set<0>(p, get<0>(vertex) + buffer_distance * cos(a));
|
Chris@102
|
110 set<1>(p, get<1>(vertex) + buffer_distance * sin(a));
|
Chris@102
|
111 range_out.push_back(p);
|
Chris@102
|
112 }
|
Chris@102
|
113 }
|
Chris@102
|
114
|
Chris@102
|
115 public :
|
Chris@102
|
116
|
Chris@102
|
117
|
Chris@102
|
118 #ifndef DOXYGEN_SHOULD_SKIP_THIS
|
Chris@102
|
119 //! Fills output_range with a rounded shape around a vertex
|
Chris@102
|
120 template <typename Point, typename DistanceType, typename RangeOut>
|
Chris@102
|
121 inline bool apply(Point const& ip, Point const& vertex,
|
Chris@102
|
122 Point const& perp1, Point const& perp2,
|
Chris@102
|
123 DistanceType const& buffer_distance,
|
Chris@102
|
124 RangeOut& range_out) const
|
Chris@102
|
125 {
|
Chris@102
|
126 typedef typename coordinate_type<Point>::type coordinate_type;
|
Chris@102
|
127 typedef typename boost::range_value<RangeOut>::type output_point_type;
|
Chris@102
|
128
|
Chris@102
|
129 typedef typename geometry::select_most_precise
|
Chris@102
|
130 <
|
Chris@102
|
131 typename geometry::select_most_precise
|
Chris@102
|
132 <
|
Chris@102
|
133 coordinate_type,
|
Chris@102
|
134 typename geometry::coordinate_type<output_point_type>::type
|
Chris@102
|
135 >::type,
|
Chris@102
|
136 double
|
Chris@102
|
137 >::type promoted_type;
|
Chris@102
|
138
|
Chris@102
|
139 geometry::equal_to<Point> equals;
|
Chris@102
|
140 if (equals(perp1, perp2))
|
Chris@102
|
141 {
|
Chris@102
|
142 #ifdef BOOST_GEOMETRY_DEBUG_BUFFER_WARN
|
Chris@102
|
143 std::cout << "Corner for equal points " << geometry::wkt(ip) << " " << geometry::wkt(perp1) << std::endl;
|
Chris@102
|
144 #endif
|
Chris@102
|
145 return false;
|
Chris@102
|
146 }
|
Chris@102
|
147
|
Chris@102
|
148 // Generate 'vectors'
|
Chris@102
|
149 coordinate_type vix = (get<0>(ip) - get<0>(vertex));
|
Chris@102
|
150 coordinate_type viy = (get<1>(ip) - get<1>(vertex));
|
Chris@102
|
151
|
Chris@102
|
152 promoted_type length_i = geometry::math::sqrt(vix * vix + viy * viy);
|
Chris@102
|
153 DistanceType const bd = geometry::math::abs(buffer_distance);
|
Chris@102
|
154 promoted_type prop = bd / length_i;
|
Chris@102
|
155
|
Chris@102
|
156 Point bp;
|
Chris@102
|
157 set<0>(bp, get<0>(vertex) + vix * prop);
|
Chris@102
|
158 set<1>(bp, get<1>(vertex) + viy * prop);
|
Chris@102
|
159
|
Chris@102
|
160 range_out.push_back(perp1);
|
Chris@102
|
161 generate_points<promoted_type>(vertex, perp1, perp2, bd, range_out);
|
Chris@102
|
162 range_out.push_back(perp2);
|
Chris@102
|
163 return true;
|
Chris@102
|
164 }
|
Chris@102
|
165
|
Chris@102
|
166 template <typename NumericType>
|
Chris@102
|
167 static inline NumericType max_distance(NumericType const& distance)
|
Chris@102
|
168 {
|
Chris@102
|
169 return distance;
|
Chris@102
|
170 }
|
Chris@102
|
171
|
Chris@102
|
172 #endif // DOXYGEN_SHOULD_SKIP_THIS
|
Chris@102
|
173
|
Chris@102
|
174 private :
|
Chris@102
|
175 std::size_t m_points_per_circle;
|
Chris@102
|
176 };
|
Chris@102
|
177
|
Chris@102
|
178
|
Chris@102
|
179 }} // namespace strategy::buffer
|
Chris@102
|
180
|
Chris@102
|
181 }} // namespace boost::geometry
|
Chris@102
|
182
|
Chris@102
|
183 #endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_BUFFER_JOIN_ROUND_HPP
|