summaryrefslogtreecommitdiff
path: root/libs/geometry/test/algorithms/buffer/test_buffer.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/geometry/test/algorithms/buffer/test_buffer.hpp')
-rw-r--r--libs/geometry/test/algorithms/buffer/test_buffer.hpp319
1 files changed, 237 insertions, 82 deletions
diff --git a/libs/geometry/test/algorithms/buffer/test_buffer.hpp b/libs/geometry/test/algorithms/buffer/test_buffer.hpp
index 248519c58..6b0d91105 100644
--- a/libs/geometry/test/algorithms/buffer/test_buffer.hpp
+++ b/libs/geometry/test/algorithms/buffer/test_buffer.hpp
@@ -16,8 +16,19 @@
#if defined(TEST_WITH_SVG)
#define BOOST_GEOMETRY_BUFFER_USE_HELPER_POINTS
+
+// Uncomment next lines if you want to have a zoomed view
+// #define BOOST_GEOMETRY_BUFFER_TEST_SVG_USE_ALTERNATE_BOX
+
+// If possible define box before including this unit with the right view
+#ifdef BOOST_GEOMETRY_BUFFER_TEST_SVG_USE_ALTERNATE_BOX
+# ifndef BOOST_GEOMETRY_BUFFER_TEST_SVG_ALTERNATE_BOX
+# define BOOST_GEOMETRY_BUFFER_TEST_SVG_ALTERNATE_BOX "BOX(0 0,100 100)"
+# endif
#endif
+#endif // TEST_WITH_SVG
+
#include <boost/foreach.hpp>
#include <geometry_test_common.hpp>
@@ -26,31 +37,45 @@
#include <boost/geometry/algorithms/area.hpp>
#include <boost/geometry/algorithms/buffer.hpp>
#include <boost/geometry/algorithms/correct.hpp>
+#include <boost/geometry/algorithms/disjoint.hpp>
+#include <boost/geometry/algorithms/intersects.hpp>
+#include <boost/geometry/algorithms/is_valid.hpp>
#include <boost/geometry/algorithms/union.hpp>
#include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp>
#include <boost/geometry/geometries/geometries.hpp>
#include <boost/geometry/strategies/strategies.hpp>
-#include <boost/geometry/algorithms/disjoint.hpp>
-#include <boost/geometry/algorithms/intersects.hpp>
-#include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp>
-
-#include <boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp>
-
#include <boost/geometry/strategies/buffer.hpp>
-
-
#include <boost/geometry/io/wkt/wkt.hpp>
+#include <boost/geometry/util/condition.hpp>
+
#if defined(TEST_WITH_SVG)
#include <boost/geometry/io/svg/svg_mapper.hpp>
+
+inline char piece_type_char(bg::strategy::buffer::piece_type const& type)
+{
+ using namespace bg::strategy::buffer;
+ switch(type)
+ {
+ case buffered_segment : return 's';
+ case buffered_join : return 'j';
+ case buffered_round_end : return 'r';
+ case buffered_flat_end : return 'f';
+ case buffered_point : return 'p';
+ case buffered_concave : return 'c';
+ default : return '?';
+ }
+}
+
template <typename Geometry, typename Mapper, typename RescalePolicy>
void post_map(Geometry const& geometry, Mapper& mapper, RescalePolicy const& rescale_policy)
{
@@ -75,9 +100,13 @@ void post_map(Geometry const& geometry, Mapper& mapper, RescalePolicy const& res
}
}
-template <typename SvgMapper, typename Tag>
+template <typename SvgMapper, typename Box, typename Tag>
struct svg_visitor
{
+#ifdef BOOST_GEOMETRY_BUFFER_TEST_SVG_USE_ALTERNATE_BOX
+ Box m_alternate_box;
+#endif
+
class si
{
private :
@@ -118,6 +147,13 @@ struct svg_visitor
for (typename boost::range_iterator<Turns const>::type it =
boost::begin(turns); it != boost::end(turns); ++it)
{
+#ifdef BOOST_GEOMETRY_BUFFER_TEST_SVG_USE_ALTERNATE_BOX
+ if (bg::disjoint(it->point, m_alternate_box))
+ {
+ continue;
+ }
+#endif
+
bool is_good = true;
char color = 'g';
std::string fill = "fill:rgb(0,255,0);";
@@ -128,7 +164,7 @@ struct svg_visitor
color = 'r';
is_good = false;
break;
- case bgdb::inside_original :
+ case bgdb::location_discard :
fill = "fill:rgb(0,0,255);";
color = 'b';
is_good = false;
@@ -226,6 +262,12 @@ struct svg_visitor
{
continue;
}
+#ifdef BOOST_GEOMETRY_BUFFER_TEST_SVG_USE_ALTERNATE_BOX
+ if (bg::disjoint(corner, m_alternate_box))
+ {
+ continue;
+ }
+#endif
if (do_pieces)
{
@@ -242,13 +284,15 @@ struct svg_visitor
typedef typename bg::point_type<ring_type>::type point_type;
std::ostringstream out;
- out << piece.index << "/" << int(piece.type) << "/" << piece.first_seg_id.segment_index << ".." << piece.last_segment_index - 1;
- point_type label_point = corner.front();
- int const mid_offset = piece.offsetted_count / 2 - 1;
- if (mid_offset >= 0 && mid_offset + 1 < corner.size())
+ out << piece.index << " (" << piece_type_char(piece.type) << ") " << piece.first_seg_id.segment_index << ".." << piece.last_segment_index - 1;
+ point_type label_point = bg::return_centroid<point_type>(corner);
+
+ if ((piece.type == bg::strategy::buffer::buffered_concave
+ || piece.type == bg::strategy::buffer::buffered_flat_end)
+ && corner.size() >= 2u)
{
- bg::set<0>(label_point, (bg::get<0>(corner[mid_offset]) + bg::get<0>(corner[mid_offset + 1])) / 2.0);
- bg::set<1>(label_point, (bg::get<1>(corner[mid_offset]) + bg::get<1>(corner[mid_offset + 1])) / 2.0);
+ bg::set<0>(label_point, (bg::get<0>(corner[0]) + bg::get<0>(corner[1])) / 2.0);
+ bg::set<1>(label_point, (bg::get<1>(corner[0]) + bg::get<1>(corner[1])) / 2.0);
}
m_mapper.text(label_point, out.str(), "fill:rgb(255,0,0);font-family='Arial';font-size:10px;", 5, 5);
}
@@ -285,16 +329,21 @@ struct svg_visitor
template <typename PieceCollection>
inline void apply(PieceCollection const& collection, int phase)
{
+ // Comment next return if you want to see pieces, turns, etc.
+ return;
+
if(phase == 0)
{
map_pieces(collection.m_pieces, collection.offsetted_rings, true, true);
map_turns(collection.m_turns, true, false);
}
+#if !defined(BOOST_GEOMETRY_BUFFER_TEST_SVG_USE_ALTERNATE_BOX)
if (phase == 1)
{
// map_traversed_rings(collection.traversed_rings);
// map_offsetted_rings(collection.offsetted_rings);
}
+#endif
}
};
@@ -302,7 +351,10 @@ struct svg_visitor
//-----------------------------------------------------------------------------
template <typename JoinStrategy>
-struct JoinTestProperties { };
+struct JoinTestProperties
+{
+ static std::string name() { return "joinunknown"; }
+};
template<> struct JoinTestProperties<boost::geometry::strategy::buffer::join_round>
{
@@ -362,12 +414,18 @@ template
typename GeometryOut,
typename JoinStrategy,
typename EndStrategy,
+ typename DistanceStrategy,
+ typename SideStrategy,
+ typename PointStrategy,
typename Geometry
>
void test_buffer(std::string const& caseid, Geometry const& geometry,
- JoinStrategy const& join_strategy, EndStrategy const& end_strategy,
+ JoinStrategy const& join_strategy,
+ EndStrategy const& end_strategy,
+ DistanceStrategy const& distance_strategy,
+ SideStrategy const& side_strategy,
+ PointStrategy const& point_strategy,
bool check_self_intersections, double expected_area,
- double distance_left, double distance_right,
double tolerance,
std::size_t* self_ip_count)
{
@@ -387,19 +445,15 @@ void test_buffer(std::string const& caseid, Geometry const& geometry,
: ""
;
- if (distance_right < -998)
- {
- distance_right = distance_left;
- }
-
bg::model::box<point_type> envelope;
bg::envelope(geometry, envelope);
std::string join_name = JoinTestProperties<JoinStrategy>::name();
std::string end_name = EndTestProperties<EndStrategy>::name();
- if (boost::is_same<tag, bg::point_tag>::value
- || boost::is_same<tag, bg::multi_point_tag>::value)
+ if ( BOOST_GEOMETRY_CONDITION((
+ boost::is_same<tag, bg::point_tag>::value
+ || boost::is_same<tag, bg::multi_point_tag>::value )) )
{
join_name.clear();
}
@@ -411,7 +465,7 @@ void test_buffer(std::string const& caseid, Geometry const& geometry,
<< string_from_type<coordinate_type>::name()
<< "_" << join_name
<< (end_name.empty() ? "" : "_") << end_name
- << (distance_left < 0 && distance_right < 0 ? "_deflate" : "")
+ << (distance_strategy.negative() ? "_deflate" : "")
<< (bg::point_order<GeometryOut>::value == bg::counterclockwise ? "_ccw" : "")
// << "_" << point_buffer_count
;
@@ -426,32 +480,36 @@ void test_buffer(std::string const& caseid, Geometry const& geometry,
typedef bg::svg_mapper<point_type> mapper_type;
mapper_type mapper(svg, 1000, 1000);
- {
- double d = std::abs(distance_left) + std::abs(distance_right);
+ svg_visitor<mapper_type, bg::model::box<point_type>, tag> visitor(mapper);
+
+#ifdef BOOST_GEOMETRY_BUFFER_TEST_SVG_USE_ALTERNATE_BOX
+ // Create a zoomed-in view
+ bg::model::box<point_type> alternate_box;
+ bg::read_wkt(BOOST_GEOMETRY_BUFFER_TEST_SVG_ALTERNATE_BOX, alternate_box);
+ mapper.add(alternate_box);
+ // Take care non-visible elements are skipped
+ visitor.m_alternate_box = alternate_box;
+#else
+
+ {
bg::model::box<point_type> box = envelope;
- bg::buffer(box, box, d * (join_name == "miter" ? 2.0 : 1.1));
+ if (distance_strategy.negative())
+ {
+ bg::buffer(box, box, 1.0);
+ }
+ else
+ {
+ bg::buffer(box, box, 1.1 * distance_strategy.max_distance(join_strategy, end_strategy));
+ }
mapper.add(box);
}
+#endif
- svg_visitor<mapper_type, tag> visitor(mapper);
#else
bg::detail::buffer::visit_pieces_default_policy visitor;
#endif
- bg::strategy::buffer::distance_asymmetric
- <
- coordinate_type
- >
- distance_strategy(distance_left, distance_right);
-
- bg::strategy::buffer::side_straight side_strategy;
-
- // For (multi)points a buffer with 88 points is used for testing.
- // More points will give a more precise result - expected area should be
- // adapted then
- bg::strategy::buffer::point_circle circle_strategy(88);
-
typedef typename bg::point_type<Geometry>::type point_type;
typedef typename bg::rescale_policy_type<point_type>::type
rescale_policy_type;
@@ -462,7 +520,7 @@ void test_buffer(std::string const& caseid, Geometry const& geometry,
rescale_policy_type rescale_policy
= bg::get_rescale_policy<rescale_policy_type>(envelope);
- std::vector<GeometryOut> buffered;
+ bg::model::multi_polygon<GeometryOut> buffered;
bg::detail::buffer::buffer_inserter<GeometryOut>(geometry,
std::back_inserter(buffered),
@@ -470,52 +528,57 @@ void test_buffer(std::string const& caseid, Geometry const& geometry,
side_strategy,
join_strategy,
end_strategy,
- circle_strategy,
+ point_strategy,
rescale_policy,
visitor);
- typename bg::default_area_result<GeometryOut>::type area = 0;
- BOOST_FOREACH(GeometryOut const& polygon, buffered)
- {
- area += bg::area(polygon);
- }
+ typename bg::default_area_result<GeometryOut>::type area = bg::area(buffered);
//std::cout << caseid << " " << distance_left << std::endl;
//std::cout << "INPUT: " << bg::wkt(geometry) << std::endl;
//std::cout << "OUTPUT: " << area << std::endl;
- //BOOST_FOREACH(GeometryOut const& polygon, buffered)
- //{
- // std::cout << bg::wkt(polygon) << std::endl;
- //}
+ //std::cout << bg::wkt(buffered) << std::endl;
if (expected_area > -0.1)
{
+ double const difference = area - expected_area;
BOOST_CHECK_MESSAGE
(
- bg::math::abs(area - expected_area) < tolerance,
+ bg::math::abs(difference) < tolerance,
complete.str() << " not as expected. "
<< std::setprecision(18)
- << " Expected: " << expected_area
- << " Detected: " << area
+ << " Expected: " << expected_area
+ << " Detected: " << area
+ << " Diff: " << difference
+ << std::setprecision(3)
+ << " , " << 100.0 * (difference / expected_area) << "%"
);
if (check_self_intersections)
{
// Be sure resulting polygon does not contain
// self-intersections
- BOOST_FOREACH(GeometryOut const& polygon, buffered)
- {
- BOOST_CHECK_MESSAGE
- (
- ! bg::detail::overlay::has_self_intersections(polygon,
- rescale_policy, false),
- complete.str() << " output is self-intersecting. "
- );
- }
+ BOOST_CHECK_MESSAGE
+ (
+ ! bg::detail::overlay::has_self_intersections(buffered,
+ rescale_policy, false),
+ complete.str() << " output is self-intersecting. "
+ );
}
}
+#ifdef BOOST_GEOMETRY_BUFFER_TEST_IS_VALID
+ if (! bg::is_valid(buffered))
+ {
+ std::cout
+ << "NOT VALID: " << complete.str() << std::endl
+ << std::fixed << std::setprecision(16) << bg::wkt(buffered) << std::endl;
+ }
+// BOOST_CHECK_MESSAGE(bg::is_valid(buffered) == true, complete.str() << " is not valid");
+// BOOST_CHECK_MESSAGE(bg::intersects(buffered) == false, complete.str() << " intersects");
+#endif
+
#if defined(TEST_WITH_SVG)
bool const areal = boost::is_same
<
@@ -525,30 +588,46 @@ void test_buffer(std::string const& caseid, Geometry const& geometry,
// Map input geometry in green
if (areal)
{
- mapper.map(geometry, "opacity:0.5;fill:rgb(0,128,0);stroke:rgb(0,128,0);stroke-width:2");
+#ifdef BOOST_GEOMETRY_BUFFER_TEST_SVG_USE_ALTERNATE_BOX_FOR_INPUT
+ // Assuming input is areal
+ bg::model::multi_polygon<GeometryOut> clipped;
+ bg::intersection(geometry, alternate_box, clipped);
+ mapper.map(clipped, "opacity:0.5;fill:rgb(0,128,0);stroke:rgb(0,64,0);stroke-width:2");
+#else
+ mapper.map(geometry, "opacity:0.5;fill:rgb(0,128,0);stroke:rgb(0,64,0);stroke-width:2");
+#endif
}
else
{
+ // TODO: clip input points/linestring
mapper.map(geometry, "opacity:0.5;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");
- post_map(polygon, mapper, rescale_policy);
- }
+ // Map buffer in yellow (inflate) and with orange-dots (deflate)
+ std::string style = distance_strategy.negative()
+ ? "opacity:0.4;fill:rgb(255,255,192);stroke:rgb(255,128,0);stroke-width:3"
+ : "opacity:0.4;fill:rgb(255,255,128);stroke:rgb(0,0,0);stroke-width:3";
+
+#ifdef BOOST_GEOMETRY_BUFFER_TEST_SVG_USE_ALTERNATE_BOX
+ // Clip output multi-polygon with box
+ bg::model::multi_polygon<GeometryOut> clipped;
+ bg::intersection(buffered, alternate_box, clipped);
+ mapper.map(clipped, style);
+#else
+ mapper.map(buffered, style);
#endif
+ }
+ post_map(buffered, mapper, rescale_policy);
+#endif // TEST_WITH_SVG
if (self_ip_count != NULL)
{
std::size_t count = 0;
- BOOST_FOREACH(GeometryOut const& polygon, buffered)
+ if (bg::detail::overlay::has_self_intersections(buffered,
+ rescale_policy, false))
{
- if (bg::detail::overlay::has_self_intersections(polygon,
- rescale_policy, false))
- {
- count += count_self_ips(polygon, rescale_policy);
- }
+ count = count_self_ips(buffered, rescale_policy);
}
*self_ip_count += count;
@@ -596,10 +675,43 @@ void test_one(std::string const& caseid, std::string const& wkt,
<< std::endl;
#endif
+
+ bg::strategy::buffer::side_straight side_strategy;
+ bg::strategy::buffer::point_circle circle_strategy(88);
+
+ bg::strategy::buffer::distance_asymmetric
+ <
+ typename bg::coordinate_type<Geometry>::type
+ > distance_strategy(distance_left,
+ distance_right > -998 ? distance_right : distance_left);
+
test_buffer<GeometryOut>
- (caseid, g, join_strategy, end_strategy,
+ (caseid, g,
+ join_strategy, end_strategy,
+ distance_strategy, side_strategy, circle_strategy,
check_self_intersections, expected_area,
- distance_left, distance_right, tolerance, NULL);
+ tolerance, NULL);
+
+#if !defined(BOOST_GEOMETRY_COMPILER_MODE_DEBUG) && defined(BOOST_GEOMETRY_COMPILER_MODE_RELEASE)
+
+ // Also test symmetric distance strategy if right-distance is not specified
+ // (only in release mode)
+ if (bg::math::equals(distance_right, -999))
+ {
+ bg::strategy::buffer::distance_symmetric
+ <
+ typename bg::coordinate_type<Geometry>::type
+ > sym_distance_strategy(distance_left);
+
+ test_buffer<GeometryOut>
+ (caseid + "_sym", g,
+ join_strategy, end_strategy,
+ sym_distance_strategy, side_strategy, circle_strategy,
+ check_self_intersections, expected_area,
+ tolerance, NULL);
+
+ }
+#endif
}
// Version (currently for the Aimes test) counting self-ip's instead of checking
@@ -622,10 +734,53 @@ void test_one(std::string const& caseid, std::string const& wkt,
bg::read_wkt(wkt, g);
bg::correct(g);
- test_buffer<GeometryOut>(caseid, g, join_strategy, end_strategy,
+ bg::strategy::buffer::distance_asymmetric
+ <
+ typename bg::coordinate_type<Geometry>::type
+ > distance_strategy(distance_left,
+ distance_right > -998 ? distance_right : distance_left);
+
+ bg::strategy::buffer::point_circle circle_strategy(88);
+ bg::strategy::buffer::side_straight side_strategy;
+ test_buffer<GeometryOut>(caseid, g,
+ join_strategy, end_strategy,
+ distance_strategy, side_strategy, circle_strategy,
false, expected_area,
- distance_left, distance_right, tolerance, &self_ip_count);
+ tolerance, &self_ip_count);
}
+template
+<
+ typename Geometry,
+ typename GeometryOut,
+ typename JoinStrategy,
+ typename EndStrategy,
+ typename DistanceStrategy,
+ typename SideStrategy,
+ typename PointStrategy
+>
+void test_with_custom_strategies(std::string const& caseid,
+ std::string const& wkt,
+ JoinStrategy const& join_strategy,
+ EndStrategy const& end_strategy,
+ DistanceStrategy const& distance_strategy,
+ SideStrategy const& side_strategy,
+ PointStrategy const& point_strategy,
+ double expected_area,
+ double tolerance = 0.01)
+{
+ namespace bg = boost::geometry;
+ Geometry g;
+ bg::read_wkt(wkt, g);
+ bg::correct(g);
+
+ test_buffer<GeometryOut>
+ (caseid, g,
+ join_strategy, end_strategy,
+ distance_strategy, side_strategy, point_strategy,
+ true, expected_area, tolerance, NULL);
+}
+
+
#endif