From a4bb2f9de18ddb4872faf316973ddbfdaa1ebb25 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Sat, 28 Jan 2012 21:13:39 +0000 Subject: [PATCH] Harmonized offset with buffer, using range_buffer, and making hooklets vary on parameter. This repairs offset (broken few days) [SVN r76767] --- .../geometry/extensions/algorithms/offset.hpp | 114 +++++------------- .../extensions/algorithms/offset_appender.hpp | 96 +++++++++++++++ .../geometry/extensions/strategies/buffer.hpp | 35 ++++-- .../algorithms/buffer/test_buffer.hpp | 6 +- test_extensions/algorithms/offset.cpp | 29 ++--- 5 files changed, 167 insertions(+), 113 deletions(-) create mode 100644 include/boost/geometry/extensions/algorithms/offset_appender.hpp diff --git a/include/boost/geometry/extensions/algorithms/offset.hpp b/include/boost/geometry/extensions/algorithms/offset.hpp index e3b7fa6c0..38194d597 100644 --- a/include/boost/geometry/extensions/algorithms/offset.hpp +++ b/include/boost/geometry/extensions/algorithms/offset.hpp @@ -11,20 +11,12 @@ #include -#if defined(BOOST_MSVC_FULL_VER) -#pragma message ("WARNING: offset might give wrong results, will be harmonized with range_buffer") -#else -#warning "WARNING: offset might give wrong results, will be harmonized with range_buffer" -#endif - - - #include -#include #include -#include #include +#include +#include #include #include @@ -44,81 +36,26 @@ template typename Range, typename RangeOut, typename JoinStrategy, - typename Distance + typename DistanceStrategy > struct offset_range + : public geometry::detail::buffer::range_buffer + < + RangeOut, + DistanceStrategy, + JoinStrategy, + linestring_tag + > { - typedef typename coordinate_type::type coordinate_type; - typedef typename point_type::type output_point_type; - typedef model::referring_segment segment_type; - typedef typename boost::range_iterator::type iterator_type; - template static inline void apply(Range const& range, Appender& appender, - JoinStrategy const& join, - Distance const& distance) + DistanceStrategy const& distance, + JoinStrategy const& join) { - output_point_type previous_p1, previous_p2; - output_point_type first_p1, first_p2; - - bool first = true; - - iterator_type it = boost::begin(range); - for (iterator_type prev = it++; it != boost::end(range); ++it) - { - if (! detail::equals::equals_point_point(*prev, *it)) - { - // 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; - - set<0>(p2, get<0>(*it) + px * distance); - set<1>(p2, get<1>(*it) + py * distance); - - set<0>(p1, get<0>(*prev) + px * distance); - set<1>(p1, get<1>(*prev) + py * distance); - - if (! first) - { - output_point_type p; - segment_type s1(p1, p2); - segment_type s2(previous_p1, previous_p2); - if (detail::buffer::line_line_intersection::apply(s1, s2, p)) - { - join.apply(p, *prev, previous_p2, p1, distance, appender); - } - } - else - { - first = false; - first_p1 = p1; - first_p2 = p2; - - appender.append(p1); - } - - previous_p1 = p1; - previous_p2 = p2; - prev = it; - } - } - - // Last one - appender.append(previous_p2); - + iterate(appender, boost::begin(range), boost::end(range), + buffer_side_left, + distance, join); } }; @@ -138,7 +75,7 @@ template typename Geometry, typename GeometryOut, typename JoinStrategy, - typename Distance + typename DistanceStrategy > struct offset {}; @@ -149,7 +86,7 @@ template typename Geometry, typename GeometryOut, typename JoinStrategy, - typename Distance + typename DistanceStrategy > struct offset < @@ -158,14 +95,14 @@ struct offset Geometry, GeometryOut, JoinStrategy, - Distance + DistanceStrategy > : detail::offset::offset_range < Geometry, GeometryOut, JoinStrategy, - Distance + DistanceStrategy > {}; @@ -188,7 +125,14 @@ inline void offset(Geometry const& geometry, GeometryOut& out, concept::check(); concept::check(); - typedef detail::buffer::buffer_appender + typedef strategy::buffer::distance_assymetric + < + typename geometry::coordinate_type::type + > distance_strategy_type; + distance_strategy_type distance_strategy(distance, distance); + + + typedef detail::offset::offset_appender < GeometryOut > appender_type; @@ -202,8 +146,8 @@ inline void offset(Geometry const& geometry, GeometryOut& out, Geometry, GeometryOut, JoinStrategy, - Distance - >::apply(geometry, appender, join, distance); + distance_strategy_type + >::apply(geometry, appender, distance_strategy, join); } diff --git a/include/boost/geometry/extensions/algorithms/offset_appender.hpp b/include/boost/geometry/extensions/algorithms/offset_appender.hpp new file mode 100644 index 000000000..594ee235c --- /dev/null +++ b/include/boost/geometry/extensions/algorithms/offset_appender.hpp @@ -0,0 +1,96 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-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_OFFSET_APPENDER_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OFFSET_APPENDER_HPP + + +#include + +#include + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace offset +{ + +// Appends points to an output range (linestring/ring). +template + < + typename Range +#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER + , typename Mapper +#endif + > +struct offset_appender +{ + typedef Range range_type; + + typedef typename geometry::point_type::type point_type; + +#ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER + Mapper const& m_mapper; + inline offset_appender(Range& r, Mapper const& mapper) + : m_range(r) + , m_mapper(mapper) +#else + inline offset_appender(Range& r) + : m_range(r) +#endif + + {} + + inline void append(point_type const& point) + { + do_append(point); + } + + inline void append_begin_join(point_type const& point) + { + do_append(point); + } + + inline void append_end_join(point_type const& point) + { + do_append(point); + } + + inline void append_begin_hooklet(point_type const& point) + { + do_append(point); + } + + inline void append_end_hooklet(point_type const& point) + { + do_append(point); + } + + +private : + + Range& m_range; + + inline void do_append(point_type const& point) + { + m_range.push_back(point); + } +}; + + +}} // namespace detail::offset +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OFFSET_APPENDER_HPP diff --git a/include/boost/geometry/extensions/strategies/buffer.hpp b/include/boost/geometry/extensions/strategies/buffer.hpp index a2f4fcaa2..03542aa62 100644 --- a/include/boost/geometry/extensions/strategies/buffer.hpp +++ b/include/boost/geometry/extensions/strategies/buffer.hpp @@ -92,7 +92,7 @@ struct join_mapper #ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER // Forget this, it will go -template +template struct join_miter : public join_mapper { join_miter(Mapper const& mapper) : join_mapper(mapper) {} @@ -102,7 +102,8 @@ struct join_miter : public join_mapper template < typename PointIn, - typename PointOut + typename PointOut, + bool AddHooklets = true > struct join_miter { @@ -125,11 +126,15 @@ struct join_miter if (side::apply(perp1, ip, perp2) == signum) { - // If it is concave (corner to left), add helperline - // The helper-line IS essential for buffering holes. Without, - // holes might be generated, while they should NOT be there. - appender.append_begin_hooklet(perp1); - appender.append_end_hooklet(perp2); + if (AddHooklets) + { + appender.append_begin_hooklet(perp1); + appender.append_end_hooklet(perp2); + } + else + { + appender.append(ip); + } } else { @@ -210,7 +215,7 @@ struct join_bevel #ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER // Forget this, it will go -template +template struct join_round : public join_mapper { join_round(Mapper const& mapper, int max_level = 4) @@ -223,7 +228,8 @@ struct join_round : public join_mapper template < typename PointIn, - typename PointOut + typename PointOut, + bool AddHooklets = true > struct join_round { @@ -291,8 +297,15 @@ struct join_round if (side::apply(perp1, ip, perp2) == signum) { // If it is concave (corner to left), add helperline - appender.append_begin_hooklet(perp1); - appender.append_end_hooklet(perp2); + if (AddHooklets) + { + appender.append_begin_hooklet(perp1); + appender.append_end_hooklet(perp2); + } + else + { + appender.append(ip); + } } else { diff --git a/test_extensions/algorithms/buffer/test_buffer.hpp b/test_extensions/algorithms/buffer/test_buffer.hpp index f385a557e..7dc7b46ad 100644 --- a/test_extensions/algorithms/buffer/test_buffer.hpp +++ b/test_extensions/algorithms/buffer/test_buffer.hpp @@ -85,6 +85,7 @@ template < typename , typename + , bool #if defined(BOOST_GEOMETRY_DEBUG_WITH_MAPPER) , typename #endif @@ -136,7 +137,8 @@ void test_buffer(std::string const& caseid, Geometry const& geometry, typedef JoinStrategy < point_type, - typename bg::point_type::type + typename bg::point_type::type, + true #ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER , bg::svg_mapper #endif @@ -253,6 +255,7 @@ template < typename , typename + , bool #if defined(BOOST_GEOMETRY_DEBUG_WITH_MAPPER) , typename #endif @@ -294,6 +297,7 @@ template < typename , typename + , bool #if defined(BOOST_GEOMETRY_DEBUG_WITH_MAPPER) , typename #endif diff --git a/test_extensions/algorithms/offset.cpp b/test_extensions/algorithms/offset.cpp index a08499a5e..c484c85d0 100644 --- a/test_extensions/algorithms/offset.cpp +++ b/test_extensions/algorithms/offset.cpp @@ -35,7 +35,7 @@ template -void test_offset(bool check, std::string const& caseid, Geometry const& geometry, +void test_offset(std::string const& caseid, Geometry const& geometry, double distance, double expected_length, double percentage) { @@ -45,7 +45,8 @@ void test_offset(bool check, std::string const& caseid, Geometry const& geometry typedef bg::strategy::buffer::join_round < point_type, - point_type + point_type, + false > join_strategy; GeometryOut moved_by_offset; @@ -66,11 +67,7 @@ void test_offset(bool check, std::string const& caseid, Geometry const& geometry //BOOST_CHECK_EQUAL(holes, expected_hole_count); - if (check) - { - BOOST_CHECK_CLOSE(length, expected_length, percentage); - } - + BOOST_CHECK_CLOSE(length, expected_length, percentage); #if defined(TEST_WITH_SVG) { @@ -97,14 +94,14 @@ void test_offset(bool check, std::string const& caseid, Geometry const& geometry template -void test_one(bool check, std::string const& caseid, std::string const& wkt, double distance, +void test_one(std::string const& caseid, std::string const& wkt, double distance, double expected_length_plus, double expected_length_minus, double percentage = 0.001) { Geometry geometry; bg::read_wkt(wkt, geometry); - test_offset(check, caseid + "_a", geometry, distance, expected_length_plus, percentage); - test_offset(check, caseid + "_b", geometry, -distance, expected_length_minus, percentage); + test_offset(caseid + "_a", geometry, distance, expected_length_plus, percentage); + test_offset(caseid + "_b", geometry, -distance, expected_length_minus, percentage); } @@ -123,12 +120,12 @@ void test_all() static std::string const curve = "LINESTRING(2 7,3 5,5 4,7 5,8 7)"; static std::string const reallife1 = "LINESTRING(76396.40464822574 410095.6795147947,76397.85016212701 410095.211865792,76401.30666443033 410095.0466387949,76405.05892643372 410096.1007777959,76409.45103273794 410098.257640797,76412.96309264141 410101.6522238015)"; - test_one(true, "ls_simplex", simplex, 0.5, std::sqrt(2.0), std::sqrt(2.0)); - test_one(false, "one_bend", one_bend, 0.5, 10.17328, 8.8681); - test_one(false, "two_bends", two_bends, 0.5, 13.2898, 12.92811); - test_one(false, "overlapping", overlapping, 0.5, 27.1466, 22.0596); - test_one(false, "curve", curve, 0.5, 7.7776, 10.0507); - test_one(false, "reallife1", reallife1, 16.5, 5.4654, 36.4943); + test_one("ls_simplex", simplex, 0.5, std::sqrt(2.0), std::sqrt(2.0)); + test_one("one_bend", one_bend, 0.5, 10.17328, 8.8681); + test_one("two_bends", two_bends, 0.5, 13.2898, 12.92811); + test_one("overlapping", overlapping, 0.5, 27.1466, 22.0596); + test_one("curve", curve, 0.5, 7.7776, 10.0507); + test_one("reallife1", reallife1, 16.5, 5.4654, 36.4943); }