File: buffer_linestring_geo.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 (144 lines) | stat: -rw-r--r-- 7,010 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
// Boost.Geometry
// Unit Test

// Copyright (c) 2018-2019 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)

#include "test_buffer_geo.hpp"
#include "aimes_cases.hpp"

// Road with one segment from west to east
static std::string const simplex = "LINESTRING(10.3965628 63.4276786,10.3953134 63.4299634)";

// Road from west to east and from south to north
static std::string const road = "LINESTRING(10.3966569 63.4276957,10.3998059 63.4279182,10.4003964 63.4288424)";

// Road with first a sharp angle to the right, then a rectangular angle to the left, then two obtuse angles
static std::string const sharp = "LINESTRING(10.3939684 63.4255808, 10.3948159 63.4263661, 10.3947354 63.4255918, 10.3950209 63.4255588, 10.3960570 63.4255423, 10.3973017 63.4255570)";

// Linestring forwards and backwards (close to 180 corner)
static std::string const opposite = "LINESTRING(10.4000988 63.4283885,10.4029694 63.4280726,10.4006988 63.4283397)";


template <typename Formula, bool Clockwise, typename PointType>
void test_linestring()
{
    using linestring = bg::model::linestring<PointType>;
    using polygon = bg::model::polygon<PointType, Clockwise>;

    // Because areas can change significantly when another formula is used,
    // use a high tolerance.
    int const points_per_circle = 360;
    ut_settings settings(0.5);

#if defined(BOOST_GEOMETRY_TEST_FAILURES)
    bool const thomas_skip = false;
#else
    // TODO: some cases are missing one or more turns
    bool const thomas_skip = std::is_same<Formula, bg::strategy::thomas>::value;
#endif

    bg::strategies::buffer::geographic<Formula> strategy;
    bg::strategy::buffer::geographic_side_straight<Formula> side;
    bg::strategy::buffer::geographic_join_miter<Formula> join_miter;
    bg::strategy::buffer::geographic_join_miter<Formula> join_miter25(2.5);
    bg::strategy::buffer::geographic_join_round<Formula> join_round(points_per_circle);
    bg::strategy::buffer::geographic_end_round<Formula> end_round(points_per_circle);
    bg::strategy::buffer::geographic_point_circle<Formula> circle(points_per_circle);
    bg::strategy::buffer::end_flat end_flat;

    test_one_geo<linestring, polygon>("simplex_5_8", simplex, strategy, side, circle, join_round, end_flat, 2622.0, 5.0, settings);
    test_one_geo<linestring, polygon>("road_5_flat", road, strategy, side, circle, join_round, end_flat, 2644.0, 5.0, settings);
    test_one_geo<linestring, polygon>("road_5_25_round", road, strategy, side, circle, join_round, end_round, 2016.0, 5.0, settings, 2.5);
    test_one_geo<linestring, polygon>("sharp_5_round", sharp, strategy, side, circle, join_round, end_round, 3090.0, 5.0, settings);
    test_one_geo<linestring, polygon>("sharp_5_miter", sharp, strategy, side, circle, join_miter, end_round, 3181.0, 5.0, settings);
    test_one_geo<linestring, polygon>("sharp_5_miter25", sharp, strategy, side, circle, join_miter25, end_round, 3121.0, 5.0, settings);

    if (! BOOST_GEOMETRY_CONDITION(thomas_skip))
    {
        // Misses an intersection point when using thomas
        test_one_geo<linestring, polygon>("opposite", opposite, strategy, side, circle, join_round, end_round, 1658.0, 5.0, settings);
    }

    {
        auto specific = settings;
        specific.fraction_buffered_points_too_close = 0.3;
        test_one_geo<linestring, polygon>("opposite_miter", opposite, strategy, side, circle, join_miter, end_flat, 1705.0, 5.0, specific);
        test_one_geo<linestring, polygon>("opposite_miter25", opposite, strategy, side, circle, join_miter25, end_flat, 1642.0, 5.0, specific);
    }

    settings.test_area = false;
    int const n = sizeof(testcases_aimes) / sizeof(testcases_aimes[0]);

    // Cases (ouf of 197) where the guessed area estimations are not met.
    // If this needs to be changed, be sure to
    // inspect the result visually on SVG or CSV (QGis).

    // Cases which are curved and have some artefacts (same as for cartesian)
    std::set<int> const cases_with_artefacts{119, 142};
    // Cases which are curved such that the min area is smaller than expected.
    std::set<int> const curved_cases_min_area{86, 181};
    // Cases which are curved such that the max area is larger than expected.
    std::set<int> const curved_cases_max_area{5, 95, 119, 142, 192};
    // Cases which are rounded such that it results in a large area
    std::set<int> const round_cases_max_area{196};
    // Cases which are not yet valid or false negatives
    std::set<int> const round_cases_invalid{143};

    for (auto i = 0; i < n; i++)
    {
        settings.multiplier_min_area
            = curved_cases_min_area.count(i) > 0 ? 0.85
            : ut_settings().multiplier_min_area;

        settings.multiplier_max_area
            = curved_cases_max_area.count(i) > 0 ? 1.2
            : round_cases_max_area.count(i) > 0 ? 1.5
            : ut_settings().multiplier_max_area;

        settings.fraction_buffered_points_too_close
            = cases_with_artefacts.count(i) > 0 ? 0.20
            : ut_settings().fraction_buffered_points_too_close;

        // With miter/flat, the artefacts are more pronounced and there can
        // be more points close than expected.
        auto settings_mf = settings;
        settings_mf.fraction_buffered_points_too_close *= 4.0;

        // With rounded cases, both rounded ends overap, adapt the expected area
        auto settings_rr = settings;
        settings_rr.multiplier_min_area
            = round_cases_max_area.count(i) > 0 ? 0.75
            : settings.multiplier_min_area;

        settings_rr.set_test_validity(round_cases_invalid.count(i) == 0);

        if (i != 181)
        {
            // 181 fails, it should generate a hole, but instead that is the outer ring now.
            test_one_geo<linestring, polygon>("aimes_" + std::to_string(i) + "_rr", testcases_aimes[i],
                strategy, side, circle, join_round, end_round, -1, 25.0, settings_rr);
        }
        test_one_geo<linestring, polygon>("aimes_" + std::to_string(i) + "_rf", testcases_aimes[i],
            strategy, side, circle, join_round, end_flat, -1, 25.0, settings);
        test_one_geo<linestring, polygon>("aimes_" + std::to_string(i) + "_mf", testcases_aimes[i],
            strategy, side, circle, join_miter, end_flat, -1, 25.0, settings_mf);
    }
}

int test_main(int, char* [])
{
    BoostGeometryWriteTestConfiguration();

    test_linestring<bg::strategy::andoyer, true, bg::model::point<default_test_type, 2, bg::cs::geographic<bg::degree> > >();
    test_linestring<bg::strategy::thomas, true, bg::model::point<default_test_type, 2, bg::cs::geographic<bg::degree> > >();

#if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE)
    test_linestring<bg::strategy::andoyer, true, bg::model::point<long double, 2, bg::cs::geographic<bg::degree> > >();
#endif

    return 0;
}