diff --git a/include/boost/geometry/algorithms/detail/buffer/polygon_buffer.hpp b/include/boost/geometry/algorithms/detail/buffer/polygon_buffer.hpp index ddc1cfaf7..b6682df1a 100644 --- a/include/boost/geometry/algorithms/detail/buffer/polygon_buffer.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/polygon_buffer.hpp @@ -35,20 +35,20 @@ namespace detail { namespace buffer template struct ring_buffer { - + typedef typename point_type::type output_point_type; + typedef typename coordinate_type::type coordinate_type; #ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER template #endif static inline void apply(RingInput const& ring, RingOutput& buffered, - double distance, // TODO: change coordinate type + coordinate_type distance, JoinStrategy const& join_strategy #ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER , Mapper& mapper #endif ) { - typedef typename point_type::type output_point_type; typedef segment segment_type; typedef typename boost::range_iterator < @@ -72,7 +72,6 @@ struct ring_buffer bool skip = false; // Generate a block along (int most cases to the left of) the segment - typedef typename coordinate_type::type coordinate_type; // Simulate a vector d (dx,dy) coordinate_type dx = get<0>(*it) - get<0>(*prev); @@ -185,7 +184,8 @@ struct polygon_buffer template #endif static inline void apply(PolygonInput const& polygon, PolygonOutput& buffered, - double distance, JoinStrategy const& join_strategy + typename coordinate_type::type distance, + JoinStrategy const& join_strategy #ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER , Mapper& mapper #endif diff --git a/include/boost/geometry/algorithms/detail/buffer/segmenting_buffer.hpp b/include/boost/geometry/algorithms/detail/buffer/segmenting_buffer.hpp new file mode 100644 index 000000000..3e03830e4 --- /dev/null +++ b/include/boost/geometry/algorithms/detail/buffer/segmenting_buffer.hpp @@ -0,0 +1,346 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) +// +// Copyright Barend Gehrels 2010, Geodan, Amsterdam, the Netherlands. +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_SEGMENTING_BUFFER_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_SEGMENTING_BUFFER_HPP + +#include + +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include + + +#include + + +// TEMPORARY do not use yet. + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace buffer +{ + + +template +inline bool calculate_parallels(Point const& point1, Point const& point2, + PointOut& p1, PointOut& p2, DistanceType const& distance) +{ + typedef typename coordinate_type::type coordinate_type; + + // Simulate a vector d (dx,dy) + coordinate_type dx = get<0>(point2) - get<0>(point1); + coordinate_type dy = get<1>(point2) - get<1>(point1); + + // For normalization [0,1] (=dot product d.d, sqrt) + // TODO: promote to non-integer + coordinate_type length = sqrt(dx * dx + dy * dy); + + // Because coordinates are not equal, should been checked before, length should not be zero + if(geometry::math::equals(length, 0)) + { + return false; + } + + // Generate the normalized perpendicular p, to the left (ccw) + coordinate_type px = -dy / length; + coordinate_type py = dx / length; + + set<0>(p1, get<0>(point1) + px * distance); + set<1>(p1, get<1>(point1) + py * distance); + + set<0>(p2, get<0>(point2) + px * distance); + set<1>(p2, get<1>(point2) + py * distance); + return true; +} + + + +template +< + typename GeometryOut, typename Range, + typename DistanceStrategy, + typename JoinStrategy +#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER + , typename Mapper +#endif +> +struct per_segment_buffer +{ + typedef typename point_type::type input_point_type; + typedef typename point_type::type point_type; + typedef typename coordinate_type::type coordinate_type; + typedef coordinate_type distance_type; // TODO promote to FP + typedef segment segment_type; + typedef typename geometry::ring_type::type ring_type; + typedef typename strategy_side::type>::type side; + + typedef typename boost::range_iterator::type iterator_type; + + + static inline void calculate_tail(input_point_type const& tail, input_point_type const& head, + point_type& tail_left, point_type& tail_right, + distance_type& distance_left, + distance_type& distance_right, + distance_type& buffered_length) + { + coordinate_type ext_x = get<0>(head) - get<0>(tail); + coordinate_type ext_y = get<1>(head) - get<1>(tail); + distance_type segment_length = sqrt(ext_x * ext_x + ext_y * ext_y); + + if (buffered_length < distance_left) + { + distance_left = buffered_length; + } + if (buffered_length < distance_right) + { + distance_right = buffered_length; + } + + distance_type prop_left = distance_left / segment_length; + distance_type prop_right = distance_right / segment_length; + + set<0>(tail_left, get<0>(tail) - ext_x * prop_left); + set<1>(tail_left, get<1>(tail) - ext_y * prop_left); + set<0>(tail_right, get<0>(tail) - ext_x * prop_right); + set<1>(tail_right, get<1>(tail) - ext_y * prop_right); + + buffered_length += segment_length; + } + + + static inline void calculate_head(input_point_type const& tail, input_point_type const& head, + point_type& head_left, point_type& head_right, + distance_type& distance_left, + distance_type& distance_right, + distance_type const& rest_length) + { + coordinate_type ext_x = get<0>(head) - get<0>(tail); + coordinate_type ext_y = get<1>(head) - get<1>(tail); + distance_type segment_length = sqrt(ext_x * ext_x + ext_y * ext_y); + + if (rest_length < distance_left) + { + distance_left = rest_length; + } + if (rest_length < distance_right) + { + distance_right = rest_length; + } + + distance_type prop_left = distance_left / segment_length; + distance_type prop_right = distance_right / segment_length; + + set<0>(head_left, get<0>(head) + ext_x * prop_left); + set<1>(head_left, get<1>(head) + ext_y * prop_left); + set<0>(head_right, get<0>(head) + ext_x * prop_right); + set<1>(head_right, get<1>(head) + ext_y * prop_right); + } + + static inline void apply(Range const& range, + std::vector& buffered, + DistanceStrategy const& distance_strategy, + JoinStrategy const& join_strategy + #ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER + , Mapper& mapper + #endif + ) + { + // Buffer all segments separately, and put them in a temporary vector + std::vector buffered_pieces; + + bool first = true; + + strategy::buffer::join_round2 new_join; + //strategy::buffer::join_none new_join; + + distance_type range_length = geometry::length(range); + distance_type buffered_length = coordinate_type(); + + iterator_type it = boost::begin(range); + //iterator_type it_c = boost::end(range); + for (iterator_type previous = it++; + it != boost::end(range); + ++it) + { + bool const last = it + 1 == boost::end(range); + + distance_type distance_left = distance_strategy.apply( + *previous, *it, buffer_side_left); + distance_type distance_right = distance_strategy.apply( + *previous, *it, buffer_side_right); + + point_type left_ab_p1, left_ab_p2, right_ab_p1, right_ab_p2; + + if (detail::disjoint::disjoint_point_point(*previous, *it) + && calculate_parallels(*previous, *it, left_ab_p1, left_ab_p2, + distance_left) + && calculate_parallels(*previous, *it, right_ab_p1, right_ab_p2, + -distance_right) + ) + { + { + point_type tail_left, tail_right, head_left, head_right; + + // For flat buffers, generate corners only if outside range of buffer_distance + distance_type distance_tail_left = distance_left; + distance_type distance_tail_right = distance_right; + distance_type distance_head_left = distance_left; + distance_type distance_head_right = distance_right; + + calculate_tail(*previous, *it, + tail_left, tail_right, + distance_tail_left, distance_tail_right, + buffered_length); + + distance_type const rest_length = range_length - buffered_length; + + calculate_head(*previous, *it, + head_left, head_right, + distance_head_left, distance_head_right, + rest_length); + + // Add non-axis aligned rectangle + buffered_pieces.resize(buffered_pieces.size() + 1); + ring_type& ring = exterior_ring(buffered_pieces.back()); + ring.push_back(left_ab_p1); + ring.push_back(left_ab_p2); + + if (! last) + { + new_join.apply(*it, left_ab_p2, left_ab_p2, head_left, + distance_left, distance_head_left, + std::back_inserter(ring)); + + ring.push_back(head_left); + ring.push_back(head_right); + + new_join.apply(*it, right_ab_p2, head_right, right_ab_p2, + distance_right, distance_head_right, + std::back_inserter(ring)); + } + + ring.push_back(right_ab_p2); + ring.push_back(right_ab_p1); + + if (! first) + { + new_join.apply(*previous, right_ab_p1, right_ab_p1, tail_right, + distance_right, distance_tail_right, + std::back_inserter(ring)); + + ring.push_back(tail_right); + ring.push_back(tail_left); + + new_join.apply(*previous, left_ab_p1, tail_left, left_ab_p1, + distance_left, distance_tail_left, + std::back_inserter(ring)); + } + + ring.push_back(left_ab_p1); + } + + previous = it; + + first = false; + } + } + + // TEMP + buffered.swap(buffered_pieces); + return; + // END TEMP + + + + BOOST_FOREACH(GeometryOut const& p, buffered_pieces) + { + if (buffered.empty()) + { + buffered.push_back(p); + } + else if (boost::size(buffered) == 1) + { + std::vector unioned; + geometry::union_inserter(buffered.front(), p, std::back_inserter(unioned)); + buffered.swap(unioned); + } + else + { + std::cerr << " D " << buffered.size(); + /*std::vector dissolved; + dissolved.push_back(p); + geometry::dissolver(buffered, dissolved); + dissolved.swap(buffered);*/ + } + } + + /*** + std::vector dissolved; + BOOST_FOREACH(GeometryOut const& p, buffered) + { + geometry::dissolve(p, dissolved); + } + dissolved.swap(buffered); + ***/ + + // Output + } +}; + + + +template +< + typename GeometryOut, typename Geometry, + typename DistanceStrategy, + typename JoinStrategy +#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER + , typename Mapper +#endif +> +inline void segmenting_buffer(Geometry const& geometry, + std::vector& buffered, + DistanceStrategy const& distance_strategy, + JoinStrategy const& join_strategy + #ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER + , Mapper& mapper + #endif + ) +{ + per_segment_buffer + < + GeometryOut, Geometry, + DistanceStrategy, JoinStrategy + >::apply(geometry, buffered, distance_strategy, join_strategy); +} + + + +}} // namespace detail::buffer +#endif // DOXYGEN_NO_DETAIL + + + + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_SEGMENTING_BUFFER_HPP