static inline void iterate(Collection& collection, Iterator begin, Iterator end, buffer_side_selector side, DistanceStrategy const& distance, JoinStrategy const& join_strategy, bool close = false) { output_point_type previous_p1, previous_p2; output_point_type first_p1, first_p2; bool first = true; Iterator it = begin; // We want to memorize the last vector too. typedef BOOST_TYPEOF(*it) point_type; point_type last_ip1, last_ip2; for (Iterator prev = it++; it != end; ++it) { if (! detail::equals::equals_point_point(*prev, *it)) { output_point_type p1, p2; last_ip1 = *prev; last_ip2 = *it; generate_side(*prev, *it, side, distance, p1, p2); std::vector<output_point_type> range_out; if (! first) { output_point_type p; segment_type s1(p1, p2); segment_type s2(previous_p1, previous_p2); if (line_line_intersection<output_point_type, segment_type>::apply(s1, s2, p)) { join_strategy.apply(p, *prev, previous_p2, p1, distance.apply(*prev, *it, side), range_out); } } else { first = false; first_p1 = p1; first_p2 = p2; } if (! range_out.empty()) { collection.add_piece(buffered_join, *prev, range_out); range_out.clear(); } collection.add_piece(buffered_segment, *prev, *it, p1, p2); previous_p1 = p1; previous_p2 = p2; prev = it; } } // Might be replaced by specialization if(boost::is_same<Tag, ring_tag>::value) { // Generate closing corner output_point_type p; segment_type s1(previous_p1, previous_p2); segment_type s2(first_p1, first_p2); line_line_intersection<output_point_type, segment_type>::apply(s1, s2, p); std::vector<output_point_type> range_out; join_strategy.apply(p, *begin, previous_p2, first_p1, distance.apply(*(end - 1), *begin, side), range_out); if (! range_out.empty()) { collection.add_piece(buffered_join, *begin, range_out); } // Buffer is closed automatically by last closing corner (NOT FOR OPEN POLYGONS - TODO) } else if (boost::is_same<Tag, linestring_tag>::value) { // Assume flat-end-strategy for now // TODO fix this (approach) for one-side buffer (1.5 - -1.0) output_point_type rp1, rp2; generate_side(last_ip2, last_ip1, side == buffer_side_left ? buffer_side_right : buffer_side_left, distance, rp2, rp1); // For flat end: std::vector<output_point_type> range_out; range_out.push_back(previous_p2); if (close) { range_out.push_back(rp2); } collection.add_piece(buffered_flat_end, range_out); } }
static inline void iterate(Inserter& inserter, Iterator begin, Iterator end, buffer_side_selector side, DistanceStrategy const& distance, JoinStrategy const& join #ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER , Mapper& mapper #endif ) { output_point_type previous_p1, previous_p2; output_point_type first_p1, first_p2; #ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER int index = 0; #endif bool first = true; Iterator it = begin; for (Iterator prev = it++; it != end; ++it) { if (! detail::equals::equals_point_point(*prev, *it)) { bool skip = false; // Simulate a vector d (dx,dy) coordinate_type dx = get<0>(*it) - get<0>(*prev); coordinate_type dy = get<1>(*it) - get<1>(*prev); // For normalization [0,1] (=dot product d.d, sqrt) coordinate_type length = sqrt(dx * dx + dy * dy); // Because coordinates are not equal, length should not be zero BOOST_ASSERT((! geometry::math::equals(length, 0))); // Generate the normalized perpendicular p, to the left (ccw) coordinate_type px = -dy / length; coordinate_type py = dx / length; output_point_type p1, p2; coordinate_type d = distance.apply(*prev, *it, side); set<0>(p2, get<0>(*it) + px * d); set<1>(p2, get<1>(*it) + py * d); set<0>(p1, get<0>(*prev) + px * d); set<1>(p1, get<1>(*prev) + py * d); { #ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER ring_type block; block.push_back(*prev); block.push_back(*it); block.push_back(p2); block.push_back(p1); block.push_back(*prev); mapper.map(block, "opacity:0.4;fill:rgb(0,255,0);stroke:rgb(0,0,0);stroke-width:1"); #endif } if (! first) { output_point_type p; segment_type s1(p1, p2); segment_type s2(previous_p1, previous_p2); if (line_line_intersection<output_point_type, segment_type>::apply(s1, s2, p)) { join.apply(p, *prev, previous_p2, p1, distance.apply(*prev, *it, side), inserter.get_ring()); { #ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER mapper.map(p, "fill:rgb(0,0,0);", 3); std::ostringstream out; out << index++; mapper.text(p, out.str(), "fill:rgb(0,0,0);font-family='Arial';", 5, 5); #endif } } else { skip = false; } } else { first = false; first_p1 = p1; first_p2 = p2; inserter.insert(p1); } if (! skip) { previous_p1 = p1; previous_p2 = p2; prev = it; } } } // Last one inserter.insert(previous_p2); }
static inline void apply(RingInput const& ring, RingOutput& buffered, coordinate_type distance, JoinStrategy const& join_strategy #ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER , Mapper& mapper #endif ) { typedef model::referring_segment<output_point_type const> segment_type; typedef typename boost::range_iterator < RingInput const >::type iterator_type; output_point_type previous_p1, previous_p2; output_point_type first_p1, first_p2; bool first = true; #ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER int index = 0; #endif iterator_type it = boost::begin(ring); for (iterator_type prev = it++; it != boost::end(ring); ++it) { if (! detail::equals::equals_point_point(*prev, *it)) { bool skip = false; // Generate a block along (int most cases to the left of) the segment // Simulate a vector d (dx,dy) coordinate_type dx = get<0>(*it) - get<0>(*prev); coordinate_type dy = get<1>(*it) - get<1>(*prev); // For normalization [0,1] (=dot product d.d, sqrt) coordinate_type length = sqrt(dx * dx + dy * dy); // Because coordinates are not equal, length should not be zero BOOST_ASSERT((! geometry::math::equals(length, 0))); // Generate the normalized perpendicular p, to the left (ccw) coordinate_type px = -dy / length; coordinate_type py = dx / length; output_point_type p1, p2; coordinate_type d = distance; set<0>(p2, get<0>(*it) + px * d); set<1>(p2, get<1>(*it) + py * d); set<0>(p1, get<0>(*prev) + px * d); set<1>(p1, get<1>(*prev) + py * d); { RingOutput block; block.push_back(*prev); block.push_back(*it); block.push_back(p2); block.push_back(p1); block.push_back(*prev); #ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER mapper.map(block, "opacity:0.4;fill:rgb(255,128,0);stroke:rgb(0,0,0);stroke-width:1"); #endif } if (! first) { output_point_type p; segment_type s1(p1, p2); segment_type s2(previous_p1, previous_p2); if (line_line_intersection<output_point_type, segment_type>::apply(s1, s2, p)) { join_strategy.apply(p, *prev, previous_p2, p1, distance, buffered); { #ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER mapper.map(p, "fill:rgb(0,0,0);", 3); std::ostringstream out; out << index++; mapper.text(p, out.str(), "fill:rgb(0,0,0);font-family='Arial';", 5, 5); #endif } } else { skip = false; } } else { first = false; first_p1 = p1; first_p2 = p2; } if (! skip) { previous_p1 = p1; previous_p2 = p2; prev = it; } } } // Last one { output_point_type p; segment_type s1(previous_p1, previous_p2); segment_type s2(first_p1, first_p2); line_line_intersection<output_point_type, segment_type>::apply(s1, s2, p); join_strategy.apply(p, *boost::begin(ring), previous_p2, first_p1, distance, buffered); #ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER mapper.map(p, "fill:rgb(0,0,0);", 3); std::ostringstream out; out << index++; mapper.text(p, out.str(), "fill:rgb(0,0,0);font-family='Arial';", 5, 5); #endif } // Close the generated buffer { output_point_type p = *boost::begin(buffered); buffered.push_back(p); } }