Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r61019 - in sandbox/geometry/boost/geometry: algorithms algorithms/detail algorithms/detail/buffer algorithms/detail/overlay algorithms/detail/sections algorithms/overlay core extensions/io/svg multi/algorithms strategies
From: barend.gehrels_at_[hidden]
Date: 2010-04-03 09:37:36


Author: barendgehrels
Date: 2010-04-03 09:37:34 EDT (Sat, 03 Apr 2010)
New Revision: 61019
URL: http://svn.boost.org/trac/boost/changeset/61019

Log:
Many changes for / related to buffer

Added:
   sandbox/geometry/boost/geometry/algorithms/detail/buffer/intersecting_inserter.hpp (contents, props changed)
   sandbox/geometry/boost/geometry/algorithms/detail/buffer/line_line_intersection.hpp (contents, props changed)
   sandbox/geometry/boost/geometry/algorithms/detail/buffer/linestring_buffer.hpp (contents, props changed)
   sandbox/geometry/boost/geometry/algorithms/detail/buffer/polygon_buffer.hpp (contents, props changed)
   sandbox/geometry/boost/geometry/algorithms/detail/overlay/dissolver.hpp (contents, props changed)
   sandbox/geometry/boost/geometry/algorithms/detail/overlay/split_rings.hpp (contents, props changed)
   sandbox/geometry/boost/geometry/strategies/buffer_side.hpp (contents, props changed)
Text files modified:
   sandbox/geometry/boost/geometry/algorithms/buffer.hpp | 238 -------------------------------------
   sandbox/geometry/boost/geometry/algorithms/detail/disjoint.hpp | 32 ++++
   sandbox/geometry/boost/geometry/algorithms/detail/sections/sectionalize.hpp | 38 +++--
   sandbox/geometry/boost/geometry/algorithms/disjoint.hpp | 25 ---
   sandbox/geometry/boost/geometry/algorithms/dissolve.hpp | 6
   sandbox/geometry/boost/geometry/algorithms/overlay/assemble.hpp | 45 +++---
   sandbox/geometry/boost/geometry/algorithms/overlay/traverse.hpp | 23 +++
   sandbox/geometry/boost/geometry/algorithms/union.hpp | 31 ++++
   sandbox/geometry/boost/geometry/core/ring_type.hpp | 9 +
   sandbox/geometry/boost/geometry/extensions/io/svg/svg_mapper.hpp | 119 ++++++++++--------
   sandbox/geometry/boost/geometry/extensions/io/svg/write_svg.hpp | 50 +++++--
   sandbox/geometry/boost/geometry/extensions/io/svg/write_svg_multi.hpp | 8
   sandbox/geometry/boost/geometry/multi/algorithms/dissolve.hpp | 145 +++++++++++++++++++++++
   sandbox/geometry/boost/geometry/strategies/buffer.hpp | 252 +++++++++++++++++++++++----------------
   14 files changed, 534 insertions(+), 487 deletions(-)

Modified: sandbox/geometry/boost/geometry/algorithms/buffer.hpp
==============================================================================
--- sandbox/geometry/boost/geometry/algorithms/buffer.hpp (original)
+++ sandbox/geometry/boost/geometry/algorithms/buffer.hpp 2010-04-03 09:37:34 EDT (Sat, 03 Apr 2010)
@@ -72,244 +72,6 @@
 
 
 
-
-template <typename RingInput, typename RingOutput, typename JoinStrategy>
-struct ring_buffer
-{
- template <typename Point, typename Line1, typename Line2 = Line1>
- struct line_line_intersection
- {
- template <typename A, typename B, typename C, typename D>
- static inline A det(A const& a, B const& b, C const& c, D const& d)
- {
- return a * d - b * c;
- }
-
- static inline bool apply(Line1 const& line1, Line2 const& line2, Point& p)
- {
- // See http://mathworld.wolfram.com/Line-LineIntersection.html
- typedef typename coordinate_type<Point>::type coordinate_type;
- coordinate_type x1 = get<0,0>(line1), y1 = get<0,1>(line1);
- coordinate_type x2 = get<1,0>(line1), y2 = get<1,1>(line1);
- coordinate_type x3 = get<0,0>(line2), y3 = get<0,1>(line2);
- coordinate_type x4 = get<1,0>(line2), y4 = get<1,1>(line2);
-
- coordinate_type denominator = det(x1 - x2, y1 - y2, x3 - x4, y3 - y4);
-
- // If denominator is zero, segments are parallel.
- // We have context information, so know that it should then
- // be the case that line1.p2 == line2.p1, and that is the
- // intersection point.
- if (geometry::math::equals(denominator, 0.0))
- {
- set<0>(p, x2);
- set<1>(p, y2);
- return true;
- }
-
- coordinate_type d1 = det(x1, y1, x2, y2);
- coordinate_type d2 = det(x3, y3, x4, y4);
- coordinate_type px = det(d1, x1 - x2, d2, x3 - x4) / denominator;
- coordinate_type py = det(d1, y1 - y2, d2, y3 - y4) / denominator;
-
- set<0>(p, px);
- set<1>(p, py);
-
- if (abs(denominator) < 1e-7)
- {
- std::cout << "small " << denominator << std::endl;
- }
- return abs(denominator) > 1e-7;
- }
- };
-
-
-
-#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
- template <typename Mapper>
-#endif
- static inline void apply(RingInput const& ring, RingOutput& buffered,
- double distance, // TODO: change coordinate type
- JoinStrategy const& join_strategy
-#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
- , Mapper& mapper
-#endif
- )
- {
- typedef typename point_type<RingOutput>::type output_point_type;
- typedef segment<output_point_type const> segment_type;
- typedef typename boost::range_iterator
- <
- RingInput const
- >::type iterator_type;
-
- output_point_type previous_p1, previous_p2;
- output_point_type first_p1, first_p2;
- bool first = true;
-
- int index = 0;
-
- iterator_type it = boost::begin(ring);
- for (iterator_type prev = it++;
- it != boost::end(ring); ++it)
- {
- if (! detail::equals::equals_point_point(*prev, *it))
- {
- bool skip = false;
-
- // Generate a block along (int most cases to the left of) the segment
- typedef typename coordinate_type<output_point_type>::type coordinate_type;
-
- // Simulate a vector d (dx,dy)
- coordinate_type dx = get<0>(*it) - get<0>(*prev);
- coordinate_type dy = get<1>(*it) - get<1>(*prev);
-
-
- // For normalization [0,1] (=dot product d.d, sqrt)
- coordinate_type length = sqrt(dx * dx + dy * dy);
-
- // Because coordinates are not equal, length should not be zero
- BOOST_ASSERT((! geometry::math::equals(length, 0)));
-
- // Generate the normalized perpendicular p, to the left (ccw)
- coordinate_type px = -dy / length;
- coordinate_type py = dx / length;
-
- output_point_type p1, p2;
-
- coordinate_type d = distance;
-
- set<0>(p2, get<0>(*it) + px * d);
- set<1>(p2, get<1>(*it) + py * d);
-
- set<0>(p1, get<0>(*prev) + px * d);
- set<1>(p1, get<1>(*prev) + py * d);
-
- {
- RingOutput block;
- block.push_back(*prev);
- block.push_back(*it);
- block.push_back(p2);
- block.push_back(p1);
- block.push_back(*prev);
-
- #ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
- mapper.map(block, "opacity:0.4;fill:rgb(0,255,0);stroke:rgb(0,0,0);stroke-width:1");
- #endif
- }
-
- if (! first)
- {
- output_point_type p;
- segment_type s1(p1, p2);
- segment_type s2(previous_p1, previous_p2);
- if (line_line_intersection<output_point_type, segment_type>::apply(s1, s2, p))
- {
- join_strategy.apply(p, *prev, previous_p2, p1, distance, buffered);
- {
- #ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
- mapper.map(p, "fill:rgb(0,0,0);", 3);
-
- std::ostringstream out;
- out << index++;
- mapper.text(p, out.str(), "fill:rgb(0,0,0);font-family='Arial';", 5, 5);
- #endif
- }
- }
- else
- {
- skip = false;
- }
- }
- else
- {
- first = false;
- first_p1 = p1;
- first_p2 = p2;
- }
-
- if (! skip)
- {
- previous_p1 = p1;
- previous_p2 = p2;
- prev = it;
- }
- }
- }
-
- // Last one
- {
- output_point_type p;
- segment_type s1(previous_p1, previous_p2);
- segment_type s2(first_p1, first_p2);
- line_line_intersection<output_point_type, segment_type>::apply(s1, s2, p);
-
- join_strategy.apply(p, *boost::begin(ring), previous_p2, first_p1, distance, buffered);
-
-#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
- mapper.map(p, "fill:rgb(0,0,0);", 3);
- std::ostringstream out;
- out << index++;
- mapper.text(p, out.str(), "fill:rgb(0,0,0);font-family='Arial';", 5, 5);
-#endif
- }
-
- // Close the generated buffer
- {
- output_point_type p = *boost::begin(buffered);
- buffered.push_back(p);
- }
- }
-};
-
-
-
-template <typename PolygonInput, typename PolygonOutput, typename JoinStrategy>
-struct polygon_buffer
-{
-#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
- template <typename Mapper>
-#endif
- static inline void apply(PolygonInput const& polygon, PolygonOutput& buffered,
- double distance, JoinStrategy const& join_strategy
-#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
- , Mapper& mapper
-#endif
- )
- {
- boost::geometry::clear(buffered);
-
- typedef typename ring_type<PolygonInput>::type input_ring_type;
- typedef typename ring_type<PolygonOutput>::type output_ring_type;
-
- typedef ring_buffer<input_ring_type, output_ring_type, JoinStrategy> policy;
- policy::apply(exterior_ring(polygon), exterior_ring(buffered),
- distance, join_strategy
-#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
- , mapper
-#endif
- );
-
- for (typename boost::range_iterator
- <
- typename interior_type<PolygonInput>::type const
- >::type it = boost::begin(interior_rings(polygon));
- it != boost::end(interior_rings(polygon));
- ++it)
- {
- output_ring_type ring;
- policy::apply(*it, ring, distance, join_strategy
-#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
- , mapper
-#endif
- );
- interior_rings(buffered).push_back(ring);
- }
- }
-};
-
-
-
 }} // namespace detail::buffer
 #endif // DOXYGEN_NO_DETAIL
 

Added: sandbox/geometry/boost/geometry/algorithms/detail/buffer/intersecting_inserter.hpp
==============================================================================
--- (empty file)
+++ sandbox/geometry/boost/geometry/algorithms/detail/buffer/intersecting_inserter.hpp 2010-04-03 09:37:34 EDT (Sat, 03 Apr 2010)
@@ -0,0 +1,90 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+//
+// Copyright Barend Gehrels 2010, Geodan, Amsterdam, the Netherlands.
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_INTERSECTING_INSERTER_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_INTERSECTING_INSERTER_HPP
+
+#include <boost/range/functions.hpp>
+#include <boost/range/metafunctions.hpp>
+
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/ring_type.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace buffer
+{
+
+
+template
+<
+ typename Collection // usually collection of rings
+>
+struct intersecting_inserter
+{
+ typedef typename boost::range_value<Collection>::type item_type;
+ typedef typename geometry::ring_type<item_type>::type ring_type;
+ typedef typename geometry::point_type<ring_type>::type point_type;
+
+ intersecting_inserter(Collection& c)
+ : m_collection(c)
+ , m_index(0)
+ {}
+
+ inline void start_ring()
+ {
+ // clear current ring
+ m_ring.clear();
+ m_index = 0;
+ }
+
+ inline ring_type& get_ring()
+ {
+ return m_ring;
+ }
+
+
+ inline void insert(point_type const& point)
+ {
+ m_ring.push_back(point);
+ }
+
+
+ inline void close_and_insert_ring()
+ {
+ if (boost::size(m_ring) > 0)
+ {
+ // Close the ring
+ point_type p = m_ring.front();
+ insert(p);
+
+ item_type poly;
+ poly.outer() = m_ring;
+ m_collection.push_back(poly);
+ }
+ }
+
+
+private :
+ Collection& m_collection;
+ ring_type m_ring;
+ std::size_t m_index;
+};
+
+
+}} // namespace detail::buffer
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_INTERSECTING_INSERTER_HPP

Added: sandbox/geometry/boost/geometry/algorithms/detail/buffer/line_line_intersection.hpp
==============================================================================
--- (empty file)
+++ sandbox/geometry/boost/geometry/algorithms/detail/buffer/line_line_intersection.hpp 2010-04-03 09:37:34 EDT (Sat, 03 Apr 2010)
@@ -0,0 +1,81 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+//
+// Copyright Barend Gehrels 2010, Geodan, Amsterdam, the Netherlands.
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_LINE_LINE_INTERSECTION_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_LINE_LINE_INTERSECTION_HPP
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace buffer
+{
+
+
+// TODO: once convert this to proper strategy
+// It is different from current segment intersection because these are not segments but lines
+// If we have the Line concept, we can create a strategy
+template <typename Point, typename Line1, typename Line2 = Line1>
+struct line_line_intersection
+{
+ template <typename A, typename B, typename C, typename D>
+ static inline A det(A const& a, B const& b, C const& c, D const& d)
+ {
+ return a * d - b * c;
+ }
+
+ static inline bool apply(Line1 const& line1, Line2 const& line2, Point& p)
+ {
+ // See http://mathworld.wolfram.com/Line-LineIntersection.html
+ typedef typename coordinate_type<Point>::type coordinate_type;
+ coordinate_type x1 = get<0,0>(line1), y1 = get<0,1>(line1);
+ coordinate_type x2 = get<1,0>(line1), y2 = get<1,1>(line1);
+ coordinate_type x3 = get<0,0>(line2), y3 = get<0,1>(line2);
+ coordinate_type x4 = get<1,0>(line2), y4 = get<1,1>(line2);
+
+ coordinate_type denominator = det(x1 - x2, y1 - y2, x3 - x4, y3 - y4);
+
+ // If denominator is zero, segments are parallel.
+ // We have context information, so know that it should then
+ // be the case that line1.p2 == line2.p1, and that is the
+ // intersection point.
+ if (geometry::math::equals(denominator, 0.0))
+ {
+ set<0>(p, x2);
+ set<1>(p, y2);
+ return true;
+ }
+
+ coordinate_type d1 = det(x1, y1, x2, y2);
+ coordinate_type d2 = det(x3, y3, x4, y4);
+ coordinate_type px = det(d1, x1 - x2, d2, x3 - x4) / denominator;
+ coordinate_type py = det(d1, y1 - y2, d2, y3 - y4) / denominator;
+
+ set<0>(p, px);
+ set<1>(p, py);
+
+#ifdef BOOST_GEOMETRY_DEBUG_BUFFER
+ if (abs(denominator) < 1e-7)
+ {
+ std::cout << "small " << denominator << std::endl;
+ }
+#endif
+ return abs(denominator) > 1e-7;
+ }
+};
+
+
+}} // namespace detail::buffer
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_LINE_LINE_INTERSECTION_HPP

Added: sandbox/geometry/boost/geometry/algorithms/detail/buffer/linestring_buffer.hpp
==============================================================================
--- (empty file)
+++ sandbox/geometry/boost/geometry/algorithms/detail/buffer/linestring_buffer.hpp 2010-04-03 09:37:34 EDT (Sat, 03 Apr 2010)
@@ -0,0 +1,217 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+//
+// Copyright Barend Gehrels 2010, Geodan, Amsterdam, the Netherlands.
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_LINESTRING_BUFFER_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_LINESTRING_BUFFER_HPP
+
+#include <cstddef>
+
+#include <boost/numeric/conversion/cast.hpp>
+
+#include <boost/range/functions.hpp>
+#include <boost/range/metafunctions.hpp>
+
+#include <boost/geometry/core/point_type.hpp>
+
+#include <boost/geometry/strategies/buffer_side.hpp>
+#include <boost/geometry/algorithms/detail/buffer/line_line_intersection.hpp>
+#include <boost/geometry/algorithms/detail/buffer/intersecting_inserter.hpp>
+
+
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace buffer
+{
+
+
+template
+<
+ typename Linestring,
+ typename Polygon,
+ typename DistanceStrategy,
+ typename JoinStrategy
+>
+struct linestring_buffer
+{
+ typedef typename coordinate_type<Polygon>::type coordinate_type;
+ typedef typename point_type<Polygon>::type output_point_type;
+ typedef typename ring_type<Polygon>::type ring_type;
+ typedef segment<output_point_type const> segment_type;
+
+ template
+ <
+ typename Inserter,
+ typename Iterator
+#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
+ , typename Mapper
+#endif
+ >
+ static inline void iterate(Inserter& inserter,
+ Iterator begin, Iterator end,
+ buffer_side_selector side,
+ DistanceStrategy const& distance,
+ JoinStrategy const& join
+#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
+ , Mapper& mapper
+#endif
+ )
+ {
+ output_point_type previous_p1, previous_p2;
+ output_point_type first_p1, first_p2;
+
+#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
+ int index = 0;
+#endif
+
+ bool first = true;
+
+ Iterator it = begin;
+ for (Iterator prev = it++; it != end; ++it)
+ {
+ if (! detail::equals::equals_point_point(*prev, *it))
+ {
+ bool skip = false;
+
+ // Simulate a vector d (dx,dy)
+ coordinate_type dx = get<0>(*it) - get<0>(*prev);
+ coordinate_type dy = get<1>(*it) - get<1>(*prev);
+
+ // For normalization [0,1] (=dot product d.d, sqrt)
+ coordinate_type length = sqrt(dx * dx + dy * dy);
+
+ // Because coordinates are not equal, length should not be zero
+ BOOST_ASSERT((! geometry::math::equals(length, 0)));
+
+ // Generate the normalized perpendicular p, to the left (ccw)
+ coordinate_type px = -dy / length;
+ coordinate_type py = dx / length;
+
+ output_point_type p1, p2;
+
+ coordinate_type d = distance.apply(*prev, *it, side);
+
+ set<0>(p2, get<0>(*it) + px * d);
+ set<1>(p2, get<1>(*it) + py * d);
+
+ set<0>(p1, get<0>(*prev) + px * d);
+ set<1>(p1, get<1>(*prev) + py * d);
+
+ {
+#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
+ ring_type block;
+ block.push_back(*prev);
+ block.push_back(*it);
+ block.push_back(p2);
+ block.push_back(p1);
+ block.push_back(*prev);
+
+ mapper.map(block, "opacity:0.4;fill:rgb(0,255,0);stroke:rgb(0,0,0);stroke-width:1");
+#endif
+ }
+
+ if (! first)
+ {
+ output_point_type p;
+ segment_type s1(p1, p2);
+ segment_type s2(previous_p1, previous_p2);
+ if (line_line_intersection<output_point_type, segment_type>::apply(s1, s2, p))
+ {
+ join.apply(p, *prev, previous_p2, p1,
+ distance.apply(*prev, *it, side),
+ inserter.get_ring());
+ {
+#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
+ mapper.map(p, "fill:rgb(0,0,0);", 3);
+
+ std::ostringstream out;
+ out << index++;
+ mapper.text(p, out.str(), "fill:rgb(0,0,0);font-family='Arial';", 5, 5);
+#endif
+ }
+ }
+ else
+ {
+ skip = false;
+ }
+ }
+ else
+ {
+ first = false;
+ first_p1 = p1;
+ first_p2 = p2;
+
+ inserter.insert(p1);
+ }
+
+ if (! skip)
+ {
+ previous_p1 = p1;
+ previous_p2 = p2;
+ prev = it;
+ }
+ }
+ }
+
+ // Last one
+ inserter.insert(previous_p2);
+ }
+
+
+ template
+ <
+ typename Inserter
+#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
+ , typename Mapper
+#endif
+ >
+ static inline void apply(Linestring const& linestring, Inserter& inserter,
+ DistanceStrategy const& distance,
+ JoinStrategy const& join
+#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
+ , Mapper& mapper
+#endif
+ )
+ {
+ typedef typename boost::range_iterator
+ <
+ Linestring const
+ >::type iterator_type;
+
+ inserter.start_ring();
+
+ iterate(inserter, boost::begin(linestring), boost::end(linestring),
+ buffer_side_left,
+ distance, join
+#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
+ , mapper
+#endif
+ );
+
+ iterate(inserter, boost::rbegin(linestring), boost::rend(linestring),
+ buffer_side_right, distance, join
+#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
+ , mapper
+#endif
+ );
+
+ inserter.close_and_insert_ring();
+ }
+};
+
+
+}} // namespace detail::buffer
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_LINESTRING_BUFFER_HPP

Added: sandbox/geometry/boost/geometry/algorithms/detail/buffer/polygon_buffer.hpp
==============================================================================
--- (empty file)
+++ sandbox/geometry/boost/geometry/algorithms/detail/buffer/polygon_buffer.hpp 2010-04-03 09:37:34 EDT (Sat, 03 Apr 2010)
@@ -0,0 +1,232 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+//
+// Copyright Barend Gehrels 2010, Geodan, Amsterdam, the Netherlands.
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_POLYGON_BUFFER_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_POLYGON_BUFFER_HPP
+
+#include <cstddef>
+
+#include <boost/numeric/conversion/cast.hpp>
+
+#include <boost/range/functions.hpp>
+#include <boost/range/metafunctions.hpp>
+
+#include <boost/geometry/core/point_type.hpp>
+
+#include <boost/geometry/strategies/buffer_side.hpp>
+#include <boost/geometry/algorithms/detail/buffer/line_line_intersection.hpp>
+
+
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace buffer
+{
+
+
+template <typename RingInput, typename RingOutput, typename JoinStrategy>
+struct ring_buffer
+{
+
+
+#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
+ template <typename Mapper>
+#endif
+ static inline void apply(RingInput const& ring, RingOutput& buffered,
+ double distance, // TODO: change coordinate type
+ JoinStrategy const& join_strategy
+#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
+ , Mapper& mapper
+#endif
+ )
+ {
+ typedef typename point_type<RingOutput>::type output_point_type;
+ typedef segment<output_point_type const> segment_type;
+ typedef typename boost::range_iterator
+ <
+ RingInput const
+ >::type iterator_type;
+
+ output_point_type previous_p1, previous_p2;
+ output_point_type first_p1, first_p2;
+ bool first = true;
+
+#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
+ int index = 0;
+#endif
+
+ iterator_type it = boost::begin(ring);
+ for (iterator_type prev = it++;
+ it != boost::end(ring); ++it)
+ {
+ if (! detail::equals::equals_point_point(*prev, *it))
+ {
+ bool skip = false;
+
+ // Generate a block along (int most cases to the left of) the segment
+ typedef typename coordinate_type<output_point_type>::type coordinate_type;
+
+ // Simulate a vector d (dx,dy)
+ coordinate_type dx = get<0>(*it) - get<0>(*prev);
+ coordinate_type dy = get<1>(*it) - get<1>(*prev);
+
+
+ // For normalization [0,1] (=dot product d.d, sqrt)
+ coordinate_type length = sqrt(dx * dx + dy * dy);
+
+ // Because coordinates are not equal, length should not be zero
+ BOOST_ASSERT((! geometry::math::equals(length, 0)));
+
+ // Generate the normalized perpendicular p, to the left (ccw)
+ coordinate_type px = -dy / length;
+ coordinate_type py = dx / length;
+
+ output_point_type p1, p2;
+
+ coordinate_type d = distance;
+
+ set<0>(p2, get<0>(*it) + px * d);
+ set<1>(p2, get<1>(*it) + py * d);
+
+ set<0>(p1, get<0>(*prev) + px * d);
+ set<1>(p1, get<1>(*prev) + py * d);
+
+ {
+ RingOutput block;
+ block.push_back(*prev);
+ block.push_back(*it);
+ block.push_back(p2);
+ block.push_back(p1);
+ block.push_back(*prev);
+
+ #ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
+ mapper.map(block, "opacity:0.4;fill:rgb(255,128,0);stroke:rgb(0,0,0);stroke-width:1");
+ #endif
+ }
+
+ if (! first)
+ {
+ output_point_type p;
+ segment_type s1(p1, p2);
+ segment_type s2(previous_p1, previous_p2);
+ if (line_line_intersection<output_point_type, segment_type>::apply(s1, s2, p))
+ {
+ join_strategy.apply(p, *prev, previous_p2, p1, distance, buffered);
+ {
+#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
+ mapper.map(p, "fill:rgb(0,0,0);", 3);
+
+ std::ostringstream out;
+ out << index++;
+ mapper.text(p, out.str(), "fill:rgb(0,0,0);font-family='Arial';", 5, 5);
+#endif
+ }
+ }
+ else
+ {
+ skip = false;
+ }
+ }
+ else
+ {
+ first = false;
+ first_p1 = p1;
+ first_p2 = p2;
+ }
+
+ if (! skip)
+ {
+ previous_p1 = p1;
+ previous_p2 = p2;
+ prev = it;
+ }
+ }
+ }
+
+ // Last one
+ {
+ output_point_type p;
+ segment_type s1(previous_p1, previous_p2);
+ segment_type s2(first_p1, first_p2);
+ line_line_intersection<output_point_type, segment_type>::apply(s1, s2, p);
+
+ join_strategy.apply(p, *boost::begin(ring), previous_p2, first_p1, distance, buffered);
+
+#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
+ mapper.map(p, "fill:rgb(0,0,0);", 3);
+ std::ostringstream out;
+ out << index++;
+ mapper.text(p, out.str(), "fill:rgb(0,0,0);font-family='Arial';", 5, 5);
+#endif
+ }
+
+ // Close the generated buffer
+ {
+ output_point_type p = *boost::begin(buffered);
+ buffered.push_back(p);
+ }
+ }
+};
+
+
+
+template <typename PolygonInput, typename PolygonOutput, typename JoinStrategy>
+struct polygon_buffer
+{
+#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
+ template <typename Mapper>
+#endif
+ static inline void apply(PolygonInput const& polygon, PolygonOutput& buffered,
+ double distance, JoinStrategy const& join_strategy
+#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
+ , Mapper& mapper
+#endif
+ )
+ {
+ boost::geometry::clear(buffered);
+
+ typedef typename ring_type<PolygonInput>::type input_ring_type;
+ typedef typename ring_type<PolygonOutput>::type output_ring_type;
+
+ typedef ring_buffer<input_ring_type, output_ring_type, JoinStrategy> policy;
+ policy::apply(exterior_ring(polygon), exterior_ring(buffered),
+ distance, join_strategy
+#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
+ , mapper
+#endif
+ );
+
+ for (typename boost::range_iterator
+ <
+ typename interior_type<PolygonInput>::type const
+ >::type it = boost::begin(interior_rings(polygon));
+ it != boost::end(interior_rings(polygon));
+ ++it)
+ {
+ output_ring_type ring;
+ policy::apply(*it, ring, distance, join_strategy
+#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
+ , mapper
+#endif
+ );
+ interior_rings(buffered).push_back(ring);
+ }
+ }
+};
+
+
+}} // namespace detail::buffer
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_POLYGON_BUFFER_HPP

Modified: sandbox/geometry/boost/geometry/algorithms/detail/disjoint.hpp
==============================================================================
--- sandbox/geometry/boost/geometry/algorithms/detail/disjoint.hpp (original)
+++ sandbox/geometry/boost/geometry/algorithms/detail/disjoint.hpp 2010-04-03 09:37:34 EDT (Sat, 03 Apr 2010)
@@ -29,7 +29,32 @@
 
 
 #ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace disjoint {
+namespace detail { namespace disjoint
+{
+
+
+struct disjoint_interrupt_policy
+{
+ static bool const enabled = true;
+ bool has_intersections;
+
+ inline disjoint_interrupt_policy()
+ : has_intersections(false)
+ {}
+
+ template <typename Range>
+ inline bool apply(Range const& range)
+ {
+ // If there is any IP in the range, it is NOT disjoint
+ if (boost::size(range) > 0)
+ {
+ has_intersections = true;
+ return true;
+ }
+ return false;
+ }
+};
+
 
 
 template
@@ -166,14 +191,13 @@
 }
 
 
-
-
 }} // namespace detail::disjoint
 #endif // DOXYGEN_NO_DETAIL
 
 
 #ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace equals {
+namespace detail { namespace equals
+{
 
 /*!
     \brief Internal utility function to detect of points are disjoint

Added: sandbox/geometry/boost/geometry/algorithms/detail/overlay/dissolver.hpp
==============================================================================
--- (empty file)
+++ sandbox/geometry/boost/geometry/algorithms/detail/overlay/dissolver.hpp 2010-04-03 09:37:34 EDT (Sat, 03 Apr 2010)
@@ -0,0 +1,492 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+//
+// Copyright Barend Gehrels 2010, Geodan, Amsterdam, the Netherlands.
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_DISSOLVER_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_DISSOLVER_HPP
+
+
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/ring_type.hpp>
+#include <boost/geometry/core/exterior_ring.hpp>
+#include <boost/geometry/core/interior_rings.hpp>
+
+#include <boost/geometry/algorithms/disjoint.hpp>
+#include <boost/geometry/algorithms/detail/disjoint.hpp>
+
+#include <boost/geometry/algorithms/overlay/get_turns.hpp>
+#include <boost/geometry/algorithms/intersection.hpp>
+#include <boost/geometry/algorithms/union.hpp>
+#include <boost/geometry/algorithms/reverse.hpp>
+
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+
+namespace detail { namespace inserter
+{
+
+
+template<typename Tag1, typename Tag2>
+struct insert_geometry
+{};
+
+template<>
+struct insert_geometry<ring_tag, polygon_tag>
+{
+ template<typename Ring, typename Collection>
+ static inline void apply(Ring const& ring, Collection& collection)
+ {
+ collection.resize(collection.size() + 1);
+ geometry::exterior_ring(collection.back()) = ring;
+ }
+};
+
+
+
+
+template<>
+struct insert_geometry<polygon_tag, polygon_tag>
+{
+ template<typename Geometry, typename Collection>
+ static inline void apply(Geometry const& geometry, Collection& collection)
+ {
+ collection.push_back(geometry);
+ }
+};
+
+template<typename Geometry, typename Collection>
+inline void insert(Geometry const& geometry, Collection& collection)
+{
+ insert_geometry
+ <
+ typename geometry::tag<Geometry>::type,
+ typename geometry::tag
+ <
+ typename boost::range_value<Collection>::type
+ >::type
+ >::apply(geometry, collection);
+}
+
+}} // namespace detail::inserter
+
+
+
+namespace detail { namespace dissolver
+{
+
+class plusmin_policy
+{
+ template
+ <
+ typename Geometry1,
+ typename Geometry2,
+ typename OutputCollection
+ >
+ static inline bool check_negative(Geometry1 a, Geometry2 b,
+ OutputCollection& output_collection)
+ {
+ // Precondition: a = positive, b = negative
+
+ // 1: make b positive to get proper intersection
+ geometry::reverse(b);
+ {
+ // 2: Check if there is overlap
+ OutputCollection difference;
+ geometry::intersection(a, b, difference);
+ if(difference.size() <= 0)
+ {
+ return false;
+ }
+ }
+
+ // There is overlap and we want to remove it, by subtracting it from b
+
+ //negative = true;
+
+ typedef typename geometry::point_type<Geometry2>::type point_type;
+ typedef overlay::turn_info<point_type> turn_info;
+ std::deque<turn_info> turns;
+
+ // Get (and stop on) any intersection
+ detail::disjoint::disjoint_interrupt_policy policy;
+ geometry::get_turns
+ <
+ overlay::assign_null_policy
+ >(a, b, turns, policy);
+
+ if (! policy.has_intersections)
+ {
+ // There is overlap but no intersections -> b is inside a.
+ // So keep A and keep B, do not change anything
+ return false;
+ }
+
+ // There are intersections.
+ // 3: make a negative
+ geometry::reverse(a); // now negative
+
+ // This will calculate B minus A, result is then positive
+ OutputCollection difference;
+ geometry::intersection(a, b, difference);
+
+ // Add original a to output (NOT necessary! TODO avoid this)
+ {
+ geometry::reverse(a); // positive again
+ detail::inserter::insert(a, output_collection);
+ }
+
+
+ // Make negative output negative again
+ typedef typename boost::range_iterator<OutputCollection>::type iterator_type;
+ for(iterator_type it = boost::begin(difference);
+ it != boost::end(difference);
+ ++it)
+ {
+ geometry::reverse(*it);
+ detail::inserter::insert(*it, output_collection);
+ }
+ return true;
+ }
+
+
+public :
+
+ template
+ <
+ typename Geometry1,
+ typename Geometry2,
+ typename OutputCollection
+ >
+ static inline bool apply(Geometry1 const& a, Geometry2 const& b,
+ OutputCollection& output_collection)
+ {
+ typedef typename geometry::coordinate_type<Geometry2>::type coordinate_type;
+ coordinate_type area_a = geometry::area(a);
+ coordinate_type area_b = geometry::area(b);
+
+ // DEBUG
+ /*
+ int n = boost::size(output_collection);
+ typedef typename geometry::point_type<Geometry2>::type point_type;
+ std::cout << "Combine "
+ << area_a << " with " << " " << area_b
+ << " { " << geometry::wkt(geometry::make_centroid<point_type>(a))
+ << geometry::wkt(geometry::make_centroid<point_type>(b)) << " }"
+ << std::endl;
+ */
+ // END DEBUG
+
+ coordinate_type zero = coordinate_type();
+ if (area_a > zero && area_b > zero)
+ {
+ geometry::union_(a, b, output_collection);
+ return true;
+ }
+ else if (area_a > zero && area_b < zero)
+ {
+ return check_negative(a, b, output_collection);
+ }
+ else if (area_a < zero && area_b > zero)
+ {
+ return check_negative(b, a, output_collection);
+ }
+
+ // both negative (?) TODO
+ // DEBUG
+ /*
+ for (int i = n; i < boost::size(output_collection); i++)
+ {
+ typedef typename geometry::point_type<Geometry2>::type point_type;
+ std::cout << "Result "
+ << geometry::area(output_collection[i])
+ << " " << geometry::wkt(geometry::make_centroid<point_type>(output_collection[i]))
+ << std::endl;
+ }
+ */
+ // END DEBUG
+ return false;
+
+ }
+
+};
+
+
+template <typename CombinePolicy>
+struct dissolver_generic
+{
+ // Small structure to access elements by index;
+ // this avoids copying or accessing elements by address (pointer)
+ template <typename Box>
+ struct dissolve_helper
+ {
+ int source; // 0,1
+ int index;
+ bool dissolved;
+ Box box;
+ double area;
+
+ dissolve_helper()
+ {}
+
+ dissolve_helper(int i, Box b, double a, int s)
+ : source(s)
+ , index(i)
+ , dissolved(false)
+ , box(b)
+ , area(a)
+ {}
+ };
+
+
+ struct get_geometry
+ {
+ template <typename Range>
+ inline static typename boost::range_value<Range>::type const& apply(
+ Range const& range, int index)
+ {
+ return range[index];
+ }
+ };
+
+ template
+ <
+ typename Vector,
+ typename HelperVector
+ >
+ static inline void init_helper(Vector const& v, HelperVector& helper,
+ int begin_index = 0, int source = 0)
+ {
+ typedef typename boost::range_value<Vector>::type value_type;
+ typedef typename geometry::point_type<value_type>::type point_type;
+ typedef geometry::box<point_type> box_type;
+ int index = begin_index;
+ for(typename boost::range_iterator<Vector const>::type it
+ = boost::begin(v);
+ it != boost::end(v);
+ ++it, ++index)
+ {
+ box_type box = geometry::make_envelope<box_type>(*it);
+ helper.push_back(dissolve_helper<box_type>(index, box, geometry::area(*it), source));
+ }
+ }
+
+ template
+ <
+ typename Geometry1, typename Geometry2,
+ typename OutputCollection
+ >
+ static inline bool call_policy(Geometry1 const& geometry1, Geometry2 const& geometry2
+ , OutputCollection& output_collection)
+ {
+ return
+ ! geometry::disjoint(geometry1, geometry2)
+ && CombinePolicy::apply(geometry1, geometry2,
+ output_collection);
+ }
+
+
+ template
+ <
+ typename HelperVector,
+ typename InputRange,
+ typename OutputCollection
+ >
+ static inline bool process(HelperVector& helper_vector
+ , InputRange const& input_range
+ , OutputCollection& output_collection
+ )
+ {
+ typedef typename boost::range_value<OutputCollection>::type output_type;
+
+ int n = boost::size(output_collection);
+ bool changed = false;
+
+ typedef typename boost::range_iterator<HelperVector>::type iterator_type;
+ for(iterator_type it1 = boost::begin(helper_vector);
+ it1 != boost::end(helper_vector);
+ ++it1)
+ {
+ bool unioned = false;
+ for(iterator_type it2 = boost::begin(helper_vector);
+ ! unioned && it2 != it1;
+ ++it2)
+ {
+ // If they are NOT disjoint, union them
+ if (! it1->dissolved
+ && ! it2->dissolved
+ && ! geometry::disjoint(it1->box, it2->box))
+ {
+ // Runtime type check here...
+ if ((it1->source == 0 && it2->source == 0
+ && call_policy
+ (
+ get_geometry::apply(input_range, it1->index),
+ get_geometry::apply(input_range, it2->index),
+ output_collection
+ )
+ )
+ || (it1->source == 0 && it2->source == 1
+ && call_policy
+ (
+ get_geometry::apply(input_range, it1->index),
+ get_geometry::apply(output_collection, it2->index),
+ output_collection
+ )
+ )
+ || (it1->source == 1 && it2->source == 0
+ && call_policy
+ (
+ get_geometry::apply(output_collection, it1->index),
+ get_geometry::apply(input_range, it2->index),
+ output_collection
+ )
+ )
+ || (it1->source == 1 && it2->source == 1
+ && call_policy
+ (
+ get_geometry::apply(output_collection, it1->index),
+ get_geometry::apply(output_collection, it2->index),
+ output_collection
+ )
+ )
+ )
+ {
+ changed = true;
+ it1->dissolved = true;
+ it2->dissolved = true;
+ unioned = true;
+ }
+ }
+ }
+ }
+
+ // Append new records in output collection to helper class
+ init_helper(std::make_pair(boost::begin(output_collection) + n,
+ boost::end(output_collection)), helper_vector, n, 1);
+
+ return changed;
+ }
+
+
+
+ template
+ <
+ typename InputRange,
+ typename OutputCollection
+ >
+ static inline void apply(InputRange const& input_range
+ , OutputCollection& output_collection
+ )
+ {
+ typedef typename boost::range_value<OutputCollection>::type output_type;
+
+ typedef typename geometry::point_type<output_type>::type point_type;
+ typedef geometry::box<point_type> box_type;
+ typedef std::vector<dissolve_helper<box_type> > helper_vector_type;
+ helper_vector_type helper_vector;
+ init_helper(input_range, helper_vector);
+
+ std::vector<output_type> unioned_collection;
+
+ while(process(helper_vector, input_range, unioned_collection))
+ {
+ }
+
+ // Add input+output to real output
+ typedef typename boost::range_iterator<helper_vector_type>::type iterator_type;
+ for(iterator_type it = boost::begin(helper_vector);
+ it != boost::end(helper_vector);
+ ++it)
+ {
+ if (! it->dissolved)
+ {
+ switch(it->source)
+ {
+ case 0 :
+ detail::inserter::insert(
+ get_geometry::apply(input_range, it->index),
+ output_collection);
+ break;
+ case 1 :
+ detail::inserter::insert(
+ get_geometry::apply(unioned_collection, it->index),
+ output_collection);
+ break;
+ }
+ }
+ }
+ }
+};
+
+
+}} // namespace detail::dissolver
+#endif // DOXYGEN_NO_DETAIL
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+template
+<
+ typename GeometryTag1,
+ typename GeometryTag2,
+ typename Policy
+>
+struct dissolver
+{};
+
+
+template<typename Policy>
+struct dissolver<ring_tag, polygon_tag, Policy>
+ : detail::dissolver::dissolver_generic<Policy>
+{};
+
+template<typename Policy>
+struct dissolver<polygon_tag, polygon_tag, Policy>
+ : detail::dissolver::dissolver_generic<Policy>
+{};
+
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+template
+<
+ typename InputRange,
+ typename OutputCollection
+>
+inline void dissolver(InputRange const& input_range,
+ OutputCollection& output_collection)
+{
+ typedef typename boost::range_value<InputRange>::type geometry_in;
+ typedef typename boost::range_value<OutputCollection>::type geometry_out;
+ concept::check<geometry_in const>();
+ concept::check<geometry_out>();
+
+ dispatch::dissolver
+ <
+ typename tag<geometry_in>::type,
+ typename tag<geometry_out>::type,
+ detail::dissolver::plusmin_policy
+ >::apply(input_range, output_collection);
+}
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_DISSOLVER_HPP

Added: sandbox/geometry/boost/geometry/algorithms/detail/overlay/split_rings.hpp
==============================================================================
--- (empty file)
+++ sandbox/geometry/boost/geometry/algorithms/detail/overlay/split_rings.hpp 2010-04-03 09:37:34 EDT (Sat, 03 Apr 2010)
@@ -0,0 +1,432 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+//
+// Copyright Barend Gehrels 2010, Geodan, Amsterdam, the Netherlands.
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SPLIT_RINGS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SPLIT_RINGS_HPP
+
+#include <boost/geometry/algorithms/overlay/get_turns.hpp>
+
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/ring_type.hpp>
+#include <boost/geometry/core/exterior_ring.hpp>
+#include <boost/geometry/core/interior_rings.hpp>
+
+
+#include <boost/geometry/algorithms/intersects.hpp>
+
+#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+#include <boost/geometry/algorithms/detail/sections/sectionalize.hpp>
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace split_rings
+{
+
+
+template <typename Range>
+struct split_range
+{
+/*
+
+ 1 2
+ +-------------+
+ | 4 /
+ | |\ /
+ | | \/____ IP
+ | | /\
+ | |/ \
+ | 3 \
+ +-------------+
+ 0,6 5
+
+ - we want to split the range at the IP into two rings
+ - At the IP: we have segment_indices 2,4 (result of get_turns_in_sections)
+ - We want to copy and remove vertices 3,4
+ --> count=4-2
+ --> copy [3,5) -> copy(begin()+id1+1, begin()+id1+count+1)
+ --> erase: idem
+ --> insert(begin()+id1+1)
+
+ --> we use id1+1
+
+*/
+ static inline void apply(Range& range, Range& output
+ , segment_identifier const& id1
+ , segment_identifier const& id2
+ , typename geometry::point_type<Range>::type const& point
+ )
+ {
+ if (id1.ring_index == id2.ring_index
+ && id1.multi_index == id2.multi_index)
+ {
+ int mn = (std::min)(id1.segment_index, id2.segment_index);
+ mn++;
+
+ typename boost::range_iterator<Range>::type first = range.begin();
+ first += mn;
+
+ typename boost::range_iterator<Range>::type last = first;
+ last += std::abs(id2.segment_index - id1.segment_index);
+
+ // Create splitted ring
+ output.push_back(point);
+ std::copy(first, last, std::back_inserter(output));
+ output.push_back(point);
+
+ // Remove the loop from the range
+ range.erase(first, last);
+
+ // Iterator is invalid because of erasure, construct again
+ range.insert(range.begin() + mn, point);
+ }
+ }
+};
+
+
+template <typename Polygon>
+struct split_polygon
+{
+ typedef typename geometry::ring_type<Polygon>::type ring_type;
+
+ static inline void apply(Polygon& polygon, ring_type& splitted
+ , segment_identifier const& id1
+ , segment_identifier const& id2
+ , typename geometry::point_type<Polygon>::type const& point
+ )
+ {
+ if (id1.ring_index == id2.ring_index
+ && id1.multi_index == id2.multi_index)
+ {
+ ring_type& ring = id1.ring_index < 0
+ ? geometry::exterior_ring(polygon)
+ : geometry::interior_rings(polygon)[id1.ring_index];
+
+ split_range<ring_type>::apply(ring, splitted, id1, id2, point);
+ }
+ }
+};
+
+
+template <typename Tag, typename Geometry>
+struct split
+{};
+
+
+template <typename Ring>
+struct split<ring_tag, Ring> : split_range<Ring>
+{};
+
+
+template <typename Polygon>
+struct split<polygon_tag, Polygon> : split_polygon<Polygon>
+{};
+
+
+template <typename Tag, typename RingCollection, typename Geometry>
+struct insert_rings
+{};
+
+
+template <typename RingCollection, typename Ring>
+struct insert_rings<ring_tag, RingCollection, Ring>
+{
+ static inline void apply(RingCollection& ring_collection, Ring const& ring)
+ {
+#ifdef BOOST_GEOMETRY_DEBUG_SPLIT_RINGS
+std::cout << geometry::wkt(ring)
+ << " ; " << geometry::area(ring)
+ << " " << ring.size()
+ //<< " at " << geometry::wkt(first.point)
+ << std::endl;
+/*std::cout << "geometry "
+ << " " << geometry::area(geometry)
+ << std::endl;*/
+#endif
+
+ ring_collection.push_back(ring);
+ }
+};
+
+
+template <typename RingCollection, typename Polygon>
+struct insert_rings<polygon_tag, RingCollection, Polygon>
+{
+ static inline void apply(RingCollection& ring_collection, Polygon const& polygon)
+ {
+ ring_collection.push_back(exterior_ring(polygon));
+ for (typename boost::range_iterator
+ <
+ typename interior_type<Polygon>::type const
+ >::type it = boost::begin(interior_rings(polygon));
+ it != boost::end(interior_rings(polygon));
+ ++it)
+ {
+#ifdef BOOST_GEOMETRY_DEBUG_SPLIT_RINGS
+std::cout << geometry::wkt(*it)
+ << " ; " << geometry::area(*it)
+ << " " << it->size()
+ //<< " at " << geometry::wkt(first.point)
+ << std::endl;
+/*std::cout << "geometry "
+ << " " << geometry::area(geometry)
+ << std::endl;*/
+#endif
+
+ ring_collection.push_back(*it);
+ }
+ }
+};
+
+
+template <typename Range, typename RingCollection>
+class range_split_rings
+{
+ typedef typename geometry::tag<Range>::type tag;
+ typedef typename geometry::point_type<Range>::type point_type;
+
+ typedef typename geometry::ring_type<Range>::type ring_type;
+
+ // create sections in one dimension
+ typedef box<point_type> box_type;
+ typedef sections<box_type, 1> sections_type;
+ typedef typename sections_type::value_type section_type;
+
+ typedef typename boost::range_reverse_iterator<sections_type const>::type
+ section_iterator;
+
+ typedef typename boost::range_iterator
+ <
+ typename geometry::range_type<Range>::type const
+ >::type iterator_type;
+
+ typedef typename boost::range_reverse_iterator
+ <
+ typename geometry::range_type<Range>::type const
+ >::type reverse_iterator_type;
+
+ // for getting intersection points
+ typedef detail::overlay::turn_info<point_type> turn_info;
+ typedef std::vector<turn_info> turns_type;
+
+ typedef typename strategy_intersection
+ <
+ typename cs_tag<point_type>::type,
+ point_type,
+ point_type,
+ point_type
+ >::segment_intersection_strategy_type strategy;
+
+
+
+ static inline bool call(Range& range, RingCollection& ring_collection, int trial)
+ {
+ sections_type sections;
+ geometry::sectionalize(range, sections);
+
+ // One section or less, there can be no intersection points.
+ if (boost::size(sections) <= 1)
+ {
+ // assign output
+ return false;
+ }
+
+ turns_type turns;
+
+ // Outer loop iterates over segments
+ iterator_type it1 = boost::begin(range);
+
+ /*if (trial % 10 == 0)
+ {
+ std::cout << "trial " << trial << std::endl;
+ }*/
+
+ int index1 = 0;
+ for (iterator_type prev1 = it1++;
+ it1 != boost::end(range);
+ prev1 = it1++, index1++)
+ {
+ geometry::segment<point_type const> segment1(*prev1, *it1);
+ box_type segment_box = geometry::make_envelope<box_type>(segment1);
+
+ // Inner loop iterates reversely over sections
+ for (section_iterator sit = boost::rbegin(sections);
+ sit != boost::rend(sections);
+ sit++)
+ {
+ if (! detail::disjoint::disjoint_box_box(segment_box, sit->bounding_box))
+ {
+ // Calculate the reverse and not-reverse index
+ // Suppose section is [0..2] [begin_index..end_index] and range.size() = 6
+ // we want to have 1-2 and then 0-1
+ // -> rbegin=5, we want to have [rbegin+3..rbegin+5]
+ int index2 = sit->end_index - 1;
+ std::size_t count = 0;
+
+
+ // Iterate (reversely) over segments within section
+ for (iterator_type it2 = boost::begin(range) + index2 + 1;
+ count < sit->count;
+ it2--, index2--, count++)
+ {
+ iterator_type prev2 = it2 - 1;
+ // Do not check adjacent segments
+ bool skip = index2 + 1 >= index1
+ || (index2 == 0 && index1 >= int(sit->range_count) - 2);
+ if (! skip)
+ {
+ geometry::segment<point_type const> segment2(*prev2, *it2);
+
+ typename strategy::return_type result
+ = strategy::apply(segment1, segment2);
+
+ if (result.get<0>().count > 0)
+ {
+ ring_type copy = range;
+ ring_type splitted;
+
+ // Insert the intersection point.
+ // Split off the sub-ring
+ split<ring_tag, Range>::apply(range, splitted,
+ segment_identifier(-1, -1, -1, index2),
+ segment_identifier(-1, -1, -1, index1),
+ result.get<0>().intersections[0]);
+
+ ring_collection.push_back(splitted);
+
+#ifdef BOOST_GEOMETRY_DEBUG_SPLIT_RINGS
+ if (geometry::intersects(splitted))
+ {
+ std::cout << geometry::wkt(copy) << std::endl;
+ std::cout << geometry::wkt(splitted) << std::endl;
+ std::cout << "not OK " << trial << std::endl;
+ }
+
+
+if (geometry::area(splitted) > 0)
+{
+std::cout << geometry::wkt(splitted)
+ << " ; " << geometry::area(splitted)
+ << " " << splitted.size()
+ << " at " << geometry::wkt(result.get<0>().intersections[0])
+ << std::endl;
+}
+#endif
+
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+
+public :
+ // Copy by value of range is intentional, copy is modified here
+ static inline void apply(Range range, RingCollection& ring_collection)
+ {
+ int trial = 1;
+ while(call(range, ring_collection, trial++))
+ {
+ // no operation is intentional
+ }
+
+ // Add the (possibly untouched) input range
+ insert_rings<tag, RingCollection, Range>::apply(ring_collection, range);
+ }
+};
+
+
+template <typename Polygon, typename RingCollection>
+struct polygon_split_rings
+{
+ typedef range_split_rings
+ <
+ typename ring_type<Polygon>::type,
+ RingCollection
+ > per_ring;
+
+ static inline void apply(Polygon const& polygon, RingCollection& ring_collection)
+ {
+ per_ring::apply(exterior_ring(polygon), ring_collection);
+ for (typename boost::range_iterator
+ <
+ typename interior_type<Polygon>::type const
+ >::type it = boost::begin(interior_rings(polygon));
+ it != boost::end(interior_rings(polygon));
+ ++it)
+ {
+ per_ring::apply(*it, ring_collection);
+ }
+ }
+};
+
+
+}} // namespace detail::split_rings
+#endif // DOXYGEN_NO_DETAIL
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+template
+<
+ typename GeometryTag,
+ typename Geometry,
+ typename RingCollection
+>
+struct split_rings
+{};
+
+
+template<typename Polygon, typename RingCollection>
+struct split_rings<polygon_tag, Polygon, RingCollection>
+ : detail::split_rings::polygon_split_rings<Polygon, RingCollection>
+{};
+
+
+template<typename Ring, typename RingCollection>
+struct split_rings<ring_tag, Ring, RingCollection>
+ : detail::split_rings::range_split_rings<Ring, RingCollection>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+template
+<
+ typename Geometry,
+ typename RingCollection
+>
+inline void split_rings(Geometry const& geometry, RingCollection& out)
+{
+ concept::check<Geometry const>();
+ concept::check<typename boost::range_value<RingCollection>::type>();
+
+ dispatch::split_rings
+ <
+ typename tag<Geometry>::type,
+ Geometry,
+ RingCollection
+ >::apply(geometry, out);
+}
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SPLIT_RINGS_HPP

Modified: sandbox/geometry/boost/geometry/algorithms/detail/sections/sectionalize.hpp
==============================================================================
--- sandbox/geometry/boost/geometry/algorithms/detail/sections/sectionalize.hpp (original)
+++ sandbox/geometry/boost/geometry/algorithms/detail/sections/sectionalize.hpp 2010-04-03 09:37:34 EDT (Sat, 03 Apr 2010)
@@ -61,7 +61,9 @@
 {
     typedef Box box_type;
 
- int id;
+ // unique ID used in get_turns to mark section-pairs already handled.
+ int id;
+
     int directions[DimensionCount];
     int ring_index;
     int multi_index;
@@ -263,16 +265,12 @@
     typedef typename boost::range_iterator<Range const>::type iterator_type;
 
     static inline void apply(Sections& sections, section_type& section,
- std::size_t& index, int& ndi,
+ int& index, int& ndi,
                 Range const& range,
                 int ring_index = -1, int multi_index = -1)
     {
-
- std::size_t const n = boost::size(range);
- if (n <= index + 1)
+ if (boost::size(range) <= index)
         {
- // Zero points, or only one point
- // -> no section can be generated
             return;
         }
 
@@ -393,7 +391,7 @@
             return;
         }
 
- std::size_t index = 0;
+ int index = 0;
         int ndi = 0; // non duplicate index
 
         typedef typename boost::range_value<Sections>::type section_type;
@@ -492,6 +490,20 @@
     }
 };
 
+template <typename Sections>
+inline void set_section_unique_ids(Sections& sections)
+{
+ // Set ID's.
+ int index = 0;
+ for (typename boost::range_iterator<Sections>::type it = boost::begin(sections);
+ it != boost::end(sections);
+ ++it)
+ {
+ it->id = index++;
+ }
+}
+
+
 }} // namespace detail::sectionalize
 #endif // DOXYGEN_NO_DETAIL
 
@@ -601,7 +613,7 @@
 template<typename Geometry, typename Sections>
 inline void sectionalize(Geometry const& geometry, Sections& sections)
 {
- concept::check<const Geometry>();
+ concept::check<Geometry const>();
 
     // A maximum of 10 segments per section seems to give the fastest results
     static const std::size_t max_segments_per_section = 10;
@@ -616,13 +628,7 @@
 
     sections.clear();
     sectionalizer_type::apply(geometry, sections);
- int index = 0;
- for (typename boost::range_iterator<Sections>::type it = boost::begin(sections);
- it != boost::end(sections);
- ++it)
- {
- it->id = index++;
- }
+ detail::sectionalize::set_section_unique_ids(sections);
 }
 
 

Modified: sandbox/geometry/boost/geometry/algorithms/disjoint.hpp
==============================================================================
--- sandbox/geometry/boost/geometry/algorithms/disjoint.hpp (original)
+++ sandbox/geometry/boost/geometry/algorithms/disjoint.hpp 2010-04-03 09:37:34 EDT (Sat, 03 Apr 2010)
@@ -55,33 +55,10 @@
 
 
 #ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace disjoint
+namespace detail { namespace disjoint
 {
 
 
-struct disjoint_interrupt_policy
-{
- static bool const enabled = true;
- bool has_intersections;
-
- inline disjoint_interrupt_policy()
- : has_intersections(false)
- {}
-
- template <typename Range>
- inline bool apply(Range const& range)
- {
- // If there is any IP in the range, it is NOT disjoint
- if (boost::size(range) > 0)
- {
- has_intersections = true;
- return true;
- }
- return false;
- }
-};
-
-
 template <typename Geometry1, typename Geometry2>
 struct general
 {

Modified: sandbox/geometry/boost/geometry/algorithms/dissolve.hpp
==============================================================================
--- sandbox/geometry/boost/geometry/algorithms/dissolve.hpp (original)
+++ sandbox/geometry/boost/geometry/algorithms/dissolve.hpp 2010-04-03 09:37:34 EDT (Sat, 03 Apr 2010)
@@ -84,8 +84,10 @@
             traverse(geometry, geometry, detail::overlay::operation_intersection,
                             turns, rings);
 
- return detail::overlay::assemble<GeometryOut>(rings, turns,
- geometry, geometry, 1, true, out);
+ std::map<ring_identifier, int> map;
+ map_turns(map, turns);
+ return detail::overlay::assemble<GeometryOut>(rings, map,
+ geometry, geometry, 1, true, false, out);
         }
         else
         {

Modified: sandbox/geometry/boost/geometry/algorithms/overlay/assemble.hpp
==============================================================================
--- sandbox/geometry/boost/geometry/algorithms/overlay/assemble.hpp (original)
+++ sandbox/geometry/boost/geometry/algorithms/overlay/assemble.hpp 2010-04-03 09:37:34 EDT (Sat, 03 Apr 2010)
@@ -611,14 +611,14 @@
 template
 <
     typename GeometryOut,
- typename Rings, typename Turns,
+ typename Rings, typename Map,
     typename Geometry1, typename Geometry2,
     typename OutputIterator
>
-inline OutputIterator assemble(Rings const& rings, Turns& turn_points,
+inline OutputIterator assemble(Rings const& rings, Map const& map,
             Geometry1 const& geometry1,
             Geometry2 const& geometry2,
- int direction, bool dissolve,
+ int direction, bool dissolve, bool splitted,
             OutputIterator out)
 {
         typedef typename geometry::tag<Geometry1>::type tag1;
@@ -632,23 +632,22 @@
 std::cout << "assemble" << std::endl;
 #endif
 
- // Map intersection-points per ring-identifier to <count>
- std::map<ring_identifier, int> map;
- map_turns(map, turn_points);
-
         typedef std::vector
             <
                 ring_properties<point_type>
> ring_properties_container_type;
         ring_properties_container_type ring_properties_container;
 
- add_to_containment
- <
- tag1,
- Geometry1
- >::apply(ring_properties_container,
- ring_identifier(0, -1,-1), geometry1,
- map, dissolve);
+ if (! splitted)
+ {
+ add_to_containment
+ <
+ tag1,
+ Geometry1
+ >::apply(ring_properties_container,
+ ring_identifier(0, -1,-1), geometry1,
+ map, dissolve);
+ }
         if (! dissolve)
         {
             add_to_containment
@@ -775,9 +774,6 @@
         // for multi-polygon, it is also the type of the ring.
         typedef typename geometry::range_type<GeometryOut>::type ring_type;
 
- container_type turn_points;
- std::vector<ring_type> rings;
-
         // If one input is empty, output the other one for a union.
         // For an intersection, the intersection is empty.
         if (geometry::num_points(geometry1) == 0
@@ -785,12 +781,16 @@
         {
             if (Direction == 1)
             {
- return assemble<GeometryOut>(rings, turn_points,
- geometry1, geometry2, Direction, false, out);
+ std::map<ring_identifier, int> map;
+ std::vector<ring_type> rings;
+ return assemble<GeometryOut>(rings, map,
+ geometry1, geometry2, Direction, false, false, out);
             }
             return out;
         }
 
+ container_type turn_points;
+
 #ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE
 std::cout << "get turns" << std::endl;
 #endif
@@ -810,6 +810,7 @@
 #ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE
 std::cout << "traverse" << std::endl;
 #endif
+ std::vector<ring_type> rings;
         geometry::traverse(geometry1, geometry2,
                 Direction == -1
                     ? boost::geometry::detail::overlay::operation_intersection
@@ -817,8 +818,10 @@
                     ,
                 turn_points, rings);
 
- return assemble<GeometryOut>(rings, turn_points,
- geometry1, geometry2, Direction, false, out);
+ std::map<ring_identifier, int> map;
+ map_turns(map, turn_points);
+ return assemble<GeometryOut>(rings, map,
+ geometry1, geometry2, Direction, false, false, out);
     }
 };
 

Modified: sandbox/geometry/boost/geometry/algorithms/overlay/traverse.hpp
==============================================================================
--- sandbox/geometry/boost/geometry/algorithms/overlay/traverse.hpp (original)
+++ sandbox/geometry/boost/geometry/algorithms/overlay/traverse.hpp 2010-04-03 09:37:34 EDT (Sat, 03 Apr 2010)
@@ -22,6 +22,8 @@
 #include <boost/geometry/extensions/gis/io/wkt/wkt.hpp>
 #endif
 
+#include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
+
 
 #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
 
@@ -181,6 +183,7 @@
 }
 
 
+
 template
 <
     typename Rings,
@@ -198,7 +201,7 @@
             Geometry1 const& geometry1,
             Geometry2 const& geometry2
 #else
- std::string const& ,
+ std::string const& reason,
             Geometry1 const& ,
             Geometry2 const&
 #endif
@@ -216,6 +219,24 @@
     // And clear all visit info
     clear_visit_info(turns);
 
+ /***
+ int c = 0;
+ for (int i = 0; i < turns.size(); i++)
+ {
+ for (int j = 0; j < 2; j++)
+ {
+ if (turns[i].operations[j].visited.rejected())
+ {
+ c++;
+ }
+ }
+ }
+ std::cout << "BACKTRACK (" << reason << " )"
+ << " " << c << " of " << turns.size() << " rejected"
+ << std::endl;
+ ***/
+
+
 
 #ifdef BOOST_GEOMETRY_OVERLAY_REPORT_WKT
     std::cout << " BT (" << reason << " )";

Modified: sandbox/geometry/boost/geometry/algorithms/union.hpp
==============================================================================
--- sandbox/geometry/boost/geometry/algorithms/union.hpp (original)
+++ sandbox/geometry/boost/geometry/algorithms/union.hpp 2010-04-03 09:37:34 EDT (Sat, 03 Apr 2010)
@@ -188,6 +188,37 @@
 }
 
 
+template
+<
+ typename Geometry1,
+ typename Geometry2,
+ typename Collection
+>
+inline void union_(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Collection& output_collection)
+{
+ concept::check<Geometry1 const>();
+ concept::check<Geometry2 const>();
+
+ typedef typename boost::range_value<Collection>::type geometry_out;
+ concept::check<geometry_out>();
+
+ typedef strategy_intersection
+ <
+ typename cs_tag<geometry_out>::type,
+ Geometry1,
+ Geometry2,
+ typename geometry::point_type<geometry_out>::type
+ > strategy;
+
+
+ union_inserter<geometry_out>(geometry1, geometry2,
+ std::back_inserter(output_collection),
+ strategy());
+}
+
+
 }} // namespace boost::geometry
 
 

Modified: sandbox/geometry/boost/geometry/core/ring_type.hpp
==============================================================================
--- sandbox/geometry/boost/geometry/core/ring_type.hpp (original)
+++ sandbox/geometry/boost/geometry/core/ring_type.hpp 2010-04-03 09:37:34 EDT (Sat, 03 Apr 2010)
@@ -44,7 +44,6 @@
 } // namespace traits
 
 
-
 #ifndef DOXYGEN_NO_DISPATCH
 namespace core_dispatch
 {
@@ -55,6 +54,13 @@
 {};
 
 
+template <typename Ring>
+struct ring_type<ring_tag, Ring>
+{
+ typedef Ring type;
+};
+
+
 template <typename Polygon>
 struct ring_type<polygon_tag, Polygon>
 {
@@ -62,7 +68,6 @@
         <
             typename boost::remove_const<Polygon>::type
>::type type;
-
 };
 
 

Modified: sandbox/geometry/boost/geometry/extensions/io/svg/svg_mapper.hpp
==============================================================================
--- sandbox/geometry/boost/geometry/extensions/io/svg/svg_mapper.hpp (original)
+++ sandbox/geometry/boost/geometry/extensions/io/svg/svg_mapper.hpp 2010-04-03 09:37:34 EDT (Sat, 03 Apr 2010)
@@ -11,11 +11,13 @@
 #include <cstdio>
 
 #include <vector>
+
+#include <boost/scoped_ptr.hpp>
+#include <boost/noncopyable.hpp>
+
 #include <boost/algorithm/string/split.hpp>
 #include <boost/algorithm/string/classification.hpp>
 
-
-//#include <boost/geometry/geometry.hpp>
 #include <boost/geometry/algorithms/envelope.hpp>
 #include <boost/geometry/algorithms/transform.hpp>
 #include <boost/geometry/algorithms/num_points.hpp>
@@ -40,7 +42,6 @@
 {
 
 
-
 #ifndef DOXYGEN_NO_DISPATCH
 namespace dispatch
 {
@@ -59,9 +60,9 @@
                     std::string const& style, int size,
                     Point const& point, TransformStrategy const& strategy)
     {
- boost::geometry::point_xy<int> p;
- boost::geometry::transform(point, p, strategy);
- stream << boost::geometry::svg(p, style, size) << std::endl;
+ boost::geometry::point_xy<int> ipoint;
+ boost::geometry::transform(point, ipoint, strategy);
+ stream << boost::geometry::svg(ipoint, style, size) << std::endl;
     }
 };
 
@@ -73,13 +74,6 @@
                     std::string const& style, int size,
                     Box const& box, TransformStrategy const& strategy)
     {
-
- typename boost::geometry::point_type<Box>::type p1, p2;
- boost::geometry::set<0>(p1, boost::geometry::get<boost::geometry::min_corner, 0>(box));
- boost::geometry::set<1>(p1, boost::geometry::get<boost::geometry::min_corner, 1>(box));
- boost::geometry::set<0>(p2, boost::geometry::get<boost::geometry::max_corner, 0>(box));
- boost::geometry::set<1>(p2, boost::geometry::get<boost::geometry::max_corner, 1>(box));
-
         boost::geometry::box<boost::geometry::point_xy<int> > ibox;
         boost::geometry::transform(box, ibox, strategy);
 
@@ -109,6 +103,7 @@
     : svg_map_range<Ring, boost::geometry::linear_ring<boost::geometry::point_xy<int> > >
 {};
 
+
 template <typename Linestring>
 struct svg_map<boost::geometry::linestring_tag, false, Linestring>
     : svg_map_range<Linestring, boost::geometry::linestring<boost::geometry::point_xy<int> > >
@@ -129,6 +124,7 @@
     }
 };
 
+
 template <typename Tag, typename Multi>
 struct svg_map<Tag, true, Multi>
 {
@@ -137,7 +133,7 @@
                     std::string const& style, int size,
                     Multi const& multi, TransformStrategy const& strategy)
     {
- for (typename boost::range_const_iterator<Multi>::type it
+ for (typename boost::range_iterator<Multi const>::type it
             = boost::begin(multi);
             it != boost::end(multi);
             ++it)
@@ -153,12 +149,10 @@
 };
 
 
-
 } // namespace dispatch
 #endif
 
 
-
 template <typename Geometry, typename TransformStrategy>
 inline void svg_map(std::ostream& stream,
             std::string const& style, int size,
@@ -173,51 +167,55 @@
 }
 
 
-template <typename P, bool SameScale = true>
-class svg_mapper
+template <typename Point, bool SameScale = true>
+class svg_mapper : boost::noncopyable
 {
+ typedef boost::geometry::point_xy<int> map_point_type;
     typedef boost::geometry::strategy::transform::map_transformer
         <
- P,
- boost::geometry::point_xy<int>,
+ Point,
+ map_point_type,
             true,
             SameScale
> transformer_type;
 
- boost::geometry::box<P> bbox;
- transformer_type* matrix;
- std::ostream& stream;
- int width, height;
+ boost::geometry::box<Point> m_bounding_box;
+ boost::scoped_ptr<transformer_type> m_matrix;
+ std::ostream& m_stream;
+ int m_width, m_height;
 
     void init_matrix()
     {
- if (! matrix)
+ if (! m_matrix)
         {
- matrix = new transformer_type(bbox, width, height);
-
- stream << "<?xml version=\"1.0\" standalone=\"no\"?>" << std::endl;
- stream << "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"" << std::endl;
- stream << "\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">" << std::endl;
+ m_matrix.reset(new transformer_type(m_bounding_box,
+ m_width, m_height));
 
- stream << "<svg width=\"100%\" height=\"100%\" version=\"1.1\"" << std::endl;
- stream << "xmlns=\"http://www.w3.org/2000/svg\">" << std::endl;
+ m_stream << "<?xml version=\"1.0\" standalone=\"no\"?>"
+ << std::endl
+ << "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\""
+ << std::endl
+ << "\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">"
+ << std::endl
+ << "<svg width=\"100%\" height=\"100%\" version=\"1.1\""
+ << std::endl
+ << "xmlns=\"http://www.w3.org/2000/svg\">"
+ << std::endl;
         }
     }
 
 public :
     svg_mapper(std::ostream& s, int w, int h)
- : matrix(NULL)
- , stream(s)
- , width(w)
- , height(h)
+ : m_stream(s)
+ , m_width(w)
+ , m_height(h)
     {
- boost::geometry::assign_inverse(bbox);
+ boost::geometry::assign_inverse(m_bounding_box);
     }
 
     virtual ~svg_mapper()
     {
- stream << "</svg>" << std::endl;
- if (matrix) delete matrix;
+ m_stream << "</svg>" << std::endl;
     }
 
     template <typename Geometry>
@@ -225,32 +223,38 @@
     {
         if (boost::geometry::num_points(geometry) > 0)
         {
- boost::geometry::combine(bbox, boost::geometry::make_envelope<boost::geometry::box<P> >(geometry));
+ boost::geometry::combine(m_bounding_box,
+ boost::geometry::make_envelope
+ <
+ boost::geometry::box<Point>
+ >(geometry));
         }
     }
 
     template <typename Geometry>
- void map(Geometry const& geometry, std::string const& style, int size = -1)
+ void map(Geometry const& geometry, std::string const& style,
+ int size = -1)
     {
         init_matrix();
- svg_map(stream, style, size, geometry, *matrix);
+ svg_map(m_stream, style, size, geometry, *m_matrix);
     }
 
- template <typename Point>
- void text(Point const& point, std::string const& s, std::string const& style,
- int offset_x = 0, int offset_y = 0, int lineheight = 10)
+ template <typename TextPoint>
+ void text(TextPoint const& point, std::string const& s,
+ std::string const& style,
+ int offset_x = 0, int offset_y = 0, int lineheight = 10)
     {
         init_matrix();
- boost::geometry::point_xy<int> p;
- boost::geometry::transform(point, p, *matrix);
- stream
+ map_point_type map_point;
+ boost::geometry::transform(point, map_point, *m_matrix);
+ m_stream
             << "<text style=\"" << style << "\""
- << " x=\"" << boost::geometry::get<0>(p) + offset_x << "\""
- << " y=\"" << boost::geometry::get<1>(p) + offset_y << "\""
+ << " x=\"" << boost::geometry::get<0>(map_point) + offset_x << "\""
+ << " y=\"" << boost::geometry::get<1>(map_point) + offset_y << "\""
             << ">";
         if (s.find("\n") == std::string::npos)
         {
- stream << s;
+ m_stream << s;
         }
         else
         {
@@ -263,17 +267,20 @@
                 it != splitted.end();
                 ++it, offset_y += lineheight)
             {
- stream
- << "<tspan x=\"" << boost::geometry::get<0>(p) + offset_x << "\""
- << " y=\"" << boost::geometry::get<1>(p) + offset_y << "\""
+ m_stream
+ << "<tspan x=\"" << boost::geometry::get<0>(map_point) + offset_x
+ << "\""
+ << " y=\"" << boost::geometry::get<1>(map_point) + offset_y
+ << "\""
                     << ">" << *it << "</tspan>";
             }
         }
- stream << "</text>" << std::endl;
+ m_stream << "</text>" << std::endl;
     }
-
 };
 
+
 }} // namespace boost::geometry
 
+
 #endif // BOOST_GEOMETRY_IO_SVG_MAPPER_HPP

Modified: sandbox/geometry/boost/geometry/extensions/io/svg/write_svg.hpp
==============================================================================
--- sandbox/geometry/boost/geometry/extensions/io/svg/write_svg.hpp (original)
+++ sandbox/geometry/boost/geometry/extensions/io/svg/write_svg.hpp 2010-04-03 09:37:34 EDT (Sat, 03 Apr 2010)
@@ -12,6 +12,7 @@
 #include <ostream>
 #include <string>
 
+#include <boost/config.hpp>
 #include <boost/range/functions.hpp>
 #include <boost/range/metafunctions.hpp>
 
@@ -28,8 +29,10 @@
 namespace boost { namespace geometry
 {
 
+
 #ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace svg {
+namespace detail { namespace svg
+{
 
 
 template <typename Point>
@@ -39,8 +42,8 @@
     static inline void apply(std::basic_ostream<Char, Traits>& os,
                 Point const& p, std::string const& style, int size)
     {
- os << "<circle cx=\"" << p.x()
- << "\" cy=\"" << p.y()
+ os << "<circle cx=\"" << geometry::get<0>(p)
+ << "\" cy=\"" << geometry::get<1>(p)
             << "\" r=\"" << (size < 0 ? 5 : size)
             << "\" style=\"" << style << "\"/>";
     }
@@ -54,16 +57,19 @@
     static inline void apply(std::basic_ostream<Char, Traits>& os,
                 Box const& box, std::string const& style, int size)
     {
- typedef typename coordinate_type<Box>::type coord_type;
- coord_type x = geometry::get<geometry::min_corner, 0>(box);
- coord_type y = geometry::get<geometry::min_corner, 1>(box);
- coord_type width = std::abs(geometry::get<geometry::max_corner, 0>(box) - x);
- coord_type height = std::abs(geometry::get<geometry::max_corner, 1>(box) - y);
-
- os << "<rect x=\"" << static_cast<int>(x)
- << "\" y=\"" << static_cast<int>(y)
- << "\" width=\"" << static_cast<int>(width)
- << "\" height=\"" << static_cast<int>(height)
+ // Prevent invisible boxes, making them >=1, using "max"
+ BOOST_USING_STD_MAX();
+
+ typedef typename coordinate_type<Box>::type ct;
+ ct x = geometry::get<geometry::min_corner, 0>(box);
+ ct y = geometry::get<geometry::min_corner, 1>(box);
+ ct width = max BOOST_PREVENT_MACRO_SUBSTITUTION(1,
+ geometry::get<geometry::max_corner, 0>(box) - x);
+ ct height = max BOOST_PREVENT_MACRO_SUBSTITUTION (1,
+ geometry::get<geometry::max_corner, 1>(box) - y);
+
+ os << "<rect x=\"" << x << "\" y=\"" << y
+ << "\" width=\"" << width << "\" height=\"" << height
            << "\" style=\"" << style << "\"/>";
     }
 };
@@ -90,7 +96,10 @@
             it != boost::end(range);
             ++it, first = false)
         {
- os << (first ? "" : " " ) << it->x() << "," << it->y();
+ os << (first ? "" : " " )
+ << geometry::get<0>(*it)
+ << ","
+ << geometry::get<1>(*it);
         }
         os << "\" style=\"" << style << Policy::style() << "\"/>";
     }
@@ -116,7 +125,10 @@
             it != boost::end(ring);
             ++it, first = false)
         {
- os << (first ? "M" : " L") << " " << it->x() << "," << it->y();
+ os << (first ? "M" : " L") << " "
+ << geometry::get<0>(*it)
+ << ","
+ << geometry::get<1>(*it);
         }
 
         // Inner rings:
@@ -134,7 +146,10 @@
                     it != boost::end(*rit);
                     ++it, first = false)
                 {
- os << (first ? "M" : " L") << " " << it->x() << "," << it->y();
+ os << (first ? "M" : " L") << " "
+ << geometry::get<0>(*it)
+ << ","
+ << geometry::get<1>(*it);
                 }
             }
         }
@@ -165,7 +180,8 @@
 
 
 #ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch {
+namespace dispatch
+{
 
 /*!
 \brief Dispatching base struct for SVG streaming, specialized below per geometry type

Modified: sandbox/geometry/boost/geometry/extensions/io/svg/write_svg_multi.hpp
==============================================================================
--- sandbox/geometry/boost/geometry/extensions/io/svg/write_svg_multi.hpp (original)
+++ sandbox/geometry/boost/geometry/extensions/io/svg/write_svg_multi.hpp 2010-04-03 09:37:34 EDT (Sat, 03 Apr 2010)
@@ -17,7 +17,8 @@
 {
 
 #ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace svg {
+namespace detail { namespace svg
+{
 
 
 template <typename MultiGeometry, typename Policy>
@@ -46,7 +47,8 @@
 
 
 #ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch {
+namespace dispatch
+{
 
 
 template <typename MultiPolygon>
@@ -67,7 +69,7 @@
 #endif // DOXYGEN_NO_DISPATCH
 
 
-
 }} // namespace boost::geometry
 
+
 #endif // BOOST_GEOMETRY_IO_SVG_WRITE_SVG_MULTI_HPP

Modified: sandbox/geometry/boost/geometry/multi/algorithms/dissolve.hpp
==============================================================================
--- sandbox/geometry/boost/geometry/multi/algorithms/dissolve.hpp (original)
+++ sandbox/geometry/boost/geometry/multi/algorithms/dissolve.hpp 2010-04-03 09:37:34 EDT (Sat, 03 Apr 2010)
@@ -10,6 +10,8 @@
 
 
 #include <boost/geometry/multi/core/tags.hpp>
+#include <boost/geometry/multi/core/point_type.hpp>
+
 #include <boost/geometry/algorithms/dissolve.hpp>
 #include <boost/geometry/algorithms/union.hpp>
 
@@ -83,6 +85,143 @@
 };
 
 
+// Dissolve on multi_linestring tries to create larger linestrings from input,
+// or closed rings.
+
+template <typename Multi, typename MultiOut>
+struct dissolve_multi_linestring
+{
+ typedef typename point_type<Multi>::type point_type;
+ typedef typename boost::range_iterator<Multi const>::type iterator_type;
+ typedef typename boost::range_value<Multi>::type linestring_type;
+ typedef typename distance_result<point_type>::type distance_result_type;
+
+ struct mapped
+ {
+ int index;
+ bool is_from;
+ mapped(int i, bool f) : index(i), is_from(f)
+ {}
+ };
+
+ // Have a map<point, <index,start/end> > such that we can find
+ // the corresponding point on each end. Note that it uses the
+ // default "equals" for the point-type
+ typedef std::multimap
+ <
+ point_type,
+ mapped,
+ boost::geometry::less<point_type>
+ > map_type;
+
+ typedef typename map_type::const_iterator map_iterator_type;
+
+ template <typename OutputIterator>
+ static inline OutputIterator apply(Multi const& multi, OutputIterator out)
+ {
+ if (boost::size(multi) <= 0)
+ {
+ return out;
+ }
+
+ map_type map;
+
+
+ // 1: fill the map.
+ int index = 0;
+ for (iterator_type it = boost::begin(multi);
+ it != boost::end(multi);
+ ++it, ++index)
+ {
+ linestring_type const& ls = *it;
+ if (boost::size(ls) > 0)
+ {
+ map.insert(std::make_pair(*boost::begin(ls), mapped(index, true)));
+ map.insert(std::make_pair(*(boost::end(ls) - 1), mapped(index, false)));
+ }
+ }
+
+ std::map<int, bool> included;
+
+ // 2: merge (dissolve) the lines
+
+ // 2a: start with the first one (by copying)
+ int current_index = 0;
+ included[current_index] = true;
+ linestring_type current = *boost::begin(multi);
+
+ bool found = true;
+ while(found)
+ {
+ // 2b: get all candidates, ask for range
+ point_type const& p = *(boost::end(current) - 1);
+ std::pair<map_iterator_type, map_iterator_type> range
+ = map.equal_range(p);
+
+ // 2c: for all candidates get closest one
+ found = false;
+ int closest_index = -1;
+ bool closest_from = false;
+ // TODO: make utility to initalize distance result with large value
+ distance_result_type min_dist
+ = make_distance_result<distance_result_type>(100);
+ for (map_iterator_type it = range.first;
+ ! found && it != range.second;
+ ++it)
+ {
+ if (it->second.index != current_index
+ && ! included[it->second.index])
+ {
+ linestring_type const& ls = multi[it->second.index];
+ point_type const& p = it->second.is_from
+ ? *boost::begin(ls)
+ : *(boost::end(ls) - 1);
+
+ distance_result_type d = geometry::distance(it->first, p);
+ if (! found || d < min_dist)
+ {
+ closest_index = it->second.index;
+ closest_from = it->second.is_from;
+ min_dist = d;
+
+ //std::cout << "TO " << geometry::wkt(p) << std::endl;
+ }
+ found = true;
+ }
+ }
+ // 2d: if there is a closest one add it
+ if (found && closest_index >= 0)
+ {
+ current_index = closest_index;
+ included[current_index] = true;
+ linestring_type const& ls = multi[current_index];
+ if (closest_from)
+ {
+ std::copy(boost::begin(ls), boost::end(ls),
+ std::back_inserter(current));
+ }
+ else
+ {
+ std::reverse_copy(boost::begin(ls), boost::end(ls),
+ std::back_inserter(current));
+ }
+ }
+
+ if (! found && (included.size() != boost::size(multi)))
+ {
+ // Get one which is NOT found and go again
+ std::cout << "TODO" << std::endl;
+ }
+ }
+ MultiOut mo;
+ mo.push_back(current);
+ *out++ = mo;
+
+ return out;
+ }
+};
+
+
 }} // namespace detail::dissolve
 #endif
 
@@ -99,6 +238,12 @@
 {};
 
 
+template<typename Multi, typename MultiOut>
+struct dissolve<multi_linestring_tag, multi_linestring_tag, Multi, MultiOut>
+ : detail::dissolve::dissolve_multi_linestring<Multi, MultiOut>
+{};
+
+
 
 } // namespace dispatch
 #endif // DOXYGEN_NO_DISPATCH

Modified: sandbox/geometry/boost/geometry/strategies/buffer.hpp
==============================================================================
--- sandbox/geometry/boost/geometry/strategies/buffer.hpp (original)
+++ sandbox/geometry/boost/geometry/strategies/buffer.hpp 2010-04-03 09:37:34 EDT (Sat, 03 Apr 2010)
@@ -15,28 +15,30 @@
 #include <boost/geometry/strategies/tags.hpp>
 #include <boost/geometry/strategies/side.hpp>
 
+#include <boost/geometry/strategies/buffer_side.hpp>
 
 
 namespace boost { namespace geometry
 {
 
 
+
+
 namespace strategy { namespace buffer
 {
 
 
 
-
 /*
 
    A Buffer-join strategy gets 4 input points.
- On the two consecutive segments s1 and s2 (combined by vertex v):
-
- There are two points perpendicular to the segments (p1,p2),
- crossing each other in interesction point x.
+ On the two consecutive segments s1 and s2 (joining at vertex v):
 
+ The lines from parallel at s1, s2 (at buffer-distance) end/start
+ in two points perpendicular to the segments: p1 and p2.
+ These parallel lines interesct in point ip
 
- (s2)
+ (s2)
               |
               |
               ^
@@ -44,37 +46,69 @@
         (p2) |(v)
         * +----<--- (s1)
 
- x(i) *(p1)
+ x(ip) *(p1)
 
 
     So, in clockwise order:
         v : vertex point
         p1: perpendicular on left side of segment1<1> (perp1)
- i : intersection point (ip)
+ ip: intersection point
         p2: perpendicular on left side of segment2<0> (perp2)
 */
 
 
+#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
+template
+<
+ typename PointIn, typename Mapper
+>
+struct join_mapper
+{
+ Mapper const& m_mapper;
+ join_mapper(Mapper const& mapper)
+ : m_mapper(mapper)
+ {}
+
+ template <typename Ring>
+ inline void map(PointIn const& ip, PointIn const& vertex,
+ PointIn const& perp1, PointIn const& perp2) const
+ {
+ Ring corner;
+ corner.push_back(vertex);
+ corner.push_back(perp1);
+ corner.push_back(ip);
+ corner.push_back(perp2);
+ corner.push_back(vertex);
+
+ const_cast<Mapper&>(m_mapper).map(corner,
+ "opacity:0.4;fill:rgb(255,0,0);stroke:rgb(0,0,0);stroke-width:1");
+ }
+};
+#endif
+
+
+
+#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
+// Forget this, it will go
+template<typename PointIn, typename PointOut, typename Mapper>
+struct join_miter : public join_mapper<PointIn, Mapper>
+{
+ join_miter(Mapper const& mapper) : join_mapper(mapper) {}
+#else
+
+
 template
 <
     typename PointIn,
     typename PointOut
-#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
- , typename Mapper
-#endif
>
 struct join_miter
 {
+
+#endif
     typedef typename strategy_side<typename cs_tag<PointIn>::type>::type side;
     typedef typename coordinate_type<PointIn>::type coordinate_type;
 
-#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
- Mapper const& m_mapper;
-
- join_miter(Mapper const& mapper)
- : m_mapper(mapper)
- {}
-#endif
 
     template <typename Ring>
     inline void apply(PointIn const& ip, PointIn const& vertex,
@@ -84,13 +118,18 @@
     {
         int signum = buffer_distance > 0 ? 1 : buffer_distance < 0 ? -1 : 0;
 
- // If it is concave (corner to left), add helper-line
         if (side::apply(perp1, ip, perp2) == signum)
         {
+ // If it is concave (corner to left), add helper-line
+ // The helper-line IS essential for buffering holes. Without,
+ // holes might be generated, while they should NOT be there.
+ // DOES NOT WORK ALWAYS buffered.push_back(ip);
+ // We might consider to make it optional (because more efficient)
+ //buffered.push_back(ip);
             buffered.push_back(perp1);
             buffered.push_back(perp2);
- // Note, because perp1 crosses perp2 at IP, it is not necessary to
- // include also IP
+ // Because perp1 crosses perp2 at IP, it is not necessary to
+ // include IP
         }
         else
         {
@@ -110,51 +149,42 @@
                 set<0>(p, get<0>(vertex) + dx * prop);
                 set<1>(p, get<1>(vertex) + dy * prop);
 
+#ifdef BOOST_GEOMETRY_DEBUG_BUFFER
                 std::cout << length << std::endl;
+#endif
             }
 
-
             buffered.push_back(p);
- }
-
-
- // Map it
- {
- Ring corner;
- corner.push_back(vertex);
- corner.push_back(perp1);
- corner.push_back(ip);
- corner.push_back(perp2);
- corner.push_back(vertex);
 
 #ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
- const_cast<Mapper&>(m_mapper).map(corner,
- "opacity:0.4;fill:rgb(255,0,0);stroke:rgb(0,0,0);stroke-width:1");
+ map<Ring>(ip, vertex, perp1, perp2);
 #endif
         }
+
+
     }
 };
 
 
+#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
+// Forget this, it will go
+template<typename PointIn, typename PointOut, typename Mapper>
+struct join_bevel : public join_mapper<PointIn, Mapper>
+{
+ join_bevel(Mapper const& mapper) : join_mapper(mapper) {}
+#else
+
+
 template
 <
     typename PointIn,
     typename PointOut
-#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
- , typename Mapper
-#endif
>
 struct join_bevel
 {
-
-#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
- Mapper const& m_mapper;
-
- join_bevel(Mapper const& mapper)
- : m_mapper(mapper)
- {}
 #endif
 
+
     template <typename Ring>
     inline void apply(PointIn const& ip, PointIn const& vertex,
                 PointIn const& perp1, PointIn const& perp2,
@@ -164,47 +194,39 @@
         buffered.push_back(perp1);
         buffered.push_back(perp2);
 
- // Map it
- {
- Ring corner;
- corner.push_back(vertex);
- corner.push_back(perp1);
- corner.push_back(perp2);
- corner.push_back(vertex);
-
 #ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
- const_cast<Mapper&>(m_mapper).map(corner,
- "opacity:0.4;fill:rgb(255,0,0);stroke:rgb(0,0,0);stroke-width:1");
+ map<Ring>(ip, vertex, perp1, perp2);
 #endif
- }
     }
 };
 
 
+#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
+// Forget this, it will go
+template<typename PointIn, typename PointOut, typename Mapper>
+struct join_round : public join_mapper<PointIn, Mapper>
+{
+ join_round(Mapper const& mapper, int max_level = 4)
+ : join_mapper(mapper)
+ , m_max_level(max_level)
+ {}
+#else
+
+
 template
 <
     typename PointIn,
     typename PointOut
-#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
- , typename Mapper
-#endif
>
 struct join_round
 {
- int m_max_level;
-
-#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
- Mapper const& m_mapper;
-
- join_round(Mapper const& mapper, int max_level = 4)
- : m_mapper(mapper)
- , m_max_level(max_level)
- {}
-#endif
-
     inline join_round(int max_level = 4)
         : m_max_level(max_level)
     {}
+#endif
+
+ typedef typename strategy_side<typename cs_tag<PointIn>::type>::type side;
+ int m_max_level;
 
 
     template <typename Ring>
@@ -250,55 +272,79 @@
                 double buffer_distance,
                 Ring& buffered) const
     {
- // Generate 'vectors'
- double vpx = get<0>(perp1) - get<0>(vertex);
- double vpy = get<1>(perp1) - get<1>(vertex);
-
- double vix = (get<0>(ip) - get<0>(vertex));
- double viy = (get<1>(ip) - get<1>(vertex));
-
- double length_i = sqrt(vix * vix + viy * viy);
-
- double prop = buffer_distance / length_i;
-
- PointIn bp;
- set<0>(bp, get<0>(vertex) + vix * prop);
- set<1>(bp, get<1>(vertex) + viy * prop);
+ int signum = buffer_distance > 0 ? 1 : buffer_distance < 0 ? -1 : 0;
 
- if (m_max_level <= 1)
+ if (side::apply(perp1, ip, perp2) == signum)
         {
+ // If it is concave (corner to left), add helper-line
             buffered.push_back(perp1);
- if (m_max_level == 1)
- {
- buffered.push_back(bp);
- }
             buffered.push_back(perp2);
         }
         else
         {
- buffered.push_back(perp1);
- mid_points(vertex, perp1, bp, buffer_distance, buffered);
- mid_points(vertex, bp, perp2, buffer_distance, buffered);
- }
+ // Generate 'vectors'
+ double vix = (get<0>(ip) - get<0>(vertex));
+ double viy = (get<1>(ip) - get<1>(vertex));
 
+ double length_i = sqrt(vix * vix + viy * viy);
 
- // Map it
- {
- Ring corner;
- corner.push_back(vertex);
- corner.push_back(perp1);
- corner.push_back(bp);
- corner.push_back(perp2);
- corner.push_back(vertex);
+ double prop = buffer_distance / length_i;
+
+ PointIn bp;
+ set<0>(bp, get<0>(vertex) + vix * prop);
+ set<1>(bp, get<1>(vertex) + viy * prop);
+
+ if (m_max_level <= 1)
+ {
+ buffered.push_back(perp1);
+ if (m_max_level == 1)
+ {
+ buffered.push_back(bp);
+ }
+ buffered.push_back(perp2);
+ }
+ else
+ {
+ buffered.push_back(perp1);
+ mid_points(vertex, perp1, bp, buffer_distance, buffered);
+ mid_points(vertex, bp, perp2, buffer_distance, buffered);
+ }
 
 #ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
- const_cast<Mapper&>(m_mapper).map(corner,
- "opacity:0.4;fill:rgb(255,0,0);stroke:rgb(0,0,0);stroke-width:1");
+ map<Ring>(bp, vertex, perp1, perp2);
 #endif
         }
     }
 };
 
+
+
+template
+<
+ typename CoordinateType
+>
+class distance_assymetric
+{
+public :
+ distance_assymetric(CoordinateType const& left,
+ CoordinateType const& right)
+ : m_left(left)
+ , m_right(right)
+ {}
+
+ template <typename Point>
+ inline CoordinateType apply(Point const& , Point const& ,
+ buffer_side_selector side) const
+ {
+ return side == buffer_side_left ? m_left : m_right;
+ }
+
+private :
+ CoordinateType m_left;
+ CoordinateType m_right;
+};
+
+
 }} // namespace strategy::buffer
 
 

Added: sandbox/geometry/boost/geometry/strategies/buffer_side.hpp
==============================================================================
--- (empty file)
+++ sandbox/geometry/boost/geometry/strategies/buffer_side.hpp 2010-04-03 09:37:34 EDT (Sat, 03 Apr 2010)
@@ -0,0 +1,25 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+//
+// Copyright Barend Gehrels 2010, Geodan, Amsterdam, the Netherlands.
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_STRATEGIES_BUFFER_SIDE_HPP
+#define BOOST_GEOMETRY_STRATEGIES_BUFFER_SIDE_HPP
+
+
+
+namespace boost { namespace geometry
+{
+
+
+// TODO: consider if this enum can be placed in another headerfile
+// or probably there will be more enum's or constants for the buffer
+enum buffer_side_selector { buffer_side_left, buffer_side_right };
+
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_STRATEGIES_BUFFER_SIDE_HPP


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