Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r77299 - in trunk: boost/geometry/algorithms/detail boost/geometry/extensions/algorithms/buffer boost/geometry/extensions/strategies libs/geometry/test/robustness/overlay/buffer libs/geometry/test_extensions/algorithms/buffer
From: barend.gehrels_at_[hidden]
Date: 2012-03-10 16:13:39


Author: barendgehrels
Date: 2012-03-10 16:13:37 EST (Sat, 10 Mar 2012)
New Revision: 77299
URL: http://svn.boost.org/trac/boost/changeset/77299

Log:
[geometry] buffer update (a.o. implemented multi), updated tests, and added robustness test
Added:
   trunk/boost/geometry/extensions/algorithms/buffer/multi_buffer_inserter.hpp (contents, props changed)
   trunk/libs/geometry/test/robustness/overlay/buffer/
   trunk/libs/geometry/test/robustness/overlay/buffer/Jamfile.v2 (contents, props changed)
   trunk/libs/geometry/test/robustness/overlay/buffer/recursive_polygons_buffer.cpp (contents, props changed)
   trunk/libs/geometry/test/robustness/overlay/buffer/recursive_polygons_buffer.sln (contents, props changed)
   trunk/libs/geometry/test/robustness/overlay/buffer/recursive_polygons_buffer.vcproj (contents, props changed)
   trunk/libs/geometry/test_extensions/algorithms/buffer/multi_polygon_buffer.cpp (contents, props changed)
   trunk/libs/geometry/test_extensions/algorithms/buffer/multi_polygon_buffer.vcproj (contents, props changed)
Text files modified:
   trunk/boost/geometry/algorithms/detail/occupation_info.hpp | 7 ++
   trunk/boost/geometry/extensions/algorithms/buffer/buffer_inserter.hpp | 27 +++++++----
   trunk/boost/geometry/extensions/algorithms/buffer/buffered_piece_collection.hpp | 90 +++++++++++++++++++++++++++++++--------
   trunk/boost/geometry/extensions/algorithms/buffer/line_line_intersection.hpp | 2
   trunk/boost/geometry/extensions/strategies/buffer.hpp | 74 ++++++++++++++++++++++++++++++++
   trunk/libs/geometry/test_extensions/algorithms/buffer/Jamfile.v2 | 1
   trunk/libs/geometry/test_extensions/algorithms/buffer/buffer.sln | 6 ++
   trunk/libs/geometry/test_extensions/algorithms/buffer/linestring_buffer.cpp | 6 +-
   trunk/libs/geometry/test_extensions/algorithms/buffer/polygon_buffer.cpp | 13 ++++-
   trunk/libs/geometry/test_extensions/algorithms/buffer/test_buffer.hpp | 67 +++++++++--------------------
   10 files changed, 206 insertions(+), 87 deletions(-)

Modified: trunk/boost/geometry/algorithms/detail/occupation_info.hpp
==============================================================================
--- trunk/boost/geometry/algorithms/detail/occupation_info.hpp (original)
+++ trunk/boost/geometry/algorithms/detail/occupation_info.hpp 2012-03-10 16:13:37 EST (Sat, 10 Mar 2012)
@@ -186,7 +186,7 @@
     typedef std::map<Point, OccupationInfo, geometry::less<Point> > map_type;
     map_type map;
 
- OccupationInfo& find_or_insert(Point point)
+ inline OccupationInfo& find_or_insert(Point const& point)
     {
         typename map_type::iterator it = map.find(point);
         if (it == boost::end(map))
@@ -199,6 +199,11 @@
         return it->second;
     }
 
+ inline bool contains(Point const& point) const
+ {
+ typename map_type::const_iterator it = map.find(point);
+ return it != boost::end(map);
+ }
 };
 
 

Modified: trunk/boost/geometry/extensions/algorithms/buffer/buffer_inserter.hpp
==============================================================================
--- trunk/boost/geometry/extensions/algorithms/buffer/buffer_inserter.hpp (original)
+++ trunk/boost/geometry/extensions/algorithms/buffer/buffer_inserter.hpp 2012-03-10 16:13:37 EST (Sat, 10 Mar 2012)
@@ -238,9 +238,12 @@
             DistanceStrategy const& distance,
             JoinStrategy const& join_strategy)
     {
- base::iterate(collection, boost::begin(ring), boost::end(ring),
- buffer_side_left,
- distance, join_strategy);
+ if (boost::size(ring) > 3)
+ {
+ base::iterate(collection, boost::begin(ring), boost::end(ring),
+ buffer_side_left,
+ distance, join_strategy);
+ }
     }
 };
 
@@ -268,14 +271,17 @@
             DistanceStrategy const& distance,
             JoinStrategy const& join_strategy)
     {
- collection.start_new_ring();
- base::iterate(collection, boost::begin(linestring), boost::end(linestring),
- buffer_side_left,
- distance, join_strategy);
+ if (boost::size(linestring) > 1)
+ {
+ collection.start_new_ring();
+ base::iterate(collection, boost::begin(linestring), boost::end(linestring),
+ buffer_side_left,
+ distance, join_strategy);
                 
- base::iterate(collection, boost::rbegin(linestring), boost::rend(linestring),
- buffer_side_right,
- distance, join_strategy, true);
+ base::iterate(collection, boost::rbegin(linestring), boost::rend(linestring),
+ buffer_side_right,
+ distance, join_strategy, true);
+ }
 
     }
 };
@@ -360,6 +366,7 @@
 
 #ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
     //collection.map_offsetted(mapper);
+ //collection.map_offsetted_points(mapper);
     collection.map_turns(mapper);
     //collection.map_opposite_locations(mapper);
 #endif

Modified: trunk/boost/geometry/extensions/algorithms/buffer/buffered_piece_collection.hpp
==============================================================================
--- trunk/boost/geometry/extensions/algorithms/buffer/buffered_piece_collection.hpp (original)
+++ trunk/boost/geometry/extensions/algorithms/buffer/buffered_piece_collection.hpp 2012-03-10 16:13:37 EST (Sat, 10 Mar 2012)
@@ -155,15 +155,19 @@
 
     inline bool is_neighbor(piece const& piece1, piece const& piece2) const
     {
+ if (piece1.first_seg_id.multi_index != piece2.first_seg_id.multi_index)
+ {
+ return false;
+ }
+
         if (std::abs(piece1.index - piece2.index) == 1)
         {
             return true;
         }
 
- // TODO: of the same multi_index
- int const b = boost::size(m_pieces) - 1; // back
- return (piece1.index == 0 && piece2.index == b)
- || (piece1.index == b && piece2.index == 0)
+ int const last = boost::size(m_pieces) - 1;
+ return (piece1.index == 0 && piece2.index == last)
+ || (piece1.index == last && piece2.index == 0)
             ;
     }
 
@@ -173,21 +177,29 @@
     }
 
     template <typename Range, typename Iterator>
- inline typename boost::range_value<Range const>::type next_point(Range const& range, Iterator it) const
+ inline void move_to_next_point(Range const& range, Iterator& next) const
     {
- Iterator next = it;
         ++next;
+ if (next == boost::end(range))
+ {
+ next = boost::begin(range) + 1;
+ }
+ }
 
- // Get next point. If end get second point (because ring is assumed to be closed)
- return next != boost::end(range) ? *next : *(boost::begin(range) + 1);
+ template <typename Range, typename Iterator>
+ inline Iterator next_point(Range const& range, Iterator it) const
+ {
+ Iterator result = it;
+ move_to_next_point(range, result);
+ while(geometry::equals(*it, *result))
+ {
+ move_to_next_point(range, result);
+ }
+ return result;
     }
 
     inline void calculate_turns(piece const& piece1, piece const& piece2)
     {
- buffer_turn_info<point_type> the_model;
- the_model.operations[0].piece_index = piece1.index;
- the_model.operations[0].seg_id = piece1.first_seg_id;
-
         typedef typename boost::range_iterator<buffered_ring<Ring> const>::type iterator;
 
                 segment_identifier seg_id1 = piece1.first_seg_id;
@@ -206,6 +218,10 @@
                 iterator it2_first = boost::begin(ring2) + seg_id2.segment_index;
                 iterator it2_last = boost::begin(ring2) + piece2.last_segment_index;
 
+ buffer_turn_info<point_type> the_model;
+ the_model.operations[0].piece_index = piece1.index;
+ the_model.operations[0].seg_id = piece1.first_seg_id;
+
         iterator it1 = it1_first;
         for (iterator prev1 = it1++;
                 it1 != it1_last;
@@ -214,6 +230,8 @@
             the_model.operations[1].piece_index = piece2.index;
             the_model.operations[1].seg_id = piece2.first_seg_id;
 
+ iterator next1 = next_point(ring1, it1);
+
             iterator it2 = it2_first;
             for (iterator prev2 = it2++;
                     it2 != it2_last;
@@ -223,8 +241,15 @@
                 the_model.operations[0].other_id = the_model.operations[1].seg_id;
                 the_model.operations[1].other_id = the_model.operations[0].seg_id;
 
- turn_policy::apply(*prev1, *it1, next_point(ring1, it1),
- *prev2, *it2, next_point(ring2, it2),
+ iterator next2 = next_point(ring2, it2);
+
+ if (piece1.index == 21 && piece2.index == 32)
+ {
+ int kkk = 0;
+ }
+
+ turn_policy::apply(*prev1, *it1, *next1,
+ *prev2, *it2, *next2,
                                     the_model, std::back_inserter(m_turns));
             }
         }
@@ -239,6 +264,7 @@
                         {
                                 m_in_opposite_segments.insert(it->operations[0].seg_id);
                                 m_in_opposite_segments.insert(it->operations[1].seg_id);
+//std::cout << " " << it->operations[0].seg_id.segment_index;
                         }
                 }
         }
@@ -344,8 +370,11 @@
         }
         if (side_helper == 0)
         {
- if (geometry::equals(turn.point, pc.helper_segments.back())
- || geometry::equals(turn.point, pc.helper_segments.front()))
+ //BOOST_AUTO(d1, geometry::comparable_distance(turn.point, pc.helper_segments.back()));
+ //BOOST_AUTO(d2, geometry::comparable_distance(turn.point, pc.helper_segments.front()));
+ //if (d1 < 0.1 || d2 < 0.1)
+ if (geometry::equals(turn.point, pc.helper_segments.back())
+ || geometry::equals(turn.point, pc.helper_segments.front()))
             {
                 turn.count_on_corner++;
             }
@@ -384,6 +413,7 @@
                                         m_turns[*sit].count_on_occupied++;
                                 }
                         }
+//std::cout << geometry::wkt(it->first) << " " << int(info.occupied()) << std::endl;
         }
         }
 
@@ -403,6 +433,24 @@
                                 add_angles(index, turn.point, turn.operations[1]);
                         }
                 }
+
+ index = 0;
+ for (typename boost::range_iterator<turn_vector_type>::type it =
+ boost::begin(m_turns); it != boost::end(m_turns); ++it, ++index)
+ {
+ buffer_turn_info<point_type>& turn = *it;
+ if (m_in_opposite_segments.count(turn.operations[0].seg_id) == 0
+ && m_in_opposite_segments.count(turn.operations[1].seg_id) == 0)
+ {
+ // See if it is in the map
+ if (m_occupation_map.contains(turn.point))
+ {
+//std::cout << "Adding point " << geometry::wkt(turn.point) << std::endl;
+ add_angles(index, turn.point, turn.operations[0]);
+ add_angles(index, turn.point, turn.operations[1]);
+ }
+ }
+ }
         }
 
     inline void classify_turns()
@@ -621,7 +669,7 @@
                 offsetted_rings[it->operations[0].seg_id.multi_index].has_discarded_intersections = true;
                 offsetted_rings[it->operations[1].seg_id.multi_index].has_discarded_intersections = true;
             }
- else
+ else if (! it->both(detail::overlay::operation_union))
             {
                 offsetted_rings[it->operations[0].seg_id.multi_index].has_accepted_intersections = true;
                 offsetted_rings[it->operations[1].seg_id.multi_index].has_accepted_intersections = true;
@@ -673,6 +721,8 @@
                 ring_identifier id(0, index, -1);
                 selected[id] = properties(*it, true);
             }
+
+//std::cout << geometry::wkt(*it) << std::endl;
         }
 
         // Select all created rings
@@ -682,11 +732,11 @@
                 it != boost::end(traversed_rings);
                 ++it, ++index)
         {
- ring_identifier id(2, index, -1);
- selected[id] = properties(*it, true);
+ ring_identifier id(2, index, -1);
+ selected[id] = properties(*it, true);
         }
 
- detail::overlay::assign_parents(offsetted_rings, traversed_rings, selected);
+ detail::overlay::assign_parents(offsetted_rings, traversed_rings, selected, false);
         return detail::overlay::add_rings<GeometryOutput>(selected, offsetted_rings, traversed_rings, out);
     }
 

Modified: trunk/boost/geometry/extensions/algorithms/buffer/line_line_intersection.hpp
==============================================================================
--- trunk/boost/geometry/extensions/algorithms/buffer/line_line_intersection.hpp (original)
+++ trunk/boost/geometry/extensions/algorithms/buffer/line_line_intersection.hpp 2012-03-10 16:13:37 EST (Sat, 10 Mar 2012)
@@ -52,7 +52,7 @@
         {
             set<0>(p, x2);
             set<1>(p, y2);
- return true;
+ return false;
         }
 
         coordinate_type d1 = det(x1, y1, x2, y2);

Added: trunk/boost/geometry/extensions/algorithms/buffer/multi_buffer_inserter.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/geometry/extensions/algorithms/buffer/multi_buffer_inserter.hpp 2012-03-10 16:13:37 EST (Sat, 10 Mar 2012)
@@ -0,0 +1,91 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2012 Barend Gehrels, 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_MULTI_BUFFER_INSERTER_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_MULTI_BUFFER_INSERTER_HPP
+
+#include <boost/range.hpp>
+#include <boost/typeof/typeof.hpp>
+
+#include <boost/geometry/multi/core/point_type.hpp>
+
+#include <boost/geometry/extensions/algorithms/buffer/buffer_inserter.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace buffer
+{
+
+template <>
+struct check_original<multi_polygon_tag>
+{
+ template <typename Point, typename Geometry>
+ static inline int apply(Point const& point, Geometry const& geometry)
+ {
+ return geometry::covered_by(point, geometry) ? 1 : -1;
+ }
+};
+
+}} // namespace detail::buffer
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template
+<
+ typename Multi,
+ typename PolygonOutput
+>
+struct buffer_inserter<multi_polygon_tag, Multi, PolygonOutput>
+{
+ template
+ <
+ typename Collection, typename DistanceStrategy, typename JoinStrategy
+ >
+ static inline void apply(Multi const& multi,
+ Collection& collection,
+ DistanceStrategy const& distance,
+ JoinStrategy const& join_strategy)
+ {
+ typedef typename ring_type<PolygonOutput>::type output_ring_type;
+ typedef buffer_inserter
+ <
+ typename single_tag_of
+ <
+ typename tag<Multi>::type
+ >::type,
+ typename boost::range_value<Multi const>::type,
+ output_ring_type
+ > policy;
+
+ for (typename boost::range_iterator<Multi const>::type
+ it = boost::begin(multi);
+ it != boost::end(multi);
+ ++it)
+ {
+ policy::apply(*it, collection, distance, join_strategy);
+ }
+ }
+};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_MULTI_BUFFER_INSERTER_HPP

Modified: trunk/boost/geometry/extensions/strategies/buffer.hpp
==============================================================================
--- trunk/boost/geometry/extensions/strategies/buffer.hpp (original)
+++ trunk/boost/geometry/extensions/strategies/buffer.hpp 2012-03-10 16:13:37 EST (Sat, 10 Mar 2012)
@@ -21,6 +21,7 @@
 #include <boost/geometry/strategies/tags.hpp>
 #include <boost/geometry/strategies/side.hpp>
 #include <boost/geometry/util/math.hpp>
+#include <boost/geometry/util/select_most_precise.hpp>
 
 #include <boost/geometry/extensions/strategies/buffer_side.hpp>
 
@@ -157,9 +158,20 @@
 
     typedef typename strategy::side::services::default_strategy<typename cs_tag<PointIn>::type>::type side;
     typedef typename coordinate_type<PointOut>::type coordinate_type;
- int m_max_level;
 
+ typedef typename geometry::select_most_precise
+ <
+ typename geometry::select_most_precise
+ <
+ typename geometry::coordinate_type<PointIn>::type,
+ typename geometry::coordinate_type<PointOut>::type
+ >::type,
+ double
+ >::type promoted_type;
+
+ int m_max_level;
 
+#ifdef BOOST_GEOMETRY_BUFFER_USE_MIDPOINTS
     template <typename RangeOut>
     inline void mid_points(PointIn const& vertex,
                 PointIn const& p1, PointIn const& p2,
@@ -196,9 +208,55 @@
         {
             mid_points(vertex, mid_point, p2, buffer_distance, range_out, level + 1);
         }
-
     }
+#endif
+
+ template <typename RangeOut>
+ inline void generate_points(PointIn const& vertex,
+ PointIn const& perp1, PointIn const& perp2,
+ promoted_type const& buffer_distance,
+ RangeOut& range_out) const
+ {
+ promoted_type dx1 = get<0>(perp1) - get<0>(vertex);
+ promoted_type dy1 = get<1>(perp1) - get<1>(vertex);
+ promoted_type dx2 = get<0>(perp2) - get<0>(vertex);
+ promoted_type dy2 = get<1>(perp2) - get<1>(vertex);
+
+ dx1 /= buffer_distance;
+ dy1 /= buffer_distance;
+ dx2 /= buffer_distance;
+ dy2 /= buffer_distance;
+
+ promoted_type angle_diff = std::acos(dx1 * dx2 + dy1 * dy2);
+
+ // Default might be 100 steps for a full circle (2 pi)
+ promoted_type const steps_per_circle = 100.0;
+ int n = int(steps_per_circle * angle_diff
+ / (2.0 * geometry::math::pi<promoted_type>()));
+
+ if (n > 1000)
+ {
+ std::cout << dx1 << ", " << dy1 << " .. " << dx2 << ", " << dy2 << std::endl;
+ std::cout << angle_diff << " -> " << n << std::endl;
+ n = 1000;
+ }
+ else if (n <= 1)
+ {
+ return;
+ }
+
+ promoted_type const angle1 = std::atan2(dy1, dx1);
+ promoted_type diff = angle_diff / promoted_type(n);
+ promoted_type a = angle1 - diff;
 
+ for (int i = 0; i < n - 1; i++, a -= diff)
+ {
+ PointIn p;
+ set<0>(p, get<0>(vertex) + buffer_distance * cos(a));
+ set<1>(p, get<1>(vertex) + buffer_distance * sin(a));
+ range_out.push_back(p);
+ }
+ }
 
     template <typename RangeOut>
     inline void apply(PointIn const& ip, PointIn const& vertex,
@@ -206,6 +264,12 @@
                 coordinate_type const& buffer_distance,
                 RangeOut& range_out) const
     {
+ if (geometry::equals(perp1, perp2))
+ {
+ //std::cout << "Corner for equal points " << geometry::wkt(ip) << " " << geometry::wkt(perp1) << std::endl;
+ return;
+ }
+
         coordinate_type zero = 0;
         int signum = buffer_distance > zero ? 1
                    : buffer_distance < zero ? -1
@@ -231,6 +295,8 @@
             set<1>(bp, get<1>(vertex) + viy * prop);
 
             range_out.push_back(perp1);
+
+#ifdef BOOST_GEOMETRY_BUFFER_USE_MIDPOINTS
             if (m_max_level <= 1)
             {
                 if (m_max_level == 1)
@@ -244,6 +310,10 @@
                 range_out.push_back(bp);
                 mid_points(vertex, bp, perp2, bd, range_out);
             }
+#else
+ generate_points(vertex, perp1, perp2, bd, range_out);
+#endif
+
             range_out.push_back(perp2);
         }
     }

Added: trunk/libs/geometry/test/robustness/overlay/buffer/Jamfile.v2
==============================================================================
--- (empty file)
+++ trunk/libs/geometry/test/robustness/overlay/buffer/Jamfile.v2 2012-03-10 16:13:37 EST (Sat, 10 Mar 2012)
@@ -0,0 +1,19 @@
+# Boost.Geometry (aka GGL, Generic Geometry Library)
+# Robustness Test - overlay - buffer
+#
+# Copyright (c) 2012 Barend Gehrels, 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)
+
+
+project recursive_polygons_buffer
+ : requirements
+ <include>.
+ <include>../..
+ <library>../../../../../program_options/build//boost_program_options
+ <link>static
+ ;
+
+exe recursive_polygons_buffer : recursive_polygons_buffer.cpp ;

Added: trunk/libs/geometry/test/robustness/overlay/buffer/recursive_polygons_buffer.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/geometry/test/robustness/overlay/buffer/recursive_polygons_buffer.cpp 2012-03-10 16:13:37 EST (Sat, 10 Mar 2012)
@@ -0,0 +1,352 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+// Robustness Test
+
+// Copyright (c) 2012 Barend Gehrels, 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)
+
+#if defined(_MSC_VER)
+# pragma warning( disable : 4244 )
+# pragma warning( disable : 4267 )
+#endif
+
+#include <fstream>
+#include <sstream>
+
+#include <boost/foreach.hpp>
+#include <boost/program_options.hpp>
+#include <boost/random/linear_congruential.hpp>
+#include <boost/random/uniform_int.hpp>
+#include <boost/random/uniform_real.hpp>
+#include <boost/random/variate_generator.hpp>
+#include <boost/timer.hpp>
+
+#include <boost/geometry.hpp>
+#include <boost/geometry/geometries/geometries.hpp>
+#include <boost/geometry/geometries/point_xy.hpp>
+#include <boost/geometry/multi/geometries/multi_geometries.hpp>
+
+#include <boost/geometry/extensions/io/svg/svg_mapper.hpp>
+#include <boost/geometry/extensions/algorithms/midpoints.hpp>
+
+#include <boost/geometry/extensions/algorithms/buffer/buffer_inserter.hpp>
+
+#include <boost/geometry/multi/multi.hpp> // TODO: more specific
+#include <boost/geometry/extensions/algorithms/buffer/multi_buffer_inserter.hpp>
+
+#include <boost/geometry/extensions/strategies/buffer.hpp>
+
+
+#include <common/common_settings.hpp>
+#include <common/make_square_polygon.hpp>
+
+
+struct buffer_settings : public common_settings
+{
+ int join_code;
+ double distance;
+};
+
+namespace bg = boost::geometry;
+
+template <typename Geometry1, typename Geometry2>
+void create_svg(std::string const& filename
+ , Geometry1 const& mp
+ , Geometry2 const& buffer
+ )
+{
+ typedef typename boost::geometry::point_type<Geometry1>::type point_type;
+
+
+ std::ofstream svg(filename.c_str());
+ boost::geometry::svg_mapper<point_type> mapper(svg, 800, 800);
+
+ boost::geometry::model::box<point_type> box;
+ bg::envelope(mp, box);
+ bg::buffer(box, box, 1.0);
+ mapper.add(box);
+
+ if (bg::num_points(buffer) > 0)
+ {
+ bg::envelope(buffer, box);
+ bg::buffer(box, box, 1.0);
+ mapper.add(box);
+ }
+
+ mapper.map(mp, "fill-opacity:0.5;fill:rgb(153,204,0);stroke:rgb(153,204,0);stroke-width:3");
+ mapper.map(buffer, "stroke-opacity:0.9;stroke:rgb(0,0,0);fill:none;stroke-width:1");
+
+ //mapper.map(intersection,"opacity:0.6;stroke:rgb(0,128,0);stroke-width:5");
+}
+
+
+
+
+template <typename MultiPolygon, typename Settings>
+bool verify(std::string const& caseid, MultiPolygon const& mp, MultiPolygon const& buffer, Settings const& settings)
+{
+ bool result = true;
+
+ // Area of buffer must be larger than of original polygon
+ BOOST_AUTO(area_mp, bg::area(mp));
+ BOOST_AUTO(area_buf, bg::area(buffer));
+
+ if (area_buf < area_mp)
+ {
+ result = false;
+ }
+
+ if (result)
+ {
+ typedef boost::range_value<MultiPolygon const>::type polygon_type;
+ BOOST_FOREACH(polygon_type const& polygon, mp)
+ {
+ typename bg::point_type<polygon_type>::type point;
+ bg::point_on_border(point, polygon);
+ if (! bg::within(point, buffer))
+ {
+ result = false;
+ }
+ }
+ }
+
+ bool svg = settings.svg;
+ bool wkt = settings.wkt;
+ if (! result)
+ {
+ std::cout << "ERROR " << caseid << std::endl;
+ //std::cout << bg::wkt(mp) << std::endl;
+ //std::cout << bg::wkt(buffer) << std::endl;
+ svg = true;
+ wkt = true;
+ }
+
+ if (svg || wkt)
+ {
+ //std::cout << caseid << std::endl;
+ }
+
+ if (svg)
+ {
+ std::ostringstream filename;
+ filename << caseid << "_"
+ << typeid(typename bg::coordinate_type<MultiPolygon>::type).name()
+ << ".svg";
+ create_svg(filename.str(), mp, buffer);
+ }
+
+ if (wkt)
+ {
+ std::ostringstream filename;
+ filename << caseid << "_"
+ << typeid(typename bg::coordinate_type<MultiPolygon>::type).name()
+ << ".wkt";
+ std::ofstream stream(filename.str().c_str());
+ stream << bg::wkt(mp) << std::endl;
+ stream << bg::wkt(buffer) << std::endl;
+ }
+
+ return result;
+}
+
+template <typename MultiPolygon, typename Generator, typename Settings>
+bool test_buffer(MultiPolygon& result, int& index,
+ Generator& generator,
+ int level, Settings const& settings)
+{
+ MultiPolygon p, q;
+
+ // Generate two boxes
+ if (level == 0)
+ {
+ p.resize(1);
+ q.resize(1);
+ make_square_polygon(p.front(), generator, settings);
+ make_square_polygon(q.front(), generator, settings);
+ bg::correct(p);
+ bg::correct(q);
+ }
+ else
+ {
+ bg::correct(p);
+ bg::correct(q);
+ if (! test_buffer(p, index, generator, level - 1, settings)
+ || ! test_buffer(q, index, generator, level - 1, settings))
+ {
+ return false;
+ }
+ }
+
+ typedef typename boost::range_value<MultiPolygon>::type polygon;
+
+ MultiPolygon mp;
+ bg::detail::union_::union_insert
+ <
+ polygon
+ >(p, q, std::back_inserter(mp));
+
+ bg::unique(mp);
+ bg::unique(mp);
+ bg::correct(mp);
+ result = mp;
+
+
+ typedef typename bg::coordinate_type<MultiPolygon>::type coordinate_type;
+ typedef typename bg::point_type<MultiPolygon>::type point_type;
+ typedef bg::strategy::buffer::distance_assymetric<coordinate_type> distance_strategy_type;
+ distance_strategy_type distance_strategy(settings.distance, settings.distance);
+
+ typedef bg::strategy::buffer::join_round<point_type, point_type> join_strategy_type;
+ join_strategy_type join_strategy;
+
+ typedef typename boost::range_value<MultiPolygon>::type polygon_type;
+ MultiPolygon buffered;
+
+ std::ostringstream out;
+ out << "recursive_polygons_buffer_" << index++ << "_" << level;
+
+ try
+ {
+ switch(settings.join_code)
+ {
+ case 1 :
+ bg::buffer_inserter<polygon_type>(mp, std::back_inserter(buffered),
+ distance_strategy,
+ bg::strategy::buffer::join_round<point_type, point_type>());
+ break;
+ case 2 :
+ bg::buffer_inserter<polygon_type>(mp, std::back_inserter(buffered),
+ distance_strategy,
+ bg::strategy::buffer::join_miter<point_type, point_type>());
+ break;
+ default :
+ return false;
+ }
+ }
+ catch(std::exception const& e)
+ {
+ MultiPolygon empty;
+ std::cout << out.str() << std::endl;
+ std::cout << "Exception " << e.what() << std::endl;
+ verify(out.str(), mp, empty, settings);
+ return false;
+ }
+
+
+ return verify(out.str(), mp, buffered, settings);
+}
+
+
+template <typename T, bool Clockwise, bool Closed, typename Settings>
+void test_all(int seed, int count, int level, Settings const& settings)
+{
+ boost::timer t;
+
+ typedef boost::minstd_rand base_generator_type;
+
+ base_generator_type generator(seed);
+
+ boost::uniform_int<> random_coordinate(0, settings.field_size - 1);
+ boost::variate_generator<base_generator_type&, boost::uniform_int<> >
+ coordinate_generator(generator, random_coordinate);
+
+ typedef bg::model::polygon
+ <
+ bg::model::d2::point_xy<T>, Clockwise, Closed
+ > polygon;
+ typedef bg::model::multi_polygon<polygon> mp;
+
+
+ int index = 0;
+ for(int i = 0; i < count; i++)
+ {
+ mp p;
+ test_buffer<mp>(p, index, coordinate_generator, level, settings);
+ }
+ std::cout
+ << "geometries: " << index
+ << " type: " << typeid(T).name()
+ << " time: " << t.elapsed() << std::endl;
+}
+
+int main(int argc, char** argv)
+{
+ try
+ {
+ namespace po = boost::program_options;
+ po::options_description description("=== recursive_polygons_linear_areal ===\nAllowed options");
+
+ int count = 1;
+ int seed = static_cast<unsigned int>(std::time(0));
+ int level = 3;
+ bool ccw = false;
+ bool open = false;
+ buffer_settings settings;
+ std::string form = "box";
+ std::string join = "round";
+
+ description.add_options()
+ ("help", "Help message")
+ ("seed", po::value<int>(&seed), "Initialization seed for random generator")
+ ("count", po::value<int>(&count)->default_value(1), "Number of tests")
+ ("level", po::value<int>(&level)->default_value(3), "Level to reach (higher->slower)")
+ ("distance", po::value<double>(&settings.distance)->default_value(1.0), "Distance (1.0)")
+ ("form", po::value<std::string>(&form)->default_value("box"), "Form of the polygons (box, triangle)")
+ ("join", po::value<std::string>(&join)->default_value("round"), "Form of the joins (round, miter)")
+ ("ccw", po::value<bool>(&ccw)->default_value(false), "Counter clockwise polygons")
+ ("open", po::value<bool>(&open)->default_value(false), "Open polygons")
+ ("size", po::value<int>(&settings.field_size)->default_value(10), "Size of the field")
+ ("wkt", po::value<bool>(&settings.wkt)->default_value(false), "Create a WKT of the inputs, for all tests")
+ ("svg", po::value<bool>(&settings.svg)->default_value(false), "Create a SVG for all tests")
+ ;
+
+ po::variables_map varmap;
+ po::store(po::parse_command_line(argc, argv, description), varmap);
+ po::notify(varmap);
+
+ if (varmap.count("help")
+ || (form != "box" && form != "triangle")
+ || (join != "round" && join != "miter")
+ )
+ {
+ std::cout << description << std::endl;
+ return 1;
+ }
+
+ settings.triangular = form != "box";
+ settings.join_code = join == "round" ? 1 : 2;
+
+ if (ccw && open)
+ {
+ test_all<double, false, false>(seed, count, level, settings);
+ }
+ else if (ccw)
+ {
+ test_all<double, false, true>(seed, count, level, settings);
+ }
+ else if (open)
+ {
+ test_all<double, true, false>(seed, count, level, settings);
+ }
+ else
+ {
+ test_all<double, true, true>(seed, count, level, settings);
+ }
+
+#if defined(HAVE_TTMATH)
+ // test_all<ttmath_big, true, true>(seed, count, max, svg, level);
+#endif
+ }
+ catch(std::exception const& e)
+ {
+ std::cout << "Exception " << e.what() << std::endl;
+ }
+ catch(...)
+ {
+ std::cout << "Other exception" << std::endl;
+ }
+
+ return 0;
+}

Added: trunk/libs/geometry/test/robustness/overlay/buffer/recursive_polygons_buffer.sln
==============================================================================
--- (empty file)
+++ trunk/libs/geometry/test/robustness/overlay/buffer/recursive_polygons_buffer.sln 2012-03-10 16:13:37 EST (Sat, 10 Mar 2012)
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "recursive_polygons_buffer", "recursive_polygons_buffer.vcxproj", "{02C9CFA4-C625-55CA-1C8E-2B96EBB09FE8}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {02C9CFA4-C625-55CA-1C8E-2B96EBB09FE8}.Debug|Win32.ActiveCfg = Debug|Win32
+ {02C9CFA4-C625-55CA-1C8E-2B96EBB09FE8}.Debug|Win32.Build.0 = Debug|Win32
+ {02C9CFA4-C625-55CA-1C8E-2B96EBB09FE8}.Release|Win32.ActiveCfg = Release|Win32
+ {02C9CFA4-C625-55CA-1C8E-2B96EBB09FE8}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal

Added: trunk/libs/geometry/test/robustness/overlay/buffer/recursive_polygons_buffer.vcproj
==============================================================================
--- (empty file)
+++ trunk/libs/geometry/test/robustness/overlay/buffer/recursive_polygons_buffer.vcproj 2012-03-10 16:13:37 EST (Sat, 10 Mar 2012)
@@ -0,0 +1,222 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="recursive_polygons_buffer"
+ RootNamespace="recursive_polygons_buffer"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)\recursive_polygons_buffer"
+ ConfigurationType="1"
+ InheritedPropertySheets="..\..\..\boost.vsprops"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../../../../..;.;../.."
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;BOOST_ALL_NO_LIB"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="0"
+ WarningLevel="2"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalLibraryDirectories=""
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)\recursive_polygons_buffer"
+ ConfigurationType="1"
+ InheritedPropertySheets="..\..\..\boost.vsprops"
+ CharacterSet="1"
+ WholeProgramOptimization="0"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../../../../../..;.;../.."
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;BOOST_ALL_NO_LIB"
+ RuntimeLibrary="0"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="program options"
+ >
+ <File
+ RelativePath="..\..\..\..\..\program_options\src\cmdline.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\program_options\src\config_file.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\program_options\src\convert.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\program_options\src\options_description.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\program_options\src\parsers.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\program_options\src\positional_options.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\program_options\src\split.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\program_options\src\utf8_codecvt_facet.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\program_options\src\value_semantic.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\..\program_options\src\variables_map.cpp"
+ >
+ </File>
+ </Filter>
+ <File
+ RelativePath=".\recursive_polygons_buffer.cpp"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>

Modified: trunk/libs/geometry/test_extensions/algorithms/buffer/Jamfile.v2
==============================================================================
--- trunk/libs/geometry/test_extensions/algorithms/buffer/Jamfile.v2 (original)
+++ trunk/libs/geometry/test_extensions/algorithms/buffer/Jamfile.v2 2012-03-10 16:13:37 EST (Sat, 10 Mar 2012)
@@ -16,5 +16,6 @@
     :
     [ run polygon_buffer.cpp ]
     [ run linestring_buffer.cpp ]
+ [ run multi_polygon_buffer.cpp ]
     ;
 

Modified: trunk/libs/geometry/test_extensions/algorithms/buffer/buffer.sln
==============================================================================
--- trunk/libs/geometry/test_extensions/algorithms/buffer/buffer.sln (original)
+++ trunk/libs/geometry/test_extensions/algorithms/buffer/buffer.sln 2012-03-10 16:13:37 EST (Sat, 10 Mar 2012)
@@ -4,6 +4,8 @@
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "linestring_buffer", "linestring_buffer.vcproj", "{02387445-E879-49F4-8264-C7CF9C6B8B9D}"
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "multi_polygon_buffer", "multi_polygon_buffer.vcproj", "{1E74F110-996E-44DD-A2EC-5D3B55425903}"
+EndProject
 Global
         GlobalSection(SolutionConfigurationPlatforms) = preSolution
                 Debug|Win32 = Debug|Win32
@@ -18,6 +20,10 @@
                 {02387445-E879-49F4-8264-C7CF9C6B8B9D}.Debug|Win32.Build.0 = Debug|Win32
                 {02387445-E879-49F4-8264-C7CF9C6B8B9D}.Release|Win32.ActiveCfg = Release|Win32
                 {02387445-E879-49F4-8264-C7CF9C6B8B9D}.Release|Win32.Build.0 = Release|Win32
+ {1E74F110-996E-44DD-A2EC-5D3B55425903}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1E74F110-996E-44DD-A2EC-5D3B55425903}.Debug|Win32.Build.0 = Debug|Win32
+ {1E74F110-996E-44DD-A2EC-5D3B55425903}.Release|Win32.ActiveCfg = Release|Win32
+ {1E74F110-996E-44DD-A2EC-5D3B55425903}.Release|Win32.Build.0 = Release|Win32
         EndGlobalSection
         GlobalSection(SolutionProperties) = preSolution
                 HideSolutionNode = FALSE

Modified: trunk/libs/geometry/test_extensions/algorithms/buffer/linestring_buffer.cpp
==============================================================================
--- trunk/libs/geometry/test_extensions/algorithms/buffer/linestring_buffer.cpp (original)
+++ trunk/libs/geometry/test_extensions/algorithms/buffer/linestring_buffer.cpp 2012-03-10 16:13:37 EST (Sat, 10 Mar 2012)
@@ -93,9 +93,9 @@
     //test_one<linestring, buf::join_round, polygon>("curve", curve, 'r', 99, 5.0, 3.0);
     //test_one<linestring, buf::join_miter, polygon>("curve", curve, 'm', 99, 5.0, 3.0);
 
- //test_one<linestring, buf::join_round, polygon>("chained2", chained2, 'r', 99, 2.5, 1.5);
- //test_one<linestring, buf::join_round, polygon>("chained3", chained3, 'r', 99, 2.5, 1.5);
- //test_one<linestring, buf::join_round, polygon>("chained4", chained4, 'r', 99, 2.5, 1.5);
+ test_one<linestring, buf::join_round, polygon>("chained2", chained2, 'r', 11.3137, 2.5, 1.5);
+ test_one<linestring, buf::join_round, polygon>("chained3", chained3, 'r', 16.9706, 2.5, 1.5);
+ test_one<linestring, buf::join_round, polygon>("chained4", chained4, 'r', 22.6274, 2.5, 1.5);
 
     //test_one<linestring, buf::join_round, polygon>("reallife1", reallife1, 'r', 99, 16.5, 6.5);
 }

Added: trunk/libs/geometry/test_extensions/algorithms/buffer/multi_polygon_buffer.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/geometry/test_extensions/algorithms/buffer/multi_polygon_buffer.cpp 2012-03-10 16:13:37 EST (Sat, 10 Mar 2012)
@@ -0,0 +1,123 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+// Unit Test
+
+// Copyright (c) 2010-2012 Barend Gehrels, 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)
+
+
+#include <geometry_test_common.hpp>
+
+#define BOOST_GEOMETRY_TEST_BUFFER_POLYGON
+#include <test_buffer.hpp>
+
+#include <boost/geometry/multi/multi.hpp> // TODO: more specific
+#include <boost/geometry/multi/geometries/multi_geometries.hpp>
+#include <boost/geometry/extensions/algorithms/buffer/multi_buffer_inserter.hpp>
+
+
+
+static std::string const simplex
+ = "MULTIPOLYGON(((0 1,2 5,5 3,0 1)),((1 1,5 2,5 0,1 1)))";
+
+static std::string const zonethru
+ = "MULTIPOLYGON(((0 0,0 6,5 6,5 4,3 4,3 0,0 0)),((5 0,5 2,7 2,7 6,10 6,10 0,5 0)))";
+
+static std::string const wrapped
+ = "MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0),(2 2,8 2,8 8,2 8,2 2)),((4 4,4 6,6 6,6 4,4 4)))";
+
+// From robustness tests
+
+// Case with duplicate points (due to chained boxes) (round)
+static std::string const rt_a
+ = "MULTIPOLYGON(((2 7,2 8,3 8,3 7,2 7)),((5 4,5 5,6 5,6 4,5 4)),((5 8,6 8,6 7,6 6,5 6,5 7,4 7,4 8,5 8)),((3 5,4 5,4 4,3 4,2 4,2 5,3 5)))";
+
+// Case with u-u (miter)
+static std::string const rt_b
+ = "MULTIPOLYGON(((8 4,8 5,9 5,9 4,8 4)),((6 2,6 3,7 3,7 2,6 2)),((8 0,8 1,9 1,9 0,8 0)),((9 7,9 8,10 8,10 7,9 7)))";
+
+// Case with geometry::equals( turn.point(7.0000000000000000, 4.3368086899420177e-019), helper_segment(7.0000000000000000, 0.00000000000000000))) (round)
+static std::string const rt_c
+ = "MULTIPOLYGON(((6 1,6 2,7 2,7 1,6 1)),((8 0,8 1,9 1,9 0,8 0)))";
+
+// Case with round corner on same perpendicular points (round)
+static std::string const rt_d
+ = "MULTIPOLYGON(((2 2,2 3,3 2,2 2)),((2 5,2 6,3 5,2 5)),((2 4,2 5,3 4,2 4)),((3 2,3 3,4 2,3 2)),((4 4,4 5,5 4,4 4)),((5 6,5 5,4 5,4 6,5 7,5 6)),((2 2,3 1,3 0,2 0,2 1,1 1,1 2,2 2)),((1 3,1 2,0 2,1 3)),((1 4,2 4,2 3,1 3,1 4)))";
+
+// Case with missing turning point (miter) and many intersections (round, OK)
+static std::string const rt_e
+ = "MULTIPOLYGON(((0 6,0 7,1 6,0 6)),((3 7,3 8,4 8,4 7,3 7)),((4 6,4 7,5 7,4 6)),((3 6,3 7,4 6,3 6)),((1 9,2 10,2 9,1 9)),((1 9,1 8,0 8,0 9,1 9)),((3 5,3 4,2 4,2 5,2 6,3 5)))";
+
+// Extact of e (miter)
+static std::string const rt_f
+ = "MULTIPOLYGON(((0 6,0 7,1 6,0 6)),((1 9,1 8,0 8,0 9,1 9)))";
+
+static std::string const rt_g
+ = "MULTIPOLYGON(((3 8,3 9,4 9,3 8)),((7 5,7 6,8 5,7 5)),((1 8,1 9,2 9,1 8)),((1 6,1 7,2 7,1 6)))";
+
+
+
+template <typename P>
+void test_all()
+{
+ namespace buf = bg::strategy::buffer;
+
+ typedef bg::model::polygon<P> polygon_type;
+ typedef bg::model::multi_polygon<polygon_type> multi_polygon_type;
+// goto wrong;
+ test_one<multi_polygon_type, buf::join_round, polygon_type>("multi_simplex_05", simplex, 'r', 23.7030, 0.5);
+ test_one<multi_polygon_type, buf::join_miter, polygon_type>("multi_simplex_05", simplex, 'm', 24.5965, 0.5);
+ test_one<multi_polygon_type, buf::join_round, polygon_type>("multi_simplex_10", simplex, 'r', 34.2532, 1.0);
+ test_one<multi_polygon_type, buf::join_miter, polygon_type>("multi_simplex_10", simplex, 'm', 38.1379, 1.0);
+ test_one<multi_polygon_type, buf::join_round, polygon_type>("multi_simplex_20", simplex, 'r', 59.9159, 2.0);
+ test_one<multi_polygon_type, buf::join_miter, polygon_type>("multi_simplex_20", simplex, 'm', 77.7060, 2.0);
+ test_one<multi_polygon_type, buf::join_round, polygon_type>("multi_simplex_50", simplex, 'r', 174.46, 5.0);
+ test_one<multi_polygon_type, buf::join_miter, polygon_type>("multi_simplex_50", simplex, 'm', 298.797, 5.0);
+
+ test_one<multi_polygon_type, buf::join_round, polygon_type>("zonethru_05", zonethru, 'r', 67.4627, 0.5);
+ test_one<multi_polygon_type, buf::join_miter, polygon_type>("zonethru_05", zonethru, 'm', 68.0000, 0.5);
+ test_one<multi_polygon_type, buf::join_round, polygon_type>("zonethru_10", zonethru, 'r', 93.8508, 1.0, -999, 1);
+ test_one<multi_polygon_type, buf::join_miter, polygon_type>("zonethru_10", zonethru, 'm', 96.0000, 1.0);
+ test_one<multi_polygon_type, buf::join_round, polygon_type>("zonethru_15", zonethru, 'r', 114.584, 1.5);
+ test_one<multi_polygon_type, buf::join_miter, polygon_type>("zonethru_15", zonethru, 'm', 117.000, 1.5);
+ test_one<multi_polygon_type, buf::join_round, polygon_type>("wrapped_05", wrapped, 'r', 104.570, 0.5);
+ test_one<multi_polygon_type, buf::join_miter, polygon_type>("wrapped_05", wrapped, 'm', 105.000, 0.5);
+ test_one<multi_polygon_type, buf::join_round, polygon_type>("wrapped_10", wrapped, 'r', 142.281, 1.0);
+ test_one<multi_polygon_type, buf::join_miter, polygon_type>("wrapped_10", wrapped, 'm', 144.000, 1.0);
+ test_one<multi_polygon_type, buf::join_round, polygon_type>("wrapped_15", wrapped, 'r', 167.066, 1.5);
+ test_one<multi_polygon_type, buf::join_miter, polygon_type>("wrapped_15", wrapped, 'm', 169.000, 1.5);
+
+ test_one<multi_polygon_type, buf::join_round, polygon_type>("rt_a", rt_a, 'r', 34.5344, 1.0);
+ test_one<multi_polygon_type, buf::join_miter, polygon_type>("rt_a", rt_a, 'm', 36, 1.0);
+ test_one<multi_polygon_type, buf::join_round, polygon_type>("rt_b", rt_b, 'r', 31.4186, 1.0);
+ test_one<multi_polygon_type, buf::join_miter, polygon_type>("rt_b", rt_b, 'm', 34, 1.0);
+ test_one<multi_polygon_type, buf::join_round, polygon_type>("rt_c", rt_c, 'r', 14.7093, 1.0);
+ test_one<multi_polygon_type, buf::join_miter, polygon_type>("rt_c", rt_c, 'm', 16, 1.0);
+ test_one<multi_polygon_type, buf::join_round, polygon_type>("rt_d", rt_d, 'r', 18.8726, 0.3);
+ test_one<multi_polygon_type, buf::join_miter, polygon_type>("rt_d", rt_d, 'm', 19.8823, 0.3);
+ test_one<multi_polygon_type, buf::join_round, polygon_type>("rt_e", rt_e, 'r', 14.1866, 0.3);
+ test_one<multi_polygon_type, buf::join_miter, polygon_type>("rt_e", rt_e, 'm', 15.1198, 0.3);
+ test_one<multi_polygon_type, buf::join_round, polygon_type>("rt_f", rt_f, 'r', 4.28937, 0.3);
+ test_one<multi_polygon_type, buf::join_miter, polygon_type>("rt_f", rt_f, 'm', 4.60853, 0.3);
+
+// TO BE FIXED:
+// wrong:
+// test_one<multi_polygon_type, buf::join_round, polygon_type>("rt_g", rt_g, 'r', 99, 1.0);
+// test_one<multi_polygon_type, buf::join_miter, polygon_type>("rt_g", rt_g, 'm', 99, 1.0);
+}
+
+
+#ifdef HAVE_TTMATH
+#include <ttmath_stub.hpp>
+#endif
+
+int test_main(int, char* [])
+{
+ test_all<bg::model::point<double, 2, bg::cs::cartesian> >();
+ //test_all<bg::model::point<tt, 2, bg::cs::cartesian> >();
+
+ return 0;
+}
+

Added: trunk/libs/geometry/test_extensions/algorithms/buffer/multi_polygon_buffer.vcproj
==============================================================================
--- (empty file)
+++ trunk/libs/geometry/test_extensions/algorithms/buffer/multi_polygon_buffer.vcproj 2012-03-10 16:13:37 EST (Sat, 10 Mar 2012)
@@ -0,0 +1,174 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8,00"
+ Name="multi_polygon_buffer"
+ ProjectGUID="{1E74F110-996E-44DD-A2EC-5D3B55425903}"
+ RootNamespace="multi_polygon_buffer"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)\multi_polygon_buffer"
+ ConfigurationType="1"
+ InheritedPropertySheets="..\..\boost.vsprops"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=".;../../../../..;../../../test"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ ExceptionHandling="2"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="0"
+ DebugInformationFormat="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)\multi_polygon_buffer"
+ ConfigurationType="1"
+ InheritedPropertySheets="..\..\boost.vsprops"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=".;../../../../..;../../../test"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ ExceptionHandling="2"
+ UsePrecompiledHeader="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <File
+ RelativePath=".\multi_polygon_buffer.cpp"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>

Modified: trunk/libs/geometry/test_extensions/algorithms/buffer/polygon_buffer.cpp
==============================================================================
--- trunk/libs/geometry/test_extensions/algorithms/buffer/polygon_buffer.cpp (original)
+++ trunk/libs/geometry/test_extensions/algorithms/buffer/polygon_buffer.cpp 2012-03-10 16:13:37 EST (Sat, 10 Mar 2012)
@@ -19,6 +19,9 @@
     = "POLYGON ((0 0,1 5,6 1,0 0))";
 static std::string const concave_simplex
     = "POLYGON ((0 0,3 5,3 3,5 3,0 0))";
+static std::string const chained_box
+ = "POLYGON((0 0,0 4,4 4,8 4,12 4,12 0,8 0,4 0,0 0))";
+
 static std::string const donut_simplex
     = "POLYGON ((0 0,1 9,8 1,0 0),(1 1,4 1,1 4,1 1))";
 static std::string const letter_L
@@ -65,12 +68,14 @@
 
     typedef bg::model::polygon<P> polygon_type;
 
- test_one<polygon_type, buf::join_miter, polygon_type>("L", letter_L, 'm', 14.0, 0.5);
- test_one<polygon_type, buf::join_round, polygon_type>("L", letter_L, 'r', 13.7314, 0.5);
- test_one<polygon_type, buf::join_miter, polygon_type>("simplex", simplex, 'm', 52.8733, 1.5);
     test_one<polygon_type, buf::join_round, polygon_type>("simplex", simplex, 'r', 47.9408, 1.5);
- test_one<polygon_type, buf::join_miter, polygon_type>("concave_simplex", concave_simplex, 'm', 16.3861, 0.5);
+ test_one<polygon_type, buf::join_miter, polygon_type>("simplex", simplex, 'm', 52.8733, 1.5);
     test_one<polygon_type, buf::join_round, polygon_type>("concave_simplex", concave_simplex, 'r', 14.5616, 0.5);
+ test_one<polygon_type, buf::join_miter, polygon_type>("concave_simplex", concave_simplex, 'm', 16.3861, 0.5);
+ test_one<polygon_type, buf::join_round, polygon_type>("chained_box", chained_box, 'r', 83.1403, 1.0);
+ test_one<polygon_type, buf::join_miter, polygon_type>("chained_box", chained_box, 'm', 84, 1.0);
+ test_one<polygon_type, buf::join_round, polygon_type>("L", letter_L, 'r', 13.7314, 0.5);
+ test_one<polygon_type, buf::join_miter, polygon_type>("L", letter_L, 'm', 14.0, 0.5);
 
     test_one<polygon_type, buf::join_miter, polygon_type>("indentation4", indentation, 'm', 25.7741, 0.4);
     test_one<polygon_type, buf::join_round, polygon_type>("indentation4", indentation, 'r', 25.5695, 0.4);

Modified: trunk/libs/geometry/test_extensions/algorithms/buffer/test_buffer.hpp
==============================================================================
--- trunk/libs/geometry/test_extensions/algorithms/buffer/test_buffer.hpp (original)
+++ trunk/libs/geometry/test_extensions/algorithms/buffer/test_buffer.hpp 2012-03-10 16:13:37 EST (Sat, 10 Mar 2012)
@@ -10,7 +10,7 @@
 #ifndef BOOST_GEOMETRY_TEST_BUFFER_HPP
 #define BOOST_GEOMETRY_TEST_BUFFER_HPP
 
-//#define BOOST_GEOMETRY_DEBUG_WITH_MAPPER
+#define BOOST_GEOMETRY_DEBUG_WITH_MAPPER
 #define TEST_WITH_SVG
 
 #include <fstream>
@@ -79,7 +79,7 @@
 void test_buffer(std::string const& caseid, Geometry const& geometry,
             char join,
             bool check, double expected_area,
- double distance_left, double distance_right)
+ double distance_left, double distance_right, int expected_self_tangencies)
 {
     namespace bg = boost::geometry;
 
@@ -89,9 +89,17 @@
 
     typedef typename bg::ring_type<GeometryOut>::type ring_type;
 
+ typedef typename bg::tag<Geometry>::type tag;
+ std::string type = boost::is_same<tag, bg::polygon_tag>::value ? "poly"
+ : boost::is_same<tag, bg::linestring_tag>::value ? "line"
+ : boost::is_same<tag, bg::multi_polygon_tag>::value ? "multipoly"
+ : boost::is_same<tag, bg::multi_linestring_tag>::value ? "multiline"
+ : ""
+ ;
+
     std::ostringstream complete;
     complete
- << (bg::geometry_id<Geometry>::value == 2 ? "line" : "poly") << "_"
+ << type << "_"
         << caseid << "_"
         << string_from_type<coordinate_type>::name()
         << "_" << join;
@@ -113,8 +121,12 @@
                 {
                         d += std::abs(distance_right);
                 }
+ else
+ {
+ distance_right = distance_left;
+ }
 
- bg::buffer(box, box, d * 1.1);
+ bg::buffer(box, box, d * (join == 'm' ? 2.0 : 1.1));
         mapper.add(box);
     }
 
@@ -167,7 +179,8 @@
         // Be sure resulting polygon does not contain
         // self-intersections
         // But indentation5 should contain 1 self-ip TODO give this check as an argument
- if (! boost::contains(complete.str(), "indentation5_d_r")
+ if (expected_self_tangencies == 0
+ && ! boost::contains(complete.str(), "indentation5_d_r")
             && ! boost::contains(complete.str(), "flower25_d_r"))
         {
             BOOST_FOREACH(GeometryOut const& polygon, buffered)
@@ -205,7 +218,7 @@
>
 void test_one(std::string const& caseid, std::string const& wkt,
         char join, double expected_area,
- double distance_left, double distance_right = -999)
+ double distance_left, double distance_right = -999, int expected_self_tangencies = 0)
 {
     namespace bg = boost::geometry;
     Geometry g;
@@ -227,48 +240,10 @@
 #endif
 
     test_buffer<GeometryOut, JoinStrategy>
- (caseid, g, join, false, expected_area, distance_left, distance_right);
+ (caseid, g, join, false, expected_area,
+ distance_left, distance_right, expected_self_tangencies);
 }
 
 
-template
-<
- typename Geometry,
- template<typename, typename> class JoinStrategy,
- typename GeometryOut
->
-void test_one(bool check, std::string const& caseid, std::string const& wkt,
- char join, double expected_area,
- double distance_left, double distance_right = -999)
-{
- namespace bg = boost::geometry;
- Geometry g;
- bg::read_wkt(wkt, g);
-
- typedef typename bg::point_type<Geometry>::type point_type;
-
- //std::cout << caseid << std::endl;
- if (join == 'm')
- {
- //return;
- }
-
-
-
-#ifdef BOOST_GEOMETRY_CHECK_WITH_POSTGIS
- std::cout
- << (counter > 0 ? "union " : "")
- << "select " << counter++
- << ", '" << caseid << "' as caseid"
- << ", ST_Area(ST_Buffer(ST_GeomFromText('" << wkt << "'), "
- << distance_left
- << ", 'endcap=flat join=" << (join == 'm' ? "miter" : "round") << "'))"
- << ", " << expected_area
- << std::endl;
-#endif
-
- test_buffer<GeometryOut, JoinStrategy>
- (caseid, g, join, check, expected_area, distance_left, distance_right);
-}
 
 #endif


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk