$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
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