Boost.Geometry buffer update

[SVN r77171]
This commit is contained in:
Barend Gehrels
2012-03-03 11:24:46 +00:00
parent e14580efdb
commit 4b59798db3
9 changed files with 1215 additions and 428 deletions

View File

@@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// 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
@@ -23,6 +23,10 @@
#include <boost/geometry/extensions/algorithms/buffer/buffered_piece_collection.hpp>
#include <boost/geometry/extensions/algorithms/buffer/line_line_intersection.hpp>
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
# include <boost/geometry/extensions/algorithms/buffer/buffered_piece_collection_with_mapper.hpp>
#endif
namespace boost { namespace geometry
{
@@ -90,7 +94,7 @@ struct buffer_range
Iterator begin, Iterator end,
buffer_side_selector side,
DistanceStrategy const& distance,
JoinStrategy const& join_strategy)
JoinStrategy const& join_strategy, bool close = false)
{
output_point_type previous_p1, previous_p2;
output_point_type first_p1, first_p2;
@@ -135,10 +139,10 @@ struct buffer_range
}
if (! range_out.empty())
{
collection.add_piece(*prev, range_out);
collection.add_piece(buffered_join, *prev, range_out);
range_out.clear();
}
collection.add_piece(*prev, *it, p1, p2);
collection.add_piece(buffered_segment, *prev, *it, p1, p2);
previous_p1 = p1;
previous_p2 = p2;
@@ -161,7 +165,7 @@ struct buffer_range
range_out);
if (! range_out.empty())
{
collection.add_piece(*begin, range_out);
collection.add_piece(buffered_join, *begin, range_out);
}
// Buffer is closed automatically by last closing corner (NOT FOR OPEN POLYGONS - TODO)
@@ -169,6 +173,7 @@ struct buffer_range
else if (boost::is_same<Tag, linestring_tag>::value)
{
// Assume flat-end-strategy for now
// TODO fix this (approach) for one-side buffer (1.5 - -1.0)
output_point_type rp1, rp2;
generate_side(last_ip2, last_ip1,
side == buffer_side_left
@@ -176,12 +181,14 @@ struct buffer_range
: buffer_side_left,
distance, rp2, rp1);
// For flat end:
std::vector<output_point_type> range_out;
range_out.push_back(previous_p2);
range_out.push_back(*(end - 1));
range_out.push_back(rp2);
// For flat:
collection.add_piece(last_ip2, range_out);
if (close)
{
range_out.push_back(rp2);
}
collection.add_piece(buffered_flat_end, range_out);
}
}
};
@@ -251,14 +258,14 @@ struct buffer_inserter<linestring_tag, Linestring, Polygon>
DistanceStrategy const& distance,
JoinStrategy const& join_strategy)
{
collection.add_input();
collection.start_new_ring();
iterate(collection, boost::begin(linestring), boost::end(linestring),
buffer_side_left,
distance, join_strategy);
iterate(collection, boost::rbegin(linestring), boost::rend(linestring),
buffer_side_right,
distance, join_strategy);
distance, join_strategy, true);
}
};
@@ -284,8 +291,7 @@ struct buffer_inserter<polygon_tag, PolygonInput, PolygonOutput>
typedef buffer_inserter<ring_tag, input_ring_type, output_ring_type> policy;
{
collection.add_input();
collection.start_new_ring();
policy::apply(exterior_ring(polygon), collection,
distance, join_strategy);
}
@@ -294,10 +300,7 @@ struct buffer_inserter<polygon_tag, PolygonInput, PolygonOutput>
= interior_rings(polygon);
for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
{
output_ring_type ring;
collection.add_input();
collection.start_new_ring();
policy::apply(*it, collection, distance, join_strategy);
}
@@ -327,7 +330,14 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator
#endif
)
{
detail::buffer::buffered_piece_collection<typename geometry::ring_type<GeometryOutput>::type> collection;
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
detail::buffer::buffered_piece_collection_with_mapper
#else
detail::buffer::buffered_piece_collection
#endif
<
typename geometry::ring_type<GeometryOutput>::type
> collection;
dispatch::buffer_inserter
<
@@ -336,20 +346,23 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator
GeometryOutput
>::apply(geometry_input, collection, distance_strategy, join_strategy);
collection.get_turns(geometry_input);
collection.get_turns(geometry_input, distance_strategy.factor());
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
collection.map_offsetted(mapper);
//collection.map_offsetted(mapper);
collection.map_turns(mapper);
//collection.map_opposite_locations(mapper);
#endif
collection.discard_points();
collection.discard_rings();
collection.discard_turns();
collection.enrich();
collection.traverse();
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
//collection.map<geometry::polygon_tag>(mapper);
collection.map_turns(mapper);
collection.map_traverse(mapper);
//collection.map_turns(mapper);
collection.map_pieces<geometry::polygon_tag>(mapper); //, false, true);
//collection.map_traverse(mapper);
#endif
collection.assign<GeometryOutput>(out);

View File

@@ -0,0 +1,139 @@
// 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_BUFFER_POLICIES_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_POLICIES_HPP
#include <cstddef>
#include <boost/range.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/algorithms/covered_by.hpp>
#include <boost/geometry/extensions/strategies/buffer_side.hpp>
#include <boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace buffer
{
enum intersection_location_type
{
location_ok, inside_buffer, inside_original
};
class backtrack_for_buffer
{
public :
typedef detail::overlay::backtrack_state state_type;
template <typename Operation, typename Rings, typename Turns, typename Geometry>
static inline void apply(std::size_t size_at_start,
Rings& rings, typename boost::range_value<Rings>::type& ring,
Turns& turns, Operation& operation,
std::string const& reason,
Geometry const& ,
Geometry const& ,
state_type& state
)
{
std::cout << "WARNING " << reason << std::endl;
// TODO this is a copy of dissolve, check this for buffer
state.m_good = false;
// Make bad output clean
rings.resize(size_at_start);
ring.clear();
// Reject this as a starting point
operation.visited.set_rejected();
// And clear all visit info
clear_visit_info(turns);
}
};
struct turn_assign_for_buffer
{
static bool const include_no_turn = false;
static bool const include_degenerate = false;
static bool const include_opposite = true;
template <typename Point1, typename Point2, typename Turn, typename IntersectionInfo, typename DirInfo>
static inline void apply(Turn& turn, Point1 const& p1, Point2 const& p2, IntersectionInfo const& intersection_info, DirInfo const& dir_info)
{
detail::overlay::calculate_distance_policy::apply(turn, p1, p2,
intersection_info, dir_info);
if (dir_info.opposite && intersection_info.count == 2)
{
turn.is_opposite = true;
}
}
};
// Should follow traversal-turn-concept (enrichment, visit structure)
// and adds index in piece vector to find it back
template <typename Point>
struct buffer_turn_operation : public detail::overlay::traversal_turn_operation<Point>
{
int piece_index;
inline buffer_turn_operation()
: piece_index(-1)
{}
};
// Version for buffer including type of location, is_opposite, and helper variables
template <typename Point>
struct buffer_turn_info : public detail::overlay::turn_info<Point, buffer_turn_operation<Point> >
{
bool is_opposite;
intersection_location_type location;
int count_within, count_on_helper, count_on_offsetted, count_on_corner;
int count_on_opposite, count_on_closed;
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
std::string debug_string;
#endif
inline buffer_turn_info()
: is_opposite(false)
, location(location_ok)
, count_within(0)
, count_on_helper(0)
, count_on_offsetted(0)
, count_on_corner(0)
, count_on_opposite(0)
, count_on_closed(0)
{}
};
}} // namespace detail::buffer
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_POLICIES_HPP

View File

@@ -0,0 +1,276 @@
// 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_BUFFERED_PIECE_COLLECTION_WM_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_PIECE_COLLECTION_WM_HPP
#include <boost/geometry/extensions/algorithms/buffer/buffered_piece_collection.hpp>
#include <boost/geometry/algorithms/unique.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace buffer
{
#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER
template <typename Ring>
struct buffered_piece_collection_with_mapper
: public buffered_piece_collection<Ring>
{
template <typename Mapper>
inline void map_opposite_locations(Mapper& mapper)
{
for (typename boost::range_iterator<clustered_location_type const>::type it =
boost::begin(clustered_turn_locations);
it != boost::end(clustered_turn_locations); ++it)
{
mapper.map(it->first, "fill:rgb(0,128,0);", 3);
std::ostringstream out;
out << it->second.angles.size();
for (std::set<int>::const_iterator sit = it->second.turn_indices.begin(); sit != it->second.turn_indices.end(); ++sit)
{
out << "," << *sit;
}
mapper.text(it->first, out.str(), "fill:rgb(0,128,0);font-family='Arial';font-size:8px", 6, 8);
for (unsigned int i = 0; i < it->second.angles.size(); i++)
{
geometry::model::linestring<point_type> line;
angle_info const& tp = it->second.angles[i];
point_type p1, p2;
geometry::set<0>(p1, geometry::get<0>(it->first) + cos(tp.angle) * 0.1);
geometry::set<1>(p1, geometry::get<1>(it->first) + sin(tp.angle) * 0.1);
geometry::set<0>(p2, geometry::get<0>(it->first) + cos(tp.angle) * 0.4);
geometry::set<1>(p2, geometry::get<1>(it->first) + sin(tp.angle) * 0.4);
std::ostringstream out;
//out << tp.angle << " " << int(tp.incoming);
out << (tp.incoming ? "i" : "o") << " " << i;
if (tp.incoming)
{
int offset = 7;
if (tp.debug) offset += 5;
out << " " << tp.debug_info;
line.push_back(p1);
line.push_back(p2);
mapper.map(line, "stroke:rgb(0,0,255);stroke-width:1", 1);
mapper.map(p1, "fill:rgb(0,0,0);", 2);
mapper.text(p2, out.str(), "fill:rgb(0,0,255);font-family='Arial';font-size:8px", 2, offset);
}
else
{
line.push_back(p1);
line.push_back(p2);
mapper.map(line, "stroke:rgb(255,0,0);stroke-width:1", 1);
mapper.map(p2, "fill:rgb(0,0,0);", 2);
mapper.text(p2, out.str(), "fill:rgb(0,0,255);font-family='Arial';font-size:8px", 2, -2);
}
}
}
}
template <typename Mapper>
inline void map_turns(Mapper& mapper)
{
typedef typename geometry::coordinate_type<point_type>::type coordinate_type;
std::map<std::pair<coordinate_type, coordinate_type>, int> offsets;
int index = 0;
for (typename boost::range_iterator<turn_vector_type>::type it =
boost::begin(m_turns); it != boost::end(m_turns); ++it)
{
if (! it->opposite())
{
std::pair<coordinate_type, coordinate_type> p
= std::make_pair(geometry::get<0>(it->point), geometry::get<1>(it->point));
char color = 'g';
std::string fill = "fill:rgb(0,255,0);";
switch(it->location)
{
case inside_buffer : fill = "fill:rgb(255,0,0);"; color = 'r'; break;
case inside_original : fill = "fill:rgb(0,0,255);"; color = 'b'; break;
}
std::ostringstream out;
out << it->operations[0].piece_index << "/" << it->operations[1].piece_index << std::endl;
//out << " " << m_pieces[it->operations[0].piece_index].first_seg_id.segment_index
// << "+" << m_pieces[it->operations[1].piece_index].first_seg_id.segment_index;
//out << " " << m_pieces[it->operations[0].piece_index].index
// << "," << m_pieces[it->operations[1].piece_index].index << std::endl;
//out << " " << it->operations[0].seg_id.segment_index
// << "|" << it->operations[1].seg_id.segment_index;
out << " " << method_char(it->method)
<< ":" << operation_char(it->operations[0].operation)
<< "/" << operation_char(it->operations[1].operation);
out << " " << it->count_within
<< "-" << it->count_on_helper
<< "-" << it->count_on_corner
<< "-" << it->count_on_offsetted
<< "-" << it->count_on_closed
//|| it->count_on_opposite > 0
//<< it->debug_string
;
out << color << std::endl;
out << " " << it->operations[0].seg_id.segment_index
<< "|" << it->operations[1].seg_id.segment_index;
//out << it->operations[0].enriched.travels_to_vertex_index
// << "/" << it->operations[1].enriched.travels_to_vertex_index;
offsets[p] += 10;
int offset = offsets[p];
mapper.map(it->point, fill, 6);
mapper.text(it->point, out.str(), "fill:rgb(0,0,0);font-family='Arial';font-size:9px;", 5, offset);
offsets[p] += 25;
}
}
}
template <typename Tag, typename Mapper>
inline void map_pieces(Mapper& mapper, bool pieces = true, bool indices = true)
{
for(typename piece_vector::const_iterator it = boost::begin(m_pieces);
it != boost::end(m_pieces);
++it)
{
Ring corner;
segment_identifier seg_id = it->first_seg_id;
buffered_ring<Ring> const& ring = offsetted_rings[seg_id.multi_index];
std::copy(boost::begin(ring) + seg_id.segment_index,
boost::begin(ring) + it->last_segment_index,
std::back_inserter(corner));
std::copy(boost::begin(it->helper_segments),
boost::end(it->helper_segments),
std::back_inserter(corner));
{
// Corners of onesided buffers are empty.
// Mapping this might result (for buffer_line_two_bends_right_d_r) in a
// "unknown location(0): fatal error in "test_main_caller( argc, argv )":
// class boost::numeric::positive_overflow: bad numeric conversion: positive overflow"
// This is only in release-mode of MSVC, only for the pieces (mapping of rings)
// Must be somewhere in either transform or ublas
// TODO: find out why
// Making them unique helps somehow (while it then still has the same coordinates...)
geometry::unique(corner);
}
if (pieces)
{
if (it->type == buffered_segment)
{
if(boost::is_same<Tag, ring_tag>::value || boost::is_same<Tag, polygon_tag>::value)
{
mapper.map(corner, "opacity:0.3;fill:rgb(255,128,0);stroke:rgb(0,0,0);stroke-width:1");
}
else if(boost::is_same<Tag, linestring_tag>::value)
{
mapper.map(corner, "opacity:0.3;fill:rgb(0,255,0);stroke:rgb(0,0,0);stroke-width:1");
}
}
else
{
mapper.map(corner, "opacity:0.3;fill:rgb(255,0,0);stroke:rgb(0,0,0);stroke-width:1");
}
}
if (indices)
{
// Put starting piece_index / segment_index in centroid
point_type centroid;
if (corner.size() > 3)
{
geometry::centroid(corner, centroid);
}
else
{
centroid = corner.front();
}
std::ostringstream out;
out << it->index << "/" << it->first_seg_id.segment_index << ".." << it->last_segment_index - 1;
mapper.text(centroid, out.str(), "fill:rgb(255,0,0);font-family='Arial';", 5, 5);
}
}
}
template <typename Mapper>
inline void map_offsetted_points(Mapper& mapper)
{
for(typename buffered_ring_collection<buffered_ring<Ring> >::const_iterator oit = boost::begin(offsetted_rings);
oit != boost::end(offsetted_rings);
++oit)
{
int index = 0;
for (typename boost::range_iterator<std::vector<point_type> const>::type pit = boost::begin(*oit); pit != boost::end(*oit); ++pit)
{
mapper.map(*pit, "fill:rgb(0,0,0);", 2);
std::ostringstream out;
out << index++;
mapper.text(*pit, out.str(), "fill:rgb(0,0,255);font-family='Arial';", -5, -5);
}
}
}
template <typename Mapper>
inline void map_traverse(Mapper& mapper)
{
for(typename buffered_ring_collection<Ring>::const_iterator it = boost::begin(traversed_rings);
it != boost::end(traversed_rings);
++it)
{
mapper.map(*it, "opacity:0.4;fill:none;stroke:rgb(0,255,0);stroke-width:8");
}
}
template <typename Mapper>
inline void map_offsetted(Mapper& mapper)
{
for(typename buffered_ring_collection<buffered_ring<Ring> >::const_iterator it = boost::begin(offsetted_rings);
it != boost::end(offsetted_rings);
++it)
{
if (it->discarded())
{
mapper.map(*it, "opacity:0.4;fill:none;stroke:rgb(255,0,0);stroke-width:8");
}
else
{
mapper.map(*it, "opacity:0.4;fill:none;stroke:rgb(0,0,255);stroke-width:8");
}
}
}
};
#endif
}} // namespace detail::buffer
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_PIECE_COLLECTION_WM_HPP

View File

@@ -0,0 +1,126 @@
// 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_SIDE_ON_CONVEX_RANGE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_SIDE_ON_CONVEX_RANGE_HPP
#include <boost/range.hpp>
#include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace buffer
{
template <int D>
struct collinear_point_on_segment_check
{
typedef double coordinate_type; // TODO just use one - they're all the same (for buffer)
static inline bool apply_sorted(coordinate_type const& subject, coordinate_type const& c1, coordinate_type const& c2)
{
return subject >= c1 && subject <= c2;
}
template <typename P0, typename P1, typename P2>
static inline bool apply(P0 const& subject, P1 const& p1, P2 const& p2)
{
coordinate_type const cs = geometry::get<D>(subject);
coordinate_type const c1 = geometry::get<D>(p1);
coordinate_type const c2 = geometry::get<D>(p2);
return c1 > c2
? apply_sorted(cs, c2, c1)
: apply_sorted(cs, c1, c2)
;
}
};
// Checks is subject-point is on the segment, provided that it is already determined that it was collinear
template <typename P0, typename P1, typename P2>
inline bool collinear_point_on_segment(P0 const& subject, P1 const& p1, P2 const& p2)
{
return collinear_point_on_segment_check<0>::apply(subject, p1, p2)
&& collinear_point_on_segment_check<1>::apply(subject, p1, p2);
}
template <typename SideStrategy, typename Point, typename Range>
inline int side_on_convex_range(Point const& subject, Range const& range)
{
bool has_collinear = false;
typedef typename boost::range_iterator
<
Range const
>::type iterator_type;
iterator_type it = boost::begin(range);
for (iterator_type prev = it++;
it != boost::end(range);
prev = it++)
{
int const side = SideStrategy::apply(subject, *prev, *it);
switch(side)
{
case 1 :
return 1;
case 0 :
// Check if it is really on the segment.
// If not, it is either on the left (because polygon is convex)
// or it is still on one of the other segments (if segments are collinear)
if (collinear_point_on_segment(subject, *prev, *it))
{
return 0;
}
has_collinear = true;
break;
}
}
return has_collinear ? 1 : -1;
}
template <typename SideStrategy, typename Point, typename Iterator>
static inline int side_on_convex_range(Point const& subject,
Iterator first, Iterator last,
/* by value: */ segment_identifier seg_id,
segment_identifier& on_segment_seg_id)
{
bool has_collinear = false;
Iterator it = first;
for (Iterator prev = it++; it != last; prev = it++, seg_id.segment_index++)
{
int side = SideStrategy::apply(subject, *prev, *it);
switch(side)
{
case 1 :
return 1;
case 0 :
// Check if it is REALLY on the segment.
// If not, it is either on the left (because polygon is convex)
// or it is still on one of the other segments (if segments are collinear)
if (collinear_point_on_segment(subject, *prev, *it))
{
on_segment_seg_id = seg_id;
return 0;
}
has_collinear = true;
break;
}
}
return has_collinear ? 1 : -1;
}
}} // namespace detail::buffer
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_SIDE_ON_CONVEX_RANGE_HPP

View File

@@ -270,6 +270,11 @@ public :
{
return side == buffer_side_left ? m_left : m_right;
}
inline int factor() const
{
return m_left < 0 ? -1 : 1;
}
private :
CoordinateType m_left;

View File

@@ -31,6 +31,9 @@ static std::string const two_bends = "LINESTRING(0 0,4 5,7 4,10 6)";
static std::string const overlapping = "LINESTRING(0 0,4 5,7 4,10 6, 10 2,2 2)";
static std::string const curve = "LINESTRING(2 7,3 5,5 4,7 5,8 7)";
static std::string const for_collinear = "LINESTRING(2 0,0 0,0 4,6 4,6 0,4 0)";
static std::string const for_collinear2 = "LINESTRING(2 1,2 0,0 0,0 4,6 4,6 0,4 0,4 1)";
static std::string const chained2 = "LINESTRING(0 0,1 1,2 2)";
static std::string const chained3 = "LINESTRING(0 0,1 1,2 2,3 3)";
static std::string const chained4 = "LINESTRING(0 0,1 1,2 2,3 3,4 4)";
@@ -46,32 +49,55 @@ void test_all()
typedef bg::model::linestring<P> linestring;
typedef bg::model::polygon<P> polygon;
double factor = +1.0; // does NOT yet work for negative buffer
double right = factor * 1.0;
test_one<linestring, buf::join_round, polygon>("simplex", simplex, 'r', 19.209, 1.5, 1.5);
test_one<linestring, buf::join_miter, polygon>("simplex", simplex, 'm', 19.209, 1.5, 1.5);
test_one<linestring, buf::join_round, polygon>("simplex", simplex, 'r', 19.2093727122985, 1.5, right);
test_one<linestring, buf::join_miter, polygon>("simplex", simplex, 'm', 19.2093727122985, 1.5, right);
test_one<linestring, buf::join_miter, polygon>("simplex_asym_neg", simplex, 'm', 3.202, +1.5, -1.0);
test_one<linestring, buf::join_miter, polygon>("simplex_asym_pos", simplex, 'm', 3.202, -1.5, +1.0);
test_one<linestring, buf::join_round, polygon>("straight", straight, 'r', 19.2093727122985, 1.5, right);
test_one<linestring, buf::join_miter, polygon>("straight", straight, 'm', 19.2093727122985, 1.5, right);
//test_one<linestring, buf::join_round, polygon>("straight", straight, 'r', 19.2093727122985, 1.5, 1.5);
//test_one<linestring, buf::join_miter, polygon>("straight", straight, 'm', 19.2093727122985, 1.5, 1.5);
test_one<linestring, buf::join_round, polygon>("one_bend", one_bend, 'r', 28.4879539312069, 1.5, right);
test_one<linestring, buf::join_miter, polygon>("one_bend", one_bend, 'm', 28.6962056928037, 1.5, right);
test_one<linestring, buf::join_round, polygon>("one_bend", one_bend, 'r', 28.488, 1.5, 1.5);
test_one<linestring, buf::join_miter, polygon>("one_bend", one_bend, 'm', 28.696, 1.5, 1.5);
test_one<linestring, buf::join_round, polygon>("two_bends", two_bends, 'r', 39.2220036534424, 1.5, right);
test_one<linestring, buf::join_miter, polygon>("two_bends", two_bends, 'm', 39.5128595191957, 1.5, right);
test_one<linestring, buf::join_round, polygon>("two_bends", two_bends, 'r', 39.222, 1.5, 1.5);
test_one<linestring, buf::join_miter, polygon>("two_bends", two_bends, 'm', 39.513, 1.5, 1.5);
test_one<linestring, buf::join_round, polygon>("two_bends_left", two_bends, 'r', 20.028, 1.5, 0.0);
test_one<linestring, buf::join_miter, polygon>("two_bends_left", two_bends, 'm', 20.225, 1.5, 0.0);
test_one<linestring, buf::join_round, polygon>("two_bends_right", two_bends, 'r', 19.211, 0.0, 1.5);
test_one<linestring, buf::join_miter, polygon>("two_bends_right", two_bends, 'm', 19.288, 0.0, 1.5);
test_one<linestring, buf::join_round, polygon>("overlapping", overlapping, 'r', 65.646005724872, 1.5, right);
test_one<linestring, buf::join_miter, polygon>("overlapping", overlapping, 'm', 68.1395194809293, 1.5, right);
test_one<linestring, buf::join_round, polygon>("curve", curve, 'r', 65.646005724872, 5.0, factor * 3.0);
test_one<linestring, buf::join_miter, polygon>("curve", curve, 'm', 68.1395194809293, 5.0, factor * 3.0);
// Next (and all similar cases) which a offsetted-one-sided buffer has to be fixed.
//test_one<linestring, buf::join_miter, polygon>("two_bends_neg", two_bends, 'm', 99, +1.5, -1.0);
//test_one<linestring, buf::join_miter, polygon>("two_bends_pos", two_bends, 'm', 99, -1.5, +1.0);
//test_one<linestring, buf::join_round, polygon>("two_bends_neg", two_bends, 'r', 99, +1.5, -1.0);
//test_one<linestring, buf::join_round, polygon>("two_bends_pos", two_bends, 'r', 99, -1.5, +1.0);
test_one<linestring, buf::join_round, polygon>("chained2", chained2, 'r', 65.646005724872, 2.5, factor * 1.5);
test_one<linestring, buf::join_round, polygon>("chained3", chained3, 'r', 65.646005724872, 2.5, factor * 1.5);
test_one<linestring, buf::join_round, polygon>("chained4", chained4, 'r', 65.646005724872, 2.5, factor * 1.5);
test_one<linestring, buf::join_round, polygon>("overlapping150", overlapping, 'r', 65.646, 1.5, 1.5);
test_one<linestring, buf::join_miter, polygon>("overlapping150", overlapping, 'm', 68.140, 1.5, 1.5);
// Different cases with intersection points on flat and (left/right from line itself)
test_one<linestring, buf::join_round, polygon>("overlapping_asym_150_010", overlapping, 'r', 48.308, 1.5, 0.25);
test_one<linestring, buf::join_miter, polygon>("overlapping_asym_150_010", overlapping, 'm', 50.770, 1.5, 0.25);
test_one<linestring, buf::join_round, polygon>("overlapping_asym_150_075", overlapping, 'r', 58.506, 1.5, 0.75);
test_one<linestring, buf::join_miter, polygon>("overlapping_asym_150_075", overlapping, 'm', 60.985, 1.5, 0.75);
test_one<linestring, buf::join_round, polygon>("overlapping_asym_150_100", overlapping, 'r', 62.514, 1.5, 1.0);
test_one<linestring, buf::join_miter, polygon>("overlapping_asym_150_100", overlapping, 'm', 64.984, 1.5, 1.0);
test_one<linestring, buf::join_round, polygon>("reallife1", reallife1, 'r', 65.646005724872, 16.5, factor * 6.5);
test_one<linestring, buf::join_round, polygon>("for_collinear", for_collinear, 'r', 68.561, 2.0, 2.0);
test_one<linestring, buf::join_miter, polygon>("for_collinear", for_collinear, 'm', 72, 2.0, 2.0);
test_one<linestring, buf::join_round, polygon>("for_collinear2", for_collinear2, 'r', 74.387, 2.0, 2.0);
test_one<linestring, buf::join_miter, polygon>("for_collinear2", for_collinear2, 'm', 78.0, 2.0, 2.0);
//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>("reallife1", reallife1, 'r', 99, 16.5, 6.5);
}
@@ -86,6 +112,5 @@ 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;
}

View File

@@ -25,6 +25,17 @@ static std::string const letter_L
= "POLYGON ((0 0,0 4,1 4,1 1,3 1,3 0,0 0))";
static std::string const indentation
= "POLYGON ((0 0,0 5,4 5,4 4,3 3,2 4,2 1,3 2,4 1,4 0,0 0))";
static std::string const funnelgate
= "POLYGON((0 0,0 7,7 7,7 0,5 0,5 1,6 6,1 6,2 1,2 0,0 0))";
static std::string const gammagate
= "POLYGON((0 0,0 6,9 6,9 0,4 0,4 2,7 2,7 4,2 4,2 0,0 0))";
static std::string const fork_a
= "POLYGON((0 0,0 6,9 6,9 0,4 0,4 2,7 2,7 4,6 4,6 5,5 5,5 4,4 4,4 5,3 5,3 4,2 4,2 0,0 0))";
static std::string const fork_b
= "POLYGON((0 0,0 8,14 8,14 0,4 0,4 2,13 2,13 4,12 4,12 7,9 7,9 4,7 4,7 7,4 7,4 4,2 4,2 0,0 0))";
static std::string const fork_c
= "POLYGON((0 0,0 9,12 9,12 0,4 0,4 4,6 4,6 2,8 2,8 4,10 4,10 7,6 7,6 6,2 6,2 0,0 0))";
static std::string const arrow
= "POLYGON ((1 0,1 5,0.5 4.5,2 10,3.5 4.5,3 5,3 0,1 0))";
static std::string const tipped_aitch
@@ -54,8 +65,6 @@ void test_all()
typedef bg::model::polygon<P> polygon_type;
test_one<polygon_type, buf::join_round, polygon_type>("saw", saw, 'r', -1, 1.0);
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);
@@ -80,11 +89,12 @@ test_one<polygon_type, buf::join_round, polygon_type>("saw", saw, 'r', -1, 1.0);
test_one<polygon_type, buf::join_miter, polygon_type>("indentation12", indentation, 'm', 46.3541, 1.2);
test_one<polygon_type, buf::join_round, polygon_type>("indentation12", indentation, 'r', 45.0537, 1.2);
test_one<polygon_type, buf::join_miter, polygon_type>("indentation4_neg", indentation, 'm', 6.99098413022335, -0.4);
// TODO: fix, the buffered pieces are currently counterclockwise, that should be reversed
//test_one<polygon_type, buf::join_miter, polygon_type>("indentation4_neg", indentation, 'm', 6.99098413022335, -0.4);
//test_one<polygon_type, buf::join_round, polygon_type>("indentation4_neg", indentation, 'r', 7.25523322189147, -0.4);
test_one<polygon_type, buf::join_miter, polygon_type>("indentation8_neg", indentation, 'm', 1.36941992048731, -0.8);
//test_one<polygon_type, buf::join_miter, polygon_type>("indentation8_neg", indentation, 'm', 1.36941992048731, -0.8);
//test_one<polygon_type, buf::join_round, polygon_type>("indentation8_neg", indentation, 'r', 1.37375487490664, -0.8);
test_one<polygon_type, buf::join_miter, polygon_type>("indentation12_neg", indentation, 'm', 0, -1.2);
//test_one<polygon_type, buf::join_miter, polygon_type>("indentation12_neg", indentation, 'm', 0, -1.2);
//test_one<polygon_type, buf::join_round, polygon_type>("indentation12_neg", indentation, 'r', 0, -1.2);
test_one<polygon_type, buf::join_miter, polygon_type>("donut_simplex6", donut_simplex, 'm', 53.648, 0.6);
@@ -121,11 +131,19 @@ test_one<polygon_type, buf::join_round, polygon_type>("saw", saw, 'r', -1, 1.0);
test_one<polygon_type, buf::join_miter, polygon_type>("snake6", snake, 'm', 75.44, 0.6);
test_one<polygon_type, buf::join_miter, polygon_type>("snake16", snake, 'm', 114.24, 1.6);
test_one<polygon_type, buf::join_miter, polygon_type>("funnelgate2", funnelgate, 'm', 120.982, 2);
test_one<polygon_type, buf::join_miter, polygon_type>("funnelgate3", funnelgate, 'm', 13*13, 3);
test_one<polygon_type, buf::join_miter, polygon_type>("funnelgate4", funnelgate, 'm', 15*15, 4);
test_one<polygon_type, buf::join_miter, polygon_type>("gammagate1", gammagate, 'm', 88, 1);
test_one<polygon_type, buf::join_miter, polygon_type>("fork_a1", fork_a, 'm', 88, 1);
test_one<polygon_type, buf::join_miter, polygon_type>("fork_b1", fork_b, 'm', 154, 1);
test_one<polygon_type, buf::join_miter, polygon_type>("fork_c1", fork_c, 'm', 152, 1);
test_one<polygon_type, buf::join_miter, polygon_type>("gammagate2", gammagate, 'm', 130, 2);
test_one<polygon_type, buf::join_miter, polygon_type>("flower1", flower, 'm', 67.614, 0.1);
test_one<polygon_type, buf::join_miter, polygon_type>("flower20", flower, 'm', 74.894, 0.20);
test_one<polygon_type, buf::join_miter, polygon_type>("flower25", flower, 'm', 78.226, 0.25);
// TODO: fix the flowers-with-miter
goto skip_flower_miter;
test_one<polygon_type, buf::join_miter, polygon_type>("flower30", flower, 'm', 81.492494146177947, 0.30);
test_one<polygon_type, buf::join_miter, polygon_type>("flower35", flower, 'm', 84.694183819917185, 0.35);
test_one<polygon_type, buf::join_miter, polygon_type>("flower40", flower, 'm', 87.8306529577, 0.40);
@@ -134,7 +152,6 @@ goto skip_flower_miter;
test_one<polygon_type, buf::join_miter, polygon_type>("flower55", flower, 'm', 96.848737155342079, 0.55);
test_one<polygon_type, buf::join_miter, polygon_type>("flower60", flower, 'm', 99.724324149315279, 0.60);
skip_flower_miter:
test_one<polygon_type, buf::join_round, polygon_type>("flower10", flower, 'r', 67.486, 0.10);
test_one<polygon_type, buf::join_round, polygon_type>("flower20", flower, 'r', 74.702, 0.20);
test_one<polygon_type, buf::join_round, polygon_type>("flower25", flower, 'r', 78.071, 0.25);

View File

@@ -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>
@@ -96,7 +96,7 @@ void test_buffer(std::string const& caseid, Geometry const& geometry,
<< string_from_type<coordinate_type>::name()
<< "_" << join;
//std::cout << complete.str() << std::endl;
std::cout << complete.str() << std::endl;
std::ostringstream filename;
filename << "buffer_" << complete.str() << ".svg";
@@ -108,13 +108,13 @@ void test_buffer(std::string const& caseid, Geometry const& geometry,
{
bg::model::box<point_type> box;
bg::envelope(geometry, box);
double d = distance_left;
if (distance_right > 0)
{
d += distance_right;
}
double d = std::abs(distance_left);
if (distance_right > -998)
{
d += std::abs(distance_right);
}
bg::buffer(box, box, std::abs(d) * 1.1);
bg::buffer(box, box, d * 1.1);
mapper.add(box);
}
@@ -127,7 +127,7 @@ void test_buffer(std::string const& caseid, Geometry const& geometry,
join_strategy_type join_strategy;
typedef bg::strategy::buffer::distance_assymetric<coordinate_type> distance_strategy_type;
distance_strategy_type distance_strategy(distance_left, distance_left / 2.0); // TODO: distance_right
distance_strategy_type distance_strategy(distance_left, distance_right);
std::vector<GeometryOut> buffered;
@@ -154,7 +154,7 @@ void test_buffer(std::string const& caseid, Geometry const& geometry,
//}
if (distance_left > 0 && expected_area > -0.1)
if (expected_area > -0.1)
{
BOOST_CHECK_MESSAGE
(
@@ -181,14 +181,13 @@ void test_buffer(std::string const& caseid, Geometry const& geometry,
}
}
// Map input geometry in green
mapper.map(geometry, "opacity:0.5;fill:rgb(0,128,0);stroke:rgb(0,128,0);stroke-width:1");
mapper.map(geometry, "opacity:0.5;fill:rgb(0,128,0);stroke:rgb(0,128,0);stroke-width:10");
BOOST_FOREACH(GeometryOut const& polygon, buffered)
{
mapper.map(polygon, "opacity:0.4;fill:rgb(255,255,128);stroke:rgb(0,0,0);stroke-width:3");
//mapper.map(polygon, "opacity:0.2;fill:none;stroke:rgb(255,0,0);stroke-width:3");
post_map(polygon, mapper);
}
}