File: buffer_variable_width.cpp

package info (click to toggle)
boost1.88 1.88.0-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 576,932 kB
  • sloc: cpp: 4,149,234; xml: 136,789; ansic: 35,092; python: 33,910; asm: 5,698; sh: 4,604; ada: 1,681; makefile: 1,633; pascal: 1,139; perl: 1,124; sql: 640; yacc: 478; ruby: 271; java: 77; lisp: 24; csh: 6
file content (187 lines) | stat: -rw-r--r-- 8,701 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
// Boost.Geometry

// Copyright (c) 2024 Barend Gehrels, Amsterdam, the Netherlands.

// This file was modified by Oracle on 2019-2024.
// Modifications copyright (c) 2019-2024 Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle

// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

#include <geometry_test_common.hpp>

#include <boost/algorithm/string.hpp>
#include <boost/optional.hpp>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/register/point.hpp>

namespace bg = boost::geometry;

#if defined(TEST_WITH_SVG)
#include "test_buffer_svg.hpp"
#endif

// A point with extra info, such that
// - it can influence the buffer with dynamically (input)
// - it can receive the side at which the buffer was (output)
struct specific_point
{
    double x{0.0};
    double y{0.0};
    double distance_left{0.0};
    double distance_right{0.0};
    boost::optional<bg::strategy::buffer::buffer_side_selector> side{};
};

BOOST_GEOMETRY_REGISTER_POINT_2D(specific_point, double, cs::cartesian, x, y)

struct specific_buffer_side_strategy
{
    bool equidistant() const
    {
        return true;
    }

    template <typename Point, typename OutputRange, typename DistanceStrategy>
    bg::strategy::buffer::result_code apply(Point const& input_p1, Point const& input_p2,
                                            bg::strategy::buffer::buffer_side_selector side,
                                            DistanceStrategy const& distance,
                                            OutputRange &output_range) const
    {
        const auto result =
            bg::strategy::buffer::side_straight::apply(input_p1, input_p2, side, distance, output_range);

        for (auto& point : output_range)
        {
            point.side = side;
        }
        return result;
    }
};

struct specific_buffer_distance_strategy
{
    /// Returns the distance-value.
    template <typename Point>
    double apply(Point const& p, Point const& q,
                 bg::strategy::buffer::buffer_side_selector side) const
    {
        return bg::strategy::buffer::buffer_side_left == side
                   ? std::max(p.distance_left, q.distance_left)
                   : std::max(p.distance_right, q.distance_right);
    }

    bool negative() const
    {
        return false;
    }

    bool empty(bg::strategy::buffer::buffer_side_selector) const
    {
        return false;
    }

    /// Returns the max distance distance up to the buffer will reach.
    template <typename JoinStrategy, typename EndStrategy>
    double max_distance(JoinStrategy const &, EndStrategy const &) const
    {
        constexpr double unit_buffer_width{3.0};
        return 6.0 * unit_buffer_width;
    }

    /// Returns the distance at which the input is simplified before the buffer process.
    double simplify_distance() const
    {
        constexpr double unit_buffer_width{3.0};
        return unit_buffer_width / 1000.0;
    }
};

void test_buffer(std::string const& caseid, std::string const& wkt, std::vector<double> const& widths, double expected_area)
{
    using ls_t = boost::geometry::model::linestring<specific_point>;
    using mls_t = boost::geometry::model::multi_linestring<ls_t>;
    using polygon_t = boost::geometry::model::polygon<specific_point>;

    mls_t mls;
    boost::geometry::read_wkt(wkt, mls);

    if (mls.size() != widths.size())
    {
        throw std::runtime_error("There should be correct widths");
    }

    using point_type = specific_point;
    using strategy_t = bg::strategies::buffer::services::default_strategy<
        mls_t>::type;
    strategy_t strategy;

#if defined(TEST_WITH_SVG)
    bg::model::box<point_type> envelope;
    bg::envelope(mls, envelope, strategy);

    buffer_svg_mapper<point_type> buffer_mapper(caseid);

    std::ostringstream filename;
    filename << "/tmp/buffer_variable_width_" << caseid << ".svg";
    std::ofstream svg(filename.str().c_str());
    typedef bg::svg_mapper<point_type> mapper_type;
    mapper_type mapper(svg, 1000, 800);

    svg_visitor<mapper_type, bg::model::box<point_type>> visitor(mapper);

    // Set the SVG boundingbox, with a margin. The margin is necessary because
    // drawing is already started before the buffer is finished. It is not
    // possible to "add" the buffer (unless we buffer twice).
    buffer_mapper.prepare(mapper, visitor, envelope, 2.0);
#else
    bg::detail::buffer::visit_pieces_default_policy visitor;
#endif

    for (std::size_t i = 0; i < mls.size(); i++)
    {
        for (auto& point : mls[i])
        {
            point.distance_left = widths[i];
            point.distance_right = widths[i];
        }
    }

    specific_buffer_side_strategy buffer_side_strategy;
    specific_buffer_distance_strategy distance_strategy;
    boost::geometry::strategy::buffer::join_miter join_strategy;
    boost::geometry::strategy::buffer::end_flat end_strategy;
    boost::geometry::strategy::buffer::point_circle point_strategy;
    boost::geometry::model::multi_polygon<polygon_t> result;
    boost::geometry::detail::buffer::buffer_inserter
        <
            polygon_t
        >(mls,
          std::back_inserter(result),
          distance_strategy, buffer_side_strategy, join_strategy,
          end_strategy, point_strategy,
          strategy,
          visitor);

#if defined(TEST_WITH_SVG)
    buffer_mapper.map_input_output(mapper, mls, result, false);
#endif

    std::cout << caseid << " : " << boost::geometry::area(result) << std::endl;
    BOOST_CHECK_CLOSE_FRACTION(boost::geometry::area(result), expected_area, 0.001);
}

int test_main(int argc, char **argv)
{
    test_buffer("case1", "MULTILINESTRING((-2.99999999998012700785920969792641699314117431640625 10.4999999997948929575386500800959765911102294921875,18.00000000002045652536253328435122966766357421875 10.4999999997948947338954894803464412689208984375),(-2.99999999998012700785920969792641699314117431640625 10.4999999997948929575386500800959765911102294921875,17.99999999995061017443731543608009815216064453125 -4.5000000001943778471513724070973694324493408203125),(-2.99999999998012700785920969792641699314117431640625 10.4999999997948929575386500800959765911102294921875,11.99999999996175148453403380699455738067626953125 -10.49999999983214848953139153309166431427001953125))",
             {4.5, 1.5, 1.5}, 304.294);
    test_buffer("case2", "MULTILINESTRING((-18.00000000002045652536253328435122966766357421875 10.4999999997948929575386500800959765911102294921875,-2.99999999998012700785920969792641699314117431640625 10.4999999997948929575386500800959765911102294921875),(-2.99999999998012700785920969792641699314117431640625 10.4999999997948929575386500800959765911102294921875,17.99999999995061017443731543608009815216064453125 -4.5000000001943778471513724070973694324493408203125),(-2.99999999998012700785920969792641699314117431640625 10.4999999997948929575386500800959765911102294921875,11.99999999996175148453403380699455738067626953125 -10.49999999983214848953139153309166431427001953125))",
             {6.0, 1.5, 1.5}, 319.767);
    test_buffer("case3", "MULTILINESTRING((-18.00000000002045652536253328435122966766357421875 10.4999999997948929575386500800959765911102294921875,-2.99999999998012700785920969792641699314117431640625 10.4999999997948929575386500800959765911102294921875),(-2.99999999998012700785920969792641699314117431640625 10.4999999997948929575386500800959765911102294921875,18.00000000002045652536253328435122966766357421875 10.4999999997948947338954894803464412689208984375),(-2.99999999998012700785920969792641699314117431640625 10.4999999997948929575386500800959765911102294921875,11.99999999996175148453403380699455738067626953125 -10.49999999983214848953139153309166431427001953125))",
             {6.0, 4.5, 1.5}, 429.831);
    test_buffer("case4", "MULTILINESTRING((-18.00000000002045652536253328435122966766357421875 10.4999999997948929575386500800959765911102294921875,-2.99999999998012700785920969792641699314117431640625 10.4999999997948929575386500800959765911102294921875),(-2.99999999998012700785920969792641699314117431640625 10.4999999997948929575386500800959765911102294921875,18.00000000002045652536253328435122966766357421875 10.4999999997948947338954894803464412689208984375),(-2.99999999998012700785920969792641699314117431640625 10.4999999997948929575386500800959765911102294921875,17.99999999995061017443731543608009815216064453125 -4.5000000001943778471513724070973694324493408203125))",
             {6.0, 4.5, 1.5}, 423.195);
    return 0;
}