@@ -100,7 +100,7 @@ inline void append_no_dups_or_spikes(Range& range, Point const& point,
100
100
return ;
101
101
}
102
102
103
- auto append = [](auto & r, const auto & p)
103
+ auto append = [](auto & r, auto const & p)
104
104
{
105
105
using point_t = typename boost::range_value<Range>::type;
106
106
point_t rp;
@@ -168,56 +168,64 @@ inline void append_no_collinear(Range& range, Point const& point,
168
168
}
169
169
}
170
170
171
- template < typename Range, typename Strategy, typename RobustPolicy>
172
- inline void clean_closing_dups_and_spikes (Range& range,
173
- Strategy const & strategy,
174
- RobustPolicy const & robust_policy)
171
+ // Should only be called internally, from traverse.
172
+ template < typename Ring, typename Strategy, typename RobustPolicy>
173
+ inline void remove_spikes_at_closure (Ring& ring, Strategy const & strategy,
174
+ RobustPolicy const & robust_policy)
175
175
{
176
- std::size_t const minsize
177
- = core_detail::closure::minimum_ring_size
178
- <
179
- geometry::closure<Range>::value
180
- >::value;
181
-
182
- if (boost::size (range) <= minsize)
176
+ // It assumes a closed ring (whatever the closure value)
177
+ constexpr std::size_t min_size
178
+ = core_detail::closure::minimum_ring_size
179
+ <
180
+ geometry::closed
181
+ >::value;
182
+
183
+ if (boost::size (ring) < min_size)
183
184
{
185
+ // Don't act on too small rings.
184
186
return ;
185
187
}
186
188
187
- static bool const closed = geometry::closure<Range>::value == geometry::closed;
188
-
189
- // TODO: the following algorithm could be rewritten to first look for spikes
190
- // and then erase some number of points from the beginning of the Range
191
-
192
189
bool found = false ;
193
190
do
194
191
{
195
192
found = false ;
196
- auto first = boost::begin (range);
197
- auto second = first + 1 ;
198
- auto ultimate = boost::end (range) - 1 ;
199
- if (BOOST_GEOMETRY_CONDITION (closed))
200
- {
201
- ultimate--;
202
- }
193
+ auto const first = boost::begin (ring);
194
+ auto const second = first + 1 ;
195
+ auto const penultimate = boost::end (ring) - 2 ;
203
196
204
197
// Check if closing point is a spike (this is so if the second point is
205
198
// considered as collinear w.r.t. the last segment)
206
- if (point_is_collinear (*second, *ultimate , *first,
199
+ if (point_is_collinear (*second, *penultimate , *first,
207
200
strategy.side (), // TODO: Pass strategy?
208
201
robust_policy))
209
202
{
210
- range::erase (range, first);
211
- if (BOOST_GEOMETRY_CONDITION (closed))
212
- {
213
- // Remove closing last point
214
- range::resize (range, boost::size (range) - 1 );
215
- // Add new closing point
216
- range::push_back (range, range::front (range));
217
- }
203
+ // Remove first point and last point
204
+ range::erase (ring, first);
205
+ range::resize (ring, boost::size (ring) - 1 );
206
+ // Close the ring again
207
+ range::push_back (ring, range::front (ring));
208
+
218
209
found = true ;
219
210
}
220
- } while (found && boost::size (range) > minsize);
211
+ } while (found && boost::size (ring) >= min_size);
212
+ }
213
+
214
+ template <typename Ring, typename Strategy>
215
+ inline void fix_closure (Ring& ring, Strategy const & strategy)
216
+ {
217
+ if (BOOST_GEOMETRY_CONDITION (geometry::closure<Ring>::value == geometry::open ))
218
+ {
219
+ if (! boost::empty (ring)
220
+ && detail::equals::equals_point_point (range::front (ring), range::back (ring), strategy))
221
+ {
222
+ // Correct closure: traversal automatically closes rings.
223
+ // Depending on the geometric configuration,
224
+ // remove_spikes_at_closure can remove the closing point.
225
+ // But it does not always do that. Therefore it is corrected here explicitly.
226
+ range::resize (ring, boost::size (ring) - 1 );
227
+ }
228
+ }
221
229
}
222
230
223
231
0 commit comments